Merge pull request #52 from jl777/jl777

Jl777
This commit is contained in:
blackjok3rtt
2019-04-07 12:03:20 +08:00
committed by GitHub
21 changed files with 2347 additions and 750 deletions

View File

@@ -0,0 +1,690 @@
#!/usr/bin/env python2
# Copyright (c) 2018 SuperNET developers
# Distributed under the MIT software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
from test_framework.test_framework import BitcoinTestFramework
from test_framework.authproxy import JSONRPCException
from test_framework.util import assert_equal, assert_greater_than, \
initialize_chain_clean, initialize_chain, start_nodes, start_node, connect_nodes_bi, \
stop_nodes, sync_blocks, sync_mempools, wait_bitcoinds, rpc_port, assert_raises
import time
from decimal import Decimal
from random import choice
from string import ascii_uppercase
def assert_success(result):
assert_equal(result['result'], 'success')
def assert_error(result):
assert_equal(result['result'], 'error')
def generate_random_string(length):
random_string = ''.join(choice(ascii_uppercase) for i in range(length))
return random_string
class CryptoConditionsTest (BitcoinTestFramework):
def setup_chain(self):
print("Initializing CC test directory "+self.options.tmpdir)
self.num_nodes = 2
initialize_chain_clean(self.options.tmpdir, self.num_nodes)
def setup_network(self, split = False):
print("Setting up network...")
self.addr = "RWPg8B91kfK5UtUN7z6s6TeV9cHSGtVY8D"
self.pubkey = "02676d00110c2cd14ae24f95969e8598f7ccfaa675498b82654a5b5bd57fc1d8cf"
self.privkey = "UqMgxk7ySPNQ4r9nKAFPjkXy6r5t898yhuNCjSZJLg3RAM4WW1m9"
self.addr1 = "RXEXoa1nRmKhMbuZovpcYwQMsicwzccZBp"
self.pubkey1 = "024026d4ad4ecfc1f705a9b42ca64af6d2ad947509c085534a30b8861d756c6ff0"
self.privkey1 = "UtdydP56pGTFmawHzHr1wDrc4oUwCNW1ttX8Pc3KrvH3MA8P49Wi"
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir,
extra_args=[[
# always give -ac_name as first extra_arg and port as third
'-ac_name=REGTEST',
'-conf='+self.options.tmpdir+'/node0/REGTEST.conf',
'-port=64367',
'-rpcport=64368',
'-regtest',
'-addressindex=1',
'-spentindex=1',
'-ac_supply=5555555',
'-ac_reward=10000000000000',
'-pubkey=' + self.pubkey,
'-ac_cc=2',
'-whitelist=127.0.0.1',
'-debug',
'--daemon',
'-rpcuser=rt',
'-rpcpassword=rt'
],
['-ac_name=REGTEST',
'-conf='+self.options.tmpdir+'/node1/REGTEST.conf',
'-port=64365',
'-rpcport=64366',
'-regtest',
'-addressindex=1',
'-spentindex=1',
'-ac_supply=5555555',
'-ac_reward=10000000000000',
'-pubkey=' + self.pubkey1,
'-ac_cc=2',
'-whitelist=127.0.0.1',
'-debug',
'-addnode=127.0.0.1:64367',
'--daemon',
'-rpcuser=rt',
'-rpcpassword=rt']]
)
self.is_network_split = split
self.rpc = self.nodes[0]
self.rpc1 = self.nodes[1]
self.sync_all()
print("Done setting up network")
def send_and_mine(self, xtn, rpc_connection):
txid = rpc_connection.sendrawtransaction(xtn)
assert txid, 'got txid'
# we need the tx above to be confirmed in the next block
rpc_connection.generate(1)
return txid
def run_faucet_tests(self):
rpc = self.rpc
rpc1 = self.rpc1
# basic sanity tests
result = rpc.getwalletinfo()
assert_greater_than(result['txcount'], 100)
assert_greater_than(result['balance'], 0.0)
balance = result['balance']
faucet = rpc.faucetaddress()
assert_equal(faucet['result'], 'success')
# verify all keys look like valid AC addrs, could be better
for x in ['myCCAddress(Faucet)', 'FaucetCCAddress', 'FaucetCCTokensAddress', 'myaddress', 'FaucetNormalAddress']:
assert_equal(faucet[x][0], 'R')
result = rpc.faucetaddress(self.pubkey)
assert_success(result)
# test that additional CCaddress key is returned
for x in ['myCCAddress(Faucet)', 'FaucetCCAddress', 'FaucetCCTokensAddress', 'myaddress', 'FaucetNormalAddress']:
assert_equal(result[x][0], 'R')
# no funds in the faucet yet
result = rpc.faucetget()
assert_error(result)
result = rpc.faucetinfo()
assert_success(result)
result = rpc.faucetfund("0")
assert_error(result)
result = rpc.faucetfund("-1")
assert_error(result)
# we need at least 1 + txfee to get
result = rpc.faucetfund("2")
assert_success(result)
assert result['hex'], "hex key found"
# broadcast the xtn
result = rpc.sendrawtransaction(result['hex'])
txid = result[0]
assert txid, "found txid"
# we need the tx above to be confirmed in the next block
rpc.generate(1)
self.sync_all()
result = rpc.getwalletinfo()
# minus one block reward
balance2 = result['balance'] - 100000
# make sure our balance is less now
assert_greater_than(balance, balance2)
result = rpc.faucetinfo()
assert_success(result)
assert_greater_than( result['funding'], 0 )
# claiming faucet on second node
faucetgethex = rpc1.faucetget()
assert_success(faucetgethex)
assert faucetgethex['hex'], "hex key found"
balance1 = rpc1.getwalletinfo()['balance']
# try to broadcast the faucetget transaction
result = self.send_and_mine(faucetgethex['hex'], rpc1)
assert txid, "transaction broadcasted"
balance2 = rpc1.getwalletinfo()['balance']
assert_greater_than(balance2, balance1)
self.sync_all()
def run_dice_tests(self):
rpc = self.nodes[0]
rpc1 = self.nodes[1]
self.sync_all()
# have to generate few blocks on second node to be able to place bets
rpc1.generate(10)
result = rpc1.getbalance()
assert_greater_than(result, 100000)
dice = rpc.diceaddress()
assert_equal(dice['result'], 'success')
for x in ['myCCAddress(Dice)', 'DiceCCAddress', 'DiceCCTokensAddress', 'myaddress', 'DiceNormalAddress']:
assert_equal(dice[x][0], 'R')
dice = rpc.diceaddress(self.pubkey)
assert_equal(dice['result'], 'success')
for x in ['myCCAddress(Dice)', 'DiceCCAddress', 'DiceCCTokensAddress', 'myaddress', 'DiceNormalAddress']:
assert_equal(dice[x][0], 'R')
# no dice created yet
result = rpc.dicelist()
assert_equal(result, [])
# creating dice plan with too long name (>8 chars)
result = rpc.dicefund("THISISTOOLONG", "10000", "10", "10000", "10", "5")
assert_error(result)
# creating dice plan with < 100 funding
result = rpc.dicefund("LUCKY","10","1","10000","10","5")
assert_error(result)
# creating dice plan with 0 blocks timeout
result = rpc.dicefund("LUCKY","10","1","10000","10","0")
assert_error(result)
# creating dice plan
dicefundtx = rpc.dicefund("LUCKY","1000","1","800","10","5")
diceid = self.send_and_mine(dicefundtx['hex'], rpc)
# checking if it in plans list now
result = rpc.dicelist()
assert_equal(result[0], diceid)
# set dice name for futher usage
dicename = "LUCKY"
# adding zero funds to plan
result = rpc.diceaddfunds(dicename,diceid,"0")
assert_error(result)
# adding negative funds to plan
result = rpc.diceaddfunds(dicename,diceid,"-1")
assert_error(result)
# adding funds to plan
addfundstx = rpc.diceaddfunds(dicename,diceid,"1100")
result = self.send_and_mine(addfundstx['hex'], rpc)
# checking if funds added to plan
result = rpc.diceinfo(diceid)
assert_equal(result["funding"], "2100.00000000")
# not valid dice info checking
result = rpc.diceinfo("invalid")
assert_error(result)
# placing 0 amount bet
result = rpc1.dicebet(dicename,diceid,"0","2")
assert_error(result)
# placing negative amount bet
result = rpc1.dicebet(dicename,diceid,"-1","2")
assert_error(result)
# placing bet more than maxbet
result = rpc1.dicebet(dicename,diceid,"900","2")
assert_error(result)
# placing bet with amount more than funding
result = rpc1.dicebet(dicename,diceid,"3000","2")
assert_error(result)
# placing bet with potential won more than funding
result = rpc1.dicebet(dicename,diceid,"750","9")
assert_error(result)
# placing 0 odds bet
result = rpc1.dicebet(dicename,diceid,"1","0")
assert_error(result)
# placing negative odds bet
result = rpc1.dicebet(dicename,diceid,"1","-1")
assert_error(result)
# placing bet with odds more than allowed
result = rpc1.dicebet(dicename,diceid,"1","11")
assert_error(result)
# placing bet with not correct dice name
result = rpc1.dicebet("nope",diceid,"100","2")
assert_error(result)
# placing bet with not correct dice id
result = rpc1.dicebet(dicename,self.pubkey,"100","2")
assert_error(result)
# have to make some entropy for the next test
entropytx = 0
fundingsum = 1
while entropytx < 110:
fundingsuminput = str(fundingsum)
fundinghex = rpc.diceaddfunds(dicename,diceid,fundingsuminput)
result = self.send_and_mine(fundinghex['hex'], rpc)
entropytx = entropytx + 1
fundingsum = fundingsum + 1
rpc.generate(2)
self.sync_all()
# valid bet placing
placebet = rpc1.dicebet(dicename,diceid,"100","2")
betid = self.send_and_mine(placebet["hex"], rpc1)
assert result, "bet placed"
# check bet status
result = rpc1.dicestatus(dicename,diceid,betid)
assert_success(result)
# note initial dice funding state at this point.
# TODO: track player balance somehow (hard to do because of mining and fees)
diceinfo = rpc.diceinfo(diceid)
funding = float(diceinfo['funding'])
# # placing same amount bets with amount 1 and odds 1:3, checking if balance changed correct
# losscounter = 0
# wincounter = 0
# betcounter = 0
#
# while (betcounter < 10):
# placebet = rpc1.dicebet(dicename,diceid,"1","2")
# betid = self.send_and_mine(placebet["hex"], rpc1)
# time.sleep(3)
# self.sync_all()
# finish = rpc.dicefinish(dicename,diceid,betid)
# self.send_and_mine(finish["hex"], rpc1)
# self.sync_all()
# time.sleep(3)
# betresult = rpc1.dicestatus(dicename,diceid,betid)
# betcounter = betcounter + 1
# if betresult["status"] == "loss":
# losscounter = losscounter + 1
# elif betresult["status"] == "win":
# wincounter = wincounter + 1
# else:
# pass
#
# # funding balance should increase if player loss, decrease if player won
# fundbalanceguess = funding + losscounter - wincounter * 2
# fundinfoactual = rpc.diceinfo(diceid)
# assert_equal(round(fundbalanceguess),round(float(fundinfoactual['funding'])))
def run_token_tests(self):
rpc = self.nodes[0]
result = rpc.tokenaddress()
assert_success(result)
for x in ['myCCAddress(Tokens)', 'TokensNormalAddress', 'TokensNormalAddress', 'myaddress','TokensCCAddress']:
assert_equal(result[x][0], 'R')
result = rpc.tokenaddress(self.pubkey)
assert_success(result)
for x in ['myCCAddress(Tokens)', 'TokensNormalAddress', 'TokensNormalAddress', 'myaddress','TokensCCAddress']:
assert_equal(result[x][0], 'R')
# there are no tokens created yet
result = rpc.tokenlist()
assert_equal(result, [])
# trying to create token with negaive supply
result = rpc.tokencreate("NUKE", "-1987420", "no bueno supply")
assert_error(result)
# creating token with name more than 32 chars
result = rpc.tokencreate("NUKE123456789012345678901234567890", "1987420", "name too long")
assert_error(result)
# creating valid token
result = rpc.tokencreate("DUKE", "1987.420", "Duke's custom token")
assert_success(result)
tokenid = self.send_and_mine(result['hex'], rpc)
result = rpc.tokenlist()
assert_equal(result[0], tokenid)
# get token balance for token with pubkey
result = rpc.tokenbalance(tokenid, self.pubkey)
assert_success(result)
assert_equal(result['balance'], 198742000000)
assert_equal(result['tokenid'], tokenid)
# get token balance for token without pubkey
result = rpc.tokenbalance(tokenid)
assert_success(result)
assert_equal(result['balance'], 198742000000)
assert_equal(result['tokenid'], tokenid)
# this is not a valid assetid
result = rpc.tokeninfo(self.pubkey)
assert_error(result)
# check tokeninfo for valid token
result = rpc.tokeninfo(tokenid)
assert_success(result)
assert_equal(result['tokenid'], tokenid)
assert_equal(result['owner'], self.pubkey)
assert_equal(result['name'], "DUKE")
assert_equal(result['supply'], 198742000000)
assert_equal(result['description'], "Duke's custom token")
# invalid numtokens ask
result = rpc.tokenask("-1", tokenid, "1")
assert_error(result)
# invalid numtokens ask
result = rpc.tokenask("0", tokenid, "1")
assert_error(result)
# invalid price ask
result = rpc.tokenask("1", tokenid, "-1")
assert_error(result)
# invalid price ask
result = rpc.tokenask("1", tokenid, "0")
assert_error(result)
# invalid tokenid ask
result = rpc.tokenask("100", "deadbeef", "1")
assert_error(result)
# valid ask
tokenask = rpc.tokenask("100", tokenid, "7.77")
tokenaskhex = tokenask['hex']
tokenaskid = self.send_and_mine(tokenask['hex'], rpc)
result = rpc.tokenorders(tokenid)
order = result[0]
assert order, "found order"
# invalid ask fillunits
result = rpc.tokenfillask(tokenid, tokenaskid, "0")
assert_error(result)
# invalid ask fillunits
result = rpc.tokenfillask(tokenid, tokenaskid, "-777")
assert_error(result)
# valid ask fillunits
fillask = rpc.tokenfillask(tokenid, tokenaskid, "777")
result = self.send_and_mine(fillask['hex'], rpc)
txid = result[0]
assert txid, "found txid"
# should be no token orders
result = rpc.tokenorders(tokenid)
assert_equal(result, [])
# checking ask cancellation
testorder = rpc.tokenask("100", tokenid, "7.77")
testorderid = self.send_and_mine(testorder['hex'], rpc)
cancel = rpc.tokencancelask(tokenid, testorderid)
self.send_and_mine(cancel["hex"], rpc)
result = rpc.tokenorders(tokenid)
assert_equal(result, [])
# invalid numtokens bid
result = rpc.tokenbid("-1", tokenid, "1")
assert_error(result)
# invalid numtokens bid
result = rpc.tokenbid("0", tokenid, "1")
assert_error(result)
# invalid price bid
result = rpc.tokenbid("1", tokenid, "-1")
assert_error(result)
# invalid price bid
result = rpc.tokenbid("1", tokenid, "0")
assert_error(result)
# invalid tokenid bid
result = rpc.tokenbid("100", "deadbeef", "1")
assert_error(result)
tokenbid = rpc.tokenbid("100", tokenid, "10")
tokenbidhex = tokenbid['hex']
tokenbidid = self.send_and_mine(tokenbid['hex'], rpc)
result = rpc.tokenorders(tokenid)
order = result[0]
assert order, "found order"
# invalid bid fillunits
result = rpc.tokenfillbid(tokenid, tokenbidid, "0")
assert_error(result)
# invalid bid fillunits
result = rpc.tokenfillbid(tokenid, tokenbidid, "-777")
assert_error(result)
# valid bid fillunits
fillbid = rpc.tokenfillbid(tokenid, tokenbidid, "1000")
result = self.send_and_mine(fillbid['hex'], rpc)
txid = result[0]
assert txid, "found txid"
# should be no token orders
result = rpc.tokenorders(tokenid)
assert_equal(result, [])
# checking bid cancellation
testorder = rpc.tokenbid("100", tokenid, "7.77")
testorderid = self.send_and_mine(testorder['hex'], rpc)
cancel = rpc.tokencancelbid(tokenid, testorderid)
self.send_and_mine(cancel["hex"], rpc)
result = rpc.tokenorders(tokenid)
assert_equal(result, [])
# invalid token transfer amount (have to add status to CC code!)
randompubkey = "021a559101e355c907d9c553671044d619769a6e71d624f68bfec7d0afa6bd6a96"
result = rpc.tokentransfer(tokenid,randompubkey,"0")
assert_error(result)
# invalid token transfer amount (have to add status to CC code!)
result = rpc.tokentransfer(tokenid,randompubkey,"-1")
assert_error(result)
# valid token transfer
sendtokens = rpc.tokentransfer(tokenid,randompubkey,"1")
self.send_and_mine(sendtokens["hex"], rpc)
result = rpc.tokenbalance(tokenid,randompubkey)
assert_equal(result["balance"], 1)
def run_rewards_tests(self):
rpc = self.nodes[0]
result = rpc.rewardsaddress()
for x in ['myCCAddress(Rewards)', 'myaddress', 'RewardsCCAddress', 'RewardsCCTokensAddress', 'RewardsNormalAddress']:
assert_equal(result[x][0], 'R')
result = rpc.rewardsaddress(self.pubkey)
for x in ['myCCAddress(Rewards)', 'myaddress', 'RewardsCCAddress', 'RewardsCCTokensAddress', 'RewardsNormalAddress']:
assert_equal(result[x][0], 'R')
# no rewards yet
result = rpc.rewardslist()
assert_equal(result, [])
# looking up non-existent reward should return error
result = rpc.rewardsinfo("none")
assert_error(result)
# creating rewards plan with name > 8 chars, should return error
result = rpc.rewardscreatefunding("STUFFSTUFF", "7777", "25", "0", "10", "10")
assert_error(result)
# creating rewards plan with 0 funding
result = rpc.rewardscreatefunding("STUFF", "0", "25", "0", "10", "10")
assert_error(result)
# creating rewards plan with 0 maxdays
result = rpc.rewardscreatefunding("STUFF", "7777", "25", "0", "10", "0")
assert_error(result)
# creating rewards plan with > 25% APR
result = rpc.rewardscreatefunding("STUFF", "7777", "30", "0", "10", "10")
assert_error(result)
# creating valid rewards plan
result = rpc.rewardscreatefunding("STUFF", "7777", "25", "0", "10", "10")
assert result['hex'], 'got raw xtn'
fundingtxid = rpc.sendrawtransaction(result['hex'])
assert fundingtxid, 'got txid'
# confirm the above xtn
rpc.generate(1)
result = rpc.rewardsinfo(fundingtxid)
assert_success(result)
assert_equal(result['name'], 'STUFF')
assert_equal(result['APR'], "25.00000000")
assert_equal(result['minseconds'], 0)
assert_equal(result['maxseconds'], 864000)
assert_equal(result['funding'], "7777.00000000")
assert_equal(result['mindeposit'], "10.00000000")
assert_equal(result['fundingtxid'], fundingtxid)
# checking if new plan in rewardslist
result = rpc.rewardslist()
assert_equal(result[0], fundingtxid)
# creating reward plan with already existing name, should return error
result = rpc.rewardscreatefunding("STUFF", "7777", "25", "0", "10", "10")
assert_error(result)
# add funding amount must be positive
result = rpc.rewardsaddfunding("STUFF", fundingtxid, "-1")
assert_error(result)
# add funding amount must be positive
result = rpc.rewardsaddfunding("STUFF", fundingtxid, "0")
assert_error(result)
# adding valid funding
result = rpc.rewardsaddfunding("STUFF", fundingtxid, "555")
addfundingtxid = self.send_and_mine(result['hex'], rpc)
assert addfundingtxid, 'got funding txid'
# checking if funding added to rewardsplan
result = rpc.rewardsinfo(fundingtxid)
assert_equal(result['funding'], "8332.00000000")
# trying to lock funds, locking funds amount must be positive
result = rpc.rewardslock("STUFF", fundingtxid, "-5")
assert_error(result)
# trying to lock funds, locking funds amount must be positive
result = rpc.rewardslock("STUFF", fundingtxid, "0")
assert_error(result)
# trying to lock less than the min amount is an error
result = rpc.rewardslock("STUFF", fundingtxid, "7")
assert_error(result)
# locking funds in rewards plan
result = rpc.rewardslock("STUFF", fundingtxid, "10")
assert_success(result)
locktxid = result['hex']
assert locktxid, "got lock txid"
# locktxid has not been broadcast yet
result = rpc.rewardsunlock("STUFF", fundingtxid, locktxid)
assert_error(result)
# broadcast xtn
txid = rpc.sendrawtransaction(locktxid)
assert txid, 'got txid from sendrawtransaction'
# confirm the xtn above
rpc.generate(1)
# will not unlock since reward amount is less than tx fee
result = rpc.rewardsunlock("STUFF", fundingtxid, locktxid)
assert_error(result)
def run_oracles_tests(self):
rpc = self.nodes[0]
rpc1 = self.nodes[1]
result = rpc1.oraclesaddress()
result = rpc.oraclesaddress()
assert_success(result)
for x in ['OraclesCCAddress', 'OraclesNormalAddress', 'myCCAddress(Oracles)','OraclesCCTokensAddress', 'myaddress']:
assert_equal(result[x][0], 'R')
result = rpc.oraclesaddress(self.pubkey)
assert_success(result)
for x in ['OraclesCCAddress', 'OraclesNormalAddress', 'myCCAddress(Oracles)','OraclesCCTokensAddress', 'myaddress']:
assert_equal(result[x][0], 'R')
# there are no oracles created yet
result = rpc.oracleslist()
assert_equal(result, [])
# looking up non-existent oracle should return error.
result = rpc.oraclesinfo("none")
assert_error(result)
# attempt to create oracle with not valid data type should return error
result = rpc.oraclescreate("Test", "Test", "Test")
assert_error(result)
# attempt to create oracle with description > 32 symbols should return error
too_long_name = generate_random_string(33)
result = rpc.oraclescreate(too_long_name, "Test", "s")
# attempt to create oracle with description > 4096 symbols should return error
too_long_description = generate_random_string(4100)
result = rpc.oraclescreate("Test", too_long_description, "s")
assert_error(result)
# # valid creating oracles of different types
# # using such naming to re-use it for data publishing / reading (e.g. oracle_s for s type)
# valid_formats = ["s", "S", "d", "D", "c", "C", "t", "T", "i", "I", "l", "L", "h", "Ihh"]
# for f in valid_formats:
# result = rpc.oraclescreate("Test", "Test", f)
# assert_success(result)
# globals()["oracle_{}".format(f)] = self.send_and_mine(result['hex'], rpc)
def run_test (self):
print("Mining blocks...")
rpc = self.nodes[0]
rpc1 = self.nodes[1]
# utxos from block 1 become mature in block 101
rpc.generate(101)
self.sync_all()
rpc.getinfo()
rpc1.getinfo()
# this corresponds to -pubkey above
print("Importing privkeys")
rpc.importprivkey(self.privkey)
rpc1.importprivkey(self.privkey1)
self.run_faucet_tests()
self.sync_all()
self.run_rewards_tests()
self.sync_all()
self.run_dice_tests()
self.sync_all()
self.run_token_tests()
self.sync_all()
self.run_oracles_tests()
if __name__ == '__main__':
CryptoConditionsTest ().main()

View File

@@ -64,7 +64,7 @@ extern uint64_t ASSETCHAINS_CBOPRET;
void komodo_passport_iteration();
uint64_t komodo_interestsum();
int32_t komodo_longestchain();
void komodo_cbopretupdate();
void komodo_cbopretupdate(int32_t forceflag);
void WaitForShutdown(boost::thread_group* threadGroup)
{
@@ -89,7 +89,7 @@ void WaitForShutdown(boost::thread_group* threadGroup)
//komodo_interestsum();
//komodo_longestchain();
if ( ASSETCHAINS_CBOPRET != 0 )
komodo_cbopretupdate();
komodo_cbopretupdate(0);
for (i=0; i<=ASSETCHAINS_BLOCKTIME/5; i++)
{
fShutdown = ShutdownRequested();

View File

@@ -18,17 +18,33 @@
#define CC_PRICES_H
#include "CCinclude.h"
int32_t prices_extract(int64_t *pricedata,int32_t firstheight,int32_t numblocks,int32_t ind);
#define PRICES_DAYWINDOW ((3600*24/ASSETCHAINS_BLOCKTIME) + 1)
#define PRICES_TXFEE 10000
#define PRICES_MAXLEVERAGE 777
#define PRICES_SMOOTHWIDTH 1
#define KOMODO_MAXPRICES 2048 // must be power of 2 and less than 8192
#define KOMODO_PRICEMASK (~(KOMODO_MAXPRICES - 1))
#define PRICES_WEIGHT (KOMODO_MAXPRICES * 1)
#define PRICES_MULT (KOMODO_MAXPRICES * 2)
#define PRICES_DIV (KOMODO_MAXPRICES * 3)
#define PRICES_INV (KOMODO_MAXPRICES * 4)
#define PRICES_MDD (KOMODO_MAXPRICES * 5)
#define PRICES_MMD (KOMODO_MAXPRICES * 6)
#define PRICES_MMM (KOMODO_MAXPRICES * 7)
#define PRICES_DDD (KOMODO_MAXPRICES * 8)
bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
// CCcustom
UniValue PricesBet(uint64_t txfee,int64_t amount,int16_t leverage,std::vector<std::string> synthetic);
UniValue PricesAddFunding(uint64_t txfee,uint256 bettxid,int64_t amount);
UniValue PricesSetcostbasis(uint64_t txfee,uint256 bettxid);
UniValue PricesRekt(uint64_t txfee,uint256 bettxid,int32_t rektheight);
UniValue PricesCashout(uint64_t txfee,uint256 bettxid);
UniValue PricesInfo(uint256 bettxid,int32_t refheight);
UniValue PricesList();
UniValue PricesInfo(uint256 fundingtxid);
UniValue PricesStatus(uint64_t txfee,uint256 refbettoken,uint256 fundingtxid,uint256 bettxid);
std::string PricesCreateFunding(uint64_t txfee,uint256 bettoken,uint256 oracletxid,uint64_t margin,uint64_t mode,uint256 longtoken,uint256 shorttoken,int32_t maxleverage,int64_t funding,std::vector<CPubKey> pubkeys);
std::string PricesAddFunding(uint64_t txfee,uint256 bettoken,uint256 fundingtxid,int64_t amount);
std::string PricesBet(uint64_t txfee,uint256 bettoken,uint256 fundingtxid,int64_t amount,int32_t leverage);
std::string PricesFinish(uint64_t txfee,uint256 bettoken,uint256 fundingtxid,uint256 bettxid);
#endif

View File

@@ -195,7 +195,7 @@ cJSON *cclib_reparse(int32_t *nump,char *jsonstr) // assumes origparams will be
UniValue CClib_method(struct CCcontract_info *cp,char *method,char *jsonstr)
{
UniValue result(UniValue::VOBJ); uint64_t txfee = 10000; int32_t m; cJSON *params = cclib_reparse(&m,jsonstr);
//fprintf(stderr,"method.(%s) -> (%s)\n",jsonstr!=0?jsonstr:"",params!=0?jprint(params,0):"");
fprintf(stderr,"method.(%s) -> (%s)\n",jsonstr!=0?jsonstr:"",params!=0?jprint(params,0):"");
#ifdef BUILD_ROGUE
if ( cp->evalcode == EVAL_ROGUE )
{
@@ -351,7 +351,7 @@ UniValue CClib_info(struct CCcontract_info *cp)
UniValue CClib(struct CCcontract_info *cp,char *method,char *jsonstr)
{
UniValue result(UniValue::VOBJ); int32_t i; std::string rawtx; cJSON *params;
//printf("CClib params.(%s)\n",jsonstr!=0?jsonstr:"");
//printf("CClib params.(%s)\n",jsonstr!=0?jsonstr:"");
for (i=0; i<sizeof(CClib_methods)/sizeof(*CClib_methods); i++)
{
if ( cp->evalcode == CClib_methods[i].evalcode && strcmp(method,CClib_methods[i].method) == 0 )
@@ -369,7 +369,7 @@ UniValue CClib(struct CCcontract_info *cp,char *method,char *jsonstr)
}
}
result.push_back(Pair("result","error"));
result.push_back(Pair("method",CClib_methods[i].method));
result.push_back(Pair("method",method));
result.push_back(Pair("error","method not found"));
return(result);
}

View File

@@ -62,6 +62,8 @@ Possible third iteration:
// start of consensus code
#define CC_MARKER_VALUE 10000
int64_t IsChannelsvout(struct CCcontract_info *cp,const CTransaction& tx,CPubKey srcpub, CPubKey destpub,int32_t v)
{
char destaddr[65],channeladdr[65],tokenschanneladdr[65];
@@ -126,8 +128,8 @@ uint8_t DecodeChannelsOpRet(const CScript &scriptPubKey, uint256 &tokenid, uint2
{
return(f);
}
} else fprintf(stderr,"script[0] %02x != EVAL_CHANNELS\n",script[0]);
} else fprintf(stderr,"not enough opret.[%d]\n",(int32_t)vopret.size());
} else LOGSTREAM("channelscc",CCLOG_DEBUG1, stream << "script[0] " << script[0] << " != EVAL_CHANNELS" << std::endl);
} else LOGSTREAM("channelscc",CCLOG_DEBUG1, stream << "not enough opret.[" << vopret.size() << "]" << std::endl);
return(0);
}
@@ -167,7 +169,7 @@ bool ChannelsExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransacti
}
if ( inputs != outputs )
{
fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
LOGSTREAM("channelscc",CCLOG_INFO, stream << "inputs " << inputs << " vs outputs " << outputs << std::endl);
return eval->Invalid("mismatched inputs != outputs");
}
else return (true);
@@ -183,7 +185,7 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
{
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numpayments,p1,param1; bool retval;
uint256 txid,hashblock,p3,param3,opentxid,tmp_txid,genhashchain,hashchain,tokenid;
uint8_t funcid,hash[32],hashdest[32];
uint8_t funcid,hash[32],hashdest[32]; char channeladdress[65],srcmarker[65],destmarker[65],destaddr[65],srcaddr[65],desttokensaddr[65],srctokensaddr[65];
int64_t p2,param2,payment;
CPubKey srcpub, destpub;
CTransaction channelOpenTx,channelCloseTx,prevTx;
@@ -202,9 +204,20 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
else
{
txid = tx.GetHash();
memcpy(hash,&txid,sizeof(hash));
memcpy(hash,&txid,sizeof(hash));
if ( (funcid = DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey, tokenid, opentxid, srcpub, destpub, param1, param2, param3)) != 0)
{
if (myGetTransaction(opentxid,channelOpenTx,hashblock)== 0)
return eval->Invalid("invalid channelopen tx!");
else if ((numvouts=channelOpenTx.vout.size()) > 0 && (DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, numpayments, payment, hashchain)) != 'O')
return eval->Invalid("invalid channelopen OP_RETURN data!");
GetCCaddress1of2(cp,channeladdress,srcpub,destpub);
GetCCaddress(cp,srcmarker,srcpub);
GetCCaddress(cp,destmarker,destpub);
Getscriptaddress(srcaddr,CScript() << ParseHex(HexStr(srcpub)) << OP_CHECKSIG);
Getscriptaddress(destaddr,CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG);
_GetCCaddress(srctokensaddr,EVAL_TOKENS,srcpub);
_GetCCaddress(desttokensaddr,EVAL_TOKENS,destpub);
switch ( funcid )
{
case 'O':
@@ -225,56 +238,53 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
//vout.3: normal output of payment amount to receiver pubkey
//vout.n-2: normal change
//vout.n-1: opreturn - 'P' opentxid senderspubkey receiverspubkey depth numpayments secret
if (komodo_txnotarizedconfirmed(opentxid) == 0)
return eval->Invalid("channelOpen is not yet confirmed(notarised)!");
if ( IsCCInput(channelOpenTx.vin[0].scriptSig) != 0 )
return eval->Invalid("vin.0 is normal for channelopen!");
else if ( ConstrainVout(channelOpenTx.vout[0],1,channeladdress,numpayments*payment)==0 )
return eval->Invalid("vout.0 is CC or invalid amount for channelopen!");
else if ( ConstrainVout(channelOpenTx.vout[1],1,srcmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.1 is CC marker to srcpub or invalid amount for channelopen!");
else if ( ConstrainVout(channelOpenTx.vout[2],1,destmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.2 is CC marker to destpub or invalid amount for channelopen!");
else if (komodo_txnotarizedconfirmed(opentxid) == 0)
return eval->Invalid("channelopen is not yet confirmed(notarised)!");
else if ( IsCCInput(tx.vin[0].scriptSig) != 0 )
return eval->Invalid("vin.0 is normal for channelPayment!");
return eval->Invalid("vin.0 is normal for channelpayment!");
else if ( IsCCInput(tx.vin[1].scriptSig) == 0 )
return eval->Invalid("vin.1 is CC for channelPayment!");
return eval->Invalid("vin.1 is CC for channelpayment!");
else if ( IsCCInput(tx.vin[2].scriptSig) == 0 )
return eval->Invalid("vin.2 is CC for channelPayment!");
else if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition()==0 )
return eval->Invalid("vout.0 is CC for channelPayment!");
else if ( IsChannelsMarkervout(cp,tx,srcpub,1)==0 )
return eval->Invalid("vout.1 is CC for channelPayment (marker to srcPub)!");
else if ( IsChannelsMarkervout(cp,tx,destpub,2)==0 )
return eval->Invalid("vout.2 is CC for channelPayment (marker to dstPub)!");
else if ( tokenid!=zeroid && tx.vout[3].scriptPubKey.IsPayToCryptoCondition() == 0 )
return eval->Invalid("vout.3 is CC for channelPayment!");
else if ( tokenid==zeroid && tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 )
return eval->Invalid("vout.3 is normal for channelPayment!");
else if ( tokenid!=zeroid && tx.vout[3].scriptPubKey!=MakeCC1vout(EVAL_TOKENS,tx.vout[3].nValue,destpub).scriptPubKey)
return eval->Invalid("payment funds do not go to receiver!");
else if ( tokenid==zeroid && tx.vout[3].scriptPubKey!=CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG)
return eval->Invalid("payment funds do not go to receiver!");
return eval->Invalid("vin.2 is CC for channelpayment!");
else if ( ConstrainVout(tx.vout[1],1,srcmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.1 is CC marker to srcpub or invalid amount for channelpayment!");
else if ( ConstrainVout(tx.vout[2],1,destmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.2 is CC marker to destpub or invalid amount for channelpayment!");
else if ( tokenid!=zeroid && ConstrainVout(tx.vout[3],1,desttokensaddr,param2*payment)==0 )
return eval->Invalid("vout.3 is CC or invalid amount or invalid receiver for channelpayment!");
else if ( tokenid==zeroid && ConstrainVout(tx.vout[3],0,destaddr,param2*payment)==0 )
return eval->Invalid("vout.3 is normal or invalid amount or invalid receiver for channelpayment!");
else if ( param1 > CHANNELS_MAXPAYMENTS)
return eval->Invalid("too many payment increments!");
else
{
if (myGetTransaction(opentxid,channelOpenTx,hashblock) != 0)
{
endiancpy(hash, (uint8_t * ) & param3, 32);
for (i = 0; i < numpayments-param1; i++)
{
if ((numvouts=channelOpenTx.vout.size()) > 0 && (funcid=DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, numpayments, payment, hashchain)) != 0 && funcid!='O')
return eval->Invalid("invalid channelopen OP_RETURN data!");
endiancpy(hash, (uint8_t * ) & param3, 32);
for (i = 0; i < numpayments-param1; i++)
{
vcalc_sha256(0, hashdest, hash, 32);
memcpy(hash, hashdest, 32);
}
endiancpy((uint8_t*)&genhashchain,hashdest,32);
if (hashchain!=genhashchain)
return eval->Invalid("invalid secret for payment, does not reach final hashchain!");
else if (tx.vout[3].nValue != param2*payment)
return eval->Invalid("vout amount does not match number_of_payments*payment!");
vcalc_sha256(0, hashdest, hash, 32);
memcpy(hash, hashdest, 32);
}
endiancpy((uint8_t*)&genhashchain,hashdest,32);
if (hashchain!=genhashchain)
return eval->Invalid("invalid secret for payment, does not reach final hashchain!");
else if (tx.vout[3].nValue != param2*payment)
return eval->Invalid("vout amount does not match number_of_payments*payment!");
if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0)
{
if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, p1, p2, p3) == 0)
return eval->Invalid("invalid previous tx OP_RETURN data!");
else if (tx.vout[1].scriptPubKey != prevTx.vout[1].scriptPubKey)
return eval->Invalid("invalid destination for sender marker!");
else if (tx.vout[2].scriptPubKey != prevTx.vout[2].scriptPubKey)
return eval->Invalid("invalid destination for receiver marker!");
else if ( ConstrainVout(tx.vout[0],1,channeladdress,(p1-param2)*payment)==0 )
return eval->Invalid("vout.0 is CC or invalid CC change amount for channelpayment!");
else if ((*cp->ismyvin)(tx.vin[2].scriptSig) == 0 || prevTx.vout[tx.vin[2].prevout.n].nValue!=CC_MARKER_VALUE)
return eval->Invalid("vin.2 is CC marker or invalid marker amount for channelpayment!");
else if (param1+param2!=p1)
return eval->Invalid("invalid payment depth!");
else if (tx.vout[3].nValue > prevTx.vout[0].nValue)
@@ -290,37 +300,37 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
//vout.1: CC vout marker to senders pubKey
//vout.2: CC vout marker to receiver pubkey
//vout.n-2: normal change
//vout.n-1: opreturn - 'C' opentxid senderspubkey receiverspubkey 0 0 0
if (komodo_txnotarizedconfirmed(opentxid) == 0)
return eval->Invalid("channelOpen is not yet confirmed(notarised)!");
//vout.n-1: opreturn - 'C' opentxid senderspubkey receiverspubkey numpayments payment 0
if ( IsCCInput(channelOpenTx.vin[0].scriptSig) != 0 )
return eval->Invalid("vin.0 is normal for channelopen!");
else if ( ConstrainVout(channelOpenTx.vout[0],1,channeladdress,numpayments*payment)==0 )
return eval->Invalid("vout.0 is CC or invalid amount for channelopen!");
else if ( ConstrainVout(channelOpenTx.vout[1],1,srcmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.1 is CC marker to srcpub or invalid amount for channelopen!");
else if ( ConstrainVout(channelOpenTx.vout[2],1,destmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.2 is CC marker to destpub or invalid amount for channelopen!");
else if (komodo_txnotarizedconfirmed(opentxid) == 0)
return eval->Invalid("channelopen is not yet confirmed(notarised)!");
else if ( IsCCInput(tx.vin[0].scriptSig) != 0 )
return eval->Invalid("vin.0 is normal for channelClose!");
return eval->Invalid("vin.0 is normal for channelclose!");
else if ( IsCCInput(tx.vin[1].scriptSig) == 0 )
return eval->Invalid("vin.1 is CC for channelClose!");
return eval->Invalid("vin.1 is CC for channelclose!");
else if ( IsCCInput(tx.vin[2].scriptSig) == 0 )
return eval->Invalid("vin.2 is CC for channelClose!");
else if ( IsChannelsvout(cp,tx,srcpub,destpub,0)==0 )
return eval->Invalid("vout.0 is CC for channelClose!");
else if ( IsChannelsMarkervout(cp,tx,srcpub,1)==0 )
return eval->Invalid("vout.1 is CC for channelClose (marker to srcPub)!");
else if ( IsChannelsMarkervout(cp,tx,destpub,2)==0 )
return eval->Invalid("vout.2 is CC for channelClose (marker to dstPub)!");
return eval->Invalid("vin.2 is CC for channelclose!");
else if ( ConstrainVout(tx.vout[0],1,channeladdress,0)==0 )
return eval->Invalid("vout.0 is CC for channelclose!");
else if ( ConstrainVout(tx.vout[1],1,srcmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.1 is CC marker to srcpub or invalid amount for channelclose!");
else if ( ConstrainVout(tx.vout[2],1,destmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.2 is CC marker to destpub or invalid amount for channelclose!");
else if ( param1 > CHANNELS_MAXPAYMENTS)
return eval->Invalid("too many payment increments!");
else if (myGetTransaction(opentxid,channelOpenTx,hashblock) == 0)
return eval->Invalid("invalid open txid!");
else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) != 'O')
return eval->Invalid("invalid channelopen OP_RETURN data!");
else if (tx.vout[0].nValue != param1*payment)
return eval->Invalid("vout amount does not match number_of_payments*payment!");
else if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0)
{
if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, p1, p2, p3) == 0)
return eval->Invalid("invalid previous tx OP_RETURN data!");
else if (tx.vout[1].scriptPubKey != prevTx.vout[1].scriptPubKey)
return eval->Invalid("invalid destination for sender marker!");
else if (tx.vout[2].scriptPubKey != prevTx.vout[2].scriptPubKey)
return eval->Invalid("invalid destination for receiver marker!");
else if ((*cp->ismyvin)(tx.vin[2].scriptSig) == 0 || prevTx.vout[tx.vin[2].prevout.n].nValue!=CC_MARKER_VALUE)
return eval->Invalid("vin.2 is CC marker or invalid marker amount for channelclose!");
else if (tx.vout[0].nValue != prevTx.vout[0].nValue)
return eval->Invalid("invalid CC amount, amount must match funds in channel");
}
@@ -334,50 +344,40 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
//vout.2: normal output of CC input to senders pubkey
//vout.n-2: normal change
//vout.n-1: opreturn - 'R' opentxid senderspubkey receiverspubkey numpayments payment closetxid
if (komodo_txnotarizedconfirmed(opentxid) == 0)
return eval->Invalid("channelOpen is not yet confirmed(notarised)!");
if ( IsCCInput(channelOpenTx.vin[0].scriptSig) != 0 )
return eval->Invalid("vin.0 is normal for channelopen!");
else if ( ConstrainVout(channelOpenTx.vout[0],1,channeladdress,numpayments*payment)==0 )
return eval->Invalid("vout.0 is CC or invalid amount for channelopen!");
else if ( ConstrainVout(channelOpenTx.vout[1],1,srcmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.1 is CC marker to srcpub or invalid amount for channelopen!");
else if ( ConstrainVout(channelOpenTx.vout[2],1,destmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.2 is CC marker to destpub or invalid amount for channelopen!");
else if (komodo_txnotarizedconfirmed(opentxid) == 0)
return eval->Invalid("channelopen is not yet confirmed(notarised)!");
else if (komodo_txnotarizedconfirmed(param3) == 0)
return eval->Invalid("channelClose is not yet confirmed(notarised)!");
else if ( IsCCInput(tx.vin[0].scriptSig) != 0 )
return eval->Invalid("vin.0 is normal for channelRefund!");
return eval->Invalid("vin.0 is normal for channelrefund!");
else if ( IsCCInput(tx.vin[1].scriptSig) == 0 )
return eval->Invalid("vin.1 is CC for channelRefund!");
return eval->Invalid("vin.1 is CC for channelrefund!");
else if ( IsCCInput(tx.vin[2].scriptSig) == 0 )
return eval->Invalid("vin.2 is CC for channelRefund!");
else if ( IsChannelsMarkervout(cp,tx,srcpub,0)==0 )
return eval->Invalid("vout.0 is CC for channelRefund (marker to srcPub)!");
else if ( IsChannelsMarkervout(cp,tx,destpub,1)==0 )
return eval->Invalid("vout.1 is CC for channelRefund (marker to dstPub)!");
else if ( tokenid!=zeroid && tx.vout[2].scriptPubKey.IsPayToCryptoCondition() == 0 )
return eval->Invalid("vout.2 is CC for channelPayment!");
else if ( tokenid==zeroid && tx.vout[2].scriptPubKey.IsPayToCryptoCondition() != 0 )
return eval->Invalid("vout.2 is normal for channelPayment!");
else if ( tokenid!=zeroid && tx.vout[2].scriptPubKey!=MakeCC1vout(EVAL_TOKENS,tx.vout[2].nValue,srcpub).scriptPubKey)
return eval->Invalid("payment funds do not go to sender!");
else if ( tokenid==zeroid && tx.vout[2].scriptPubKey!=CScript() << ParseHex(HexStr(srcpub)) << OP_CHECKSIG)
return eval->Invalid("payment funds do not go to sender!");
return eval->Invalid("vin.2 is CC for channelrefund!");
else if ( ConstrainVout(tx.vout[0],1,srcmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.0 is CC marker to srcpub or invalid amount for channelrefund!");
else if ( ConstrainVout(tx.vout[1],1,destmarker,CC_MARKER_VALUE)==0 )
return eval->Invalid("vout.1 is CC marker to destpub or invalid amount for channelrefund!");
else if ( tokenid!=zeroid && ConstrainVout(tx.vout[2],1,srctokensaddr,param1*payment)==0 )
return eval->Invalid("vout.2 is CC or invalid amount or invalid receiver for channelrefund!");
else if ( tokenid==zeroid && ConstrainVout(tx.vout[2],0,srcaddr,param1*payment)==0 )
return eval->Invalid("vout.2 is normal or invalid amount or invalid receiver for channelrefund!");
else if ( param1 > CHANNELS_MAXPAYMENTS)
return eval->Invalid("too many payment increments!");
else if (myGetTransaction(opentxid,channelOpenTx,hashblock) == 0)
return eval->Invalid("invalid open txid!");
else if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, numpayments, payment, hashchain) != 'O')
return eval->Invalid("invalid channelopen OP_RETURN data!");
else if (myGetTransaction(param3,channelCloseTx,hashblock) == 0)
return eval->Invalid("invalid close txid!");
else if ((numvouts=channelCloseTx.vout.size()) > 0 && DecodeChannelsOpRet(channelCloseTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, param1, param2, param3) != 'C')
return eval->Invalid("invalid channelclose OP_RETURN data!");
else if (tmp_txid!=opentxid)
return eval->Invalid("invalid close tx, opentxid do not match on close and refund!");
else if (tx.vout[2].nValue != param1*payment)
return eval->Invalid("vout amount does not match number_of_payments*payment!");
else if (myGetTransaction(tx.vin[1].prevout.hash,prevTx,hashblock) != 0)
{
if ((numvouts=prevTx.vout.size()) > 0 && DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tokenid, tmp_txid, srcpub, destpub, p1, p2, p3) == 0)
return eval->Invalid("invalid previous tx OP_RETURN data!");
else if (tx.vout[0].scriptPubKey != prevTx.vout[1].scriptPubKey)
return eval->Invalid("invalid destination for sender marker!");
else if (tx.vout[1].scriptPubKey != prevTx.vout[2].scriptPubKey)
return eval->Invalid("invalid destination for receiver marker!");
else if ((*cp->ismyvin)(tx.vin[2].scriptSig) == 0 || prevTx.vout[tx.vin[2].prevout.n].nValue!=CC_MARKER_VALUE)
return eval->Invalid("vin.2 is CC marker or invalid marker amount for channelrefund!");
else if (tx.vout[2].nValue != prevTx.vout[0].nValue)
return eval->Invalid("invalid amount, refund amount and funds in channel must match!");
}
@@ -390,8 +390,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &
else return eval->Invalid("unexpected channels missing funcid");
retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts);
if ( retval != 0 )
fprintf(stderr,"Channel tx validated\n");
else fprintf(stderr,"Channel tx invalid\n");
LOGSTREAM("channels",CCLOG_INFO, stream << "Channels tx validated" << std::endl);
else fprintf(stderr,"Channels tx invalid\n");
return(retval);
}
}
@@ -415,7 +415,7 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C
}
else
{
fprintf(stderr,"invalid channel open txid\n");
LOGSTREAM("channelscc",CCLOG_INFO, stream << "invalid channel open txid" << std::endl);
return 0;
}
if (srcpub==mypk) marker=1;
@@ -473,7 +473,7 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64
if ( numpayments <= 0 || payment <= 0 || numpayments > CHANNELS_MAXPAYMENTS )
{
CCerror = strprintf("invalid ChannelOpen param numpayments.%d max.%d payment.%lld\n",numpayments,CHANNELS_MAXPAYMENTS,(long long)payment);
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
cp = CCinit(&C,EVAL_CHANNELS);
@@ -484,11 +484,11 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64
funds = numpayments * payment;
if (tokenid!=zeroid)
{
amount=AddNormalinputs(mtx,mypk,3*txfee,5);
amount=AddNormalinputs(mtx,mypk,txfee+2*CC_MARKER_VALUE,5);
tokens=AddTokenCCInputs(cpTokens, mtx, mypk, tokenid, funds, 64);
}
else amount=AddNormalinputs(mtx,mypk,funds+3*txfee,64);
if (amount+tokens >= funds+2*txfee)
else amount=AddNormalinputs(mtx,mypk,funds+txfee+2*CC_MARKER_VALUE,64);
if (amount+tokens >= funds+txfee+2*CC_MARKER_VALUE)
{
hentropy = DiceHashEntropy(entropy,mtx.vin[0].prevout.hash,mtx.vin[0].prevout.n,1);
endiancpy(hash,(uint8_t *)&hentropy,32);
@@ -500,13 +500,13 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64
endiancpy((uint8_t *)&hashchain,hashdest,32);
if (tokenid!=zeroid) mtx.vout.push_back(MakeTokensCC1of2vout(EVAL_CHANNELS,funds,mypk,destpub));
else mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS,funds,mypk,destpub));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,CC_MARKER_VALUE,mypk));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,CC_MARKER_VALUE,destpub));
if (tokenid!=zeroid && tokens>funds) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,tokens-funds,mypk));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('O',tokenid,zeroid,mypk,destpub,numpayments,payment,hashchain)));
}
CCerror = strprintf("error adding funds");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
@@ -526,7 +526,7 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2
if (GetTransaction(opentxid,channelOpenTx,hashblock,false) == 0)
{
CCerror = strprintf("invalid channel open txid");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tokenid, txid, srcpub, destpub, totalnumpayments, payment, hashchain)=='O')
@@ -534,23 +534,29 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2
if (mypk != srcpub && mypk != destpub)
{
CCerror = strprintf("this is not our channel");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
else if (amount % payment != 0 || amount<payment)
{
CCerror = strprintf("invalid amount, not a magnitude of payment size");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return ("");
}
}
else
{
CCerror = strprintf("invalid channel open tx");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return ("");
}
if (AddNormalinputs(mtx,mypk,2*txfee,3) > 0)
if (komodo_txnotarizedconfirmed(opentxid)==false)
{
CCerror = strprintf("channelsopen tx not yet confirmed/notarized");
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
if (AddNormalinputs(mtx,mypk,txfee+CC_MARKER_VALUE,3) > 0)
{
if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid,mypk)) !=0 && (change=funds-amount)>=0)
{
@@ -562,12 +568,12 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2
if (numpayments > prevdepth)
{
CCerror = strprintf("not enough funds in channel for that amount");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return ("");
} else if (numpayments == 0)
{
CCerror = strprintf("invalid amount");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return ("");
}
if (secret!=zeroid)
@@ -582,7 +588,7 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2
if (gensecret!=hashchain)
{
CCerror = strprintf("invalid secret supplied");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
}
@@ -605,13 +611,13 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2
else
{
CCerror = strprintf("invalid previous tx");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
if (tokenid!=zeroid) mtx.vout.push_back(MakeTokensCC1of2vout(EVAL_CHANNELS, change, srcpub, destpub));
else mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, change, srcpub, destpub));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,srcpub));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,CC_MARKER_VALUE,srcpub));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,CC_MARKER_VALUE,destpub));
if (tokenid!=zeroid) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, amount, destpub));
else mtx.vout.push_back(CTxOut(amount, CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG));
return (FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeChannelsOpRet('P', tokenid, opentxid, srcpub, destpub, prevdepth-numpayments, numpayments, secret)));
@@ -619,12 +625,12 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2
else
{
CCerror = strprintf("error adding CC inputs");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
}
CCerror = strprintf("error adding normal inputs");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
@@ -645,40 +651,46 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid)
if (GetTransaction(opentxid,channelOpenTx,hashblock,false) == 0)
{
CCerror = strprintf("invalid channel open txid");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return ("");
}
if ((numvouts=channelOpenTx.vout.size()) < 1 || DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,numpayments,payment,hashchain)!='O')
{
CCerror = strprintf("invalid channel open tx");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return ("");
}
if (komodo_txnotarizedconfirmed(opentxid)==false)
{
CCerror = strprintf("channelsopen tx not yet confirmed/notarized");
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
if (mypk != srcpub)
{
CCerror = strprintf("cannot close, you are not channel owner");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 )
if ( AddNormalinputs(mtx,mypk,txfee+CC_MARKER_VALUE,3) > 0 )
{
if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid,mypk)) !=0 && funds>0)
{
if (tokenid!=zeroid) mtx.vout.push_back(MakeTokensCC1of2vout(EVAL_CHANNELS, funds, mypk, destpub));
else mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, funds, mypk, destpub));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,CC_MARKER_VALUE,mypk));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,CC_MARKER_VALUE,destpub));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('C',tokenid,opentxid,mypk,destpub,funds/payment,payment,zeroid)));
}
else
{
CCerror = strprintf("error adding CC inputs");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
}
CCerror = strprintf("error adding normal inputs");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
@@ -699,48 +711,60 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid)
if (GetTransaction(closetxid,channelCloseTx,hashblock,false) == 0)
{
CCerror = strprintf("invalid channel close txid");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return ("");
}
if ((numvouts=channelCloseTx.vout.size()) < 1 || DecodeChannelsOpRet(channelCloseTx.vout[numvouts-1].scriptPubKey,tokenid,txid,srcpub,destpub,param1,param2,param3)!='C')
{
CCerror = strprintf("invalid channel close tx");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return ("");
}
if (komodo_txnotarizedconfirmed(closetxid)==false)
{
CCerror = strprintf("channelsclose tx not yet confirmed/notarized");
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
if (txid!=opentxid)
{
CCerror = strprintf("open and close txid are not from same channel");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return ("");
}
if (GetTransaction(opentxid,channelOpenTx,hashblock,false) == 0)
{
CCerror = strprintf("invalid channel open txid");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return ("");
}
if (komodo_txnotarizedconfirmed(opentxid)==false)
{
CCerror = strprintf("channelsopen tx not yet confirmed/notarized");
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
if ((numvouts=channelOpenTx.vout.size()) < 1 || DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,tokenid,txid,srcpub,destpub,numpayments,payment,hashchain)!='O')
{
CCerror = strprintf("invalid channel open tx");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return ("");
}
if (mypk != srcpub)
{
CCerror = strprintf("cannot refund, you are not the channel owner");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 )
if ( AddNormalinputs(mtx,mypk,txfee+CC_MARKER_VALUE,3) > 0 )
{
if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid,mypk)) !=0 && funds>0)
{
if ((GetTransaction(prevtxid,prevTx,hashblock,false) != 0) && (numvouts=prevTx.vout.size()) > 0 &&
DecodeChannelsOpRet(prevTx.vout[numvouts-1].scriptPubKey, tokenid, txid, srcpub, destpub, param1, param2, param3) != 0)
{
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,mypk));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,CC_MARKER_VALUE,mypk));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,CC_MARKER_VALUE,destpub));
if (tokenid!=zeroid) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,funds,mypk));
else mtx.vout.push_back(CTxOut(funds,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('R',tokenid,opentxid,mypk,destpub,funds/payment,payment,closetxid)));
@@ -748,19 +772,19 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid)
else
{
CCerror = strprintf("previous tx is invalid");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
}
else
{
CCerror = strprintf("error adding CC inputs");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
}
CCerror = strprintf("error adding normal inputs");
fprintf(stderr,"%s\n",CCerror.c_str());
LOGSTREAM("channelscc",CCLOG_INFO, stream << CCerror << std::endl);
return("");
}
@@ -781,7 +805,7 @@ UniValue ChannelsList()
txid = it->first.txhash;
vout = (int32_t)it->first.index;
nValue = (int64_t)it->second;
if ( (vout == 1 || vout == 2) && nValue == 10000 && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
if ( (vout == 1 || vout == 2) && nValue == CC_MARKER_VALUE && GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
{
if (DecodeChannelsOpRet(tx.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,param1,param2,param3) == 'O')
{

View File

@@ -732,6 +732,78 @@ UniValue PaymentsCreate(struct CCcontract_info *cp,char *jsonstr)
return(result);
}
UniValue PaymentsAirdrop(struct CCcontract_info *cp,char *jsonstr)
{
// need to code: exclude list of tokenid, dust threshold, maxpayees, excluded pubkeys[]
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
UniValue result(UniValue::VOBJ); CTransaction tx; CPubKey Paymentspk,mypk; char markeraddr[64]; std::vector<uint256> txidoprets; uint256 hashBlock; int32_t i,n,numoprets=0,lockedblocks,minrelease; std::string rawtx; int64_t totalallocations = 0;
cJSON *params = payments_reparse(&n,jsonstr);
if ( params != 0 && n >= 4 )
{
lockedblocks = juint(jitem(params,0),0);
minrelease = juint(jitem(params,1),0);
if ( lockedblocks < 0 || minrelease < 0 )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","negative parameter"));
if ( params != 0 )
free_json(params);
return(result);
}
for (i=0; i<n-2; i++)
txidoprets.push_back(payments_juint256(jitem(params,2+i)));
for (i=0; i<txidoprets.size(); i++)
{
std::vector<uint8_t> scriptPubKey,opret; int64_t allocation;
if ( myGetTransaction(txidoprets[i],tx,hashBlock) != 0 && tx.vout.size() > 1 && DecodePaymentsTxidOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,allocation,scriptPubKey,opret) == 'T' )
{
totalallocations += allocation;
if ( opret.size() > 0 )
numoprets++;
}
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","invalid txidopret"));
result.push_back(Pair("txid",txidoprets[i].GetHex()));
result.push_back(Pair("txi",(int64_t)i));
if ( params != 0 )
free_json(params);
return(result);
}
}
if ( numoprets > 1 )
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","too many opreturns"));
result.push_back(Pair("numoprets",(int64_t)numoprets));
if ( params != 0 )
free_json(params);
return(result);
}
mypk = pubkey2pk(Mypubkey());
Paymentspk = GetUnspendable(cp,0);
if ( AddNormalinputs(mtx,mypk,2*PAYMENTS_TXFEE,60) > 0 )
{
mtx.vout.push_back(MakeCC1of2vout(cp->evalcode,PAYMENTS_TXFEE,Paymentspk,Paymentspk));
rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,EncodePaymentsOpRet(lockedblocks,minrelease,totalallocations,txidoprets));
if ( params != 0 )
free_json(params);
return(payments_rawtxresult(result,rawtx,1));
}
result.push_back(Pair("result","error"));
result.push_back(Pair("error","not enough normal funds"));
}
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","parameters error"));
}
if ( params != 0 )
free_json(params);
return(result);
}
UniValue PaymentsInfo(struct CCcontract_info *cp,char *jsonstr)
{
UniValue result(UniValue::VOBJ),a(UniValue::VARR); CTransaction tx,txO; CPubKey Paymentspk,txidpk; int32_t i,j,n,flag=0,numoprets=0,lockedblocks,minrelease; std::vector<uint256> txidoprets; int64_t funds,fundsopret,totalallocations=0,allocation; char fundsaddr[64],fundsopretaddr[64],txidaddr[64],*outstr; uint256 createtxid,hashBlock;

View File

@@ -16,15 +16,7 @@
#include "CCPegs.h"
/*
Pegs CC builds on top of Prices CC and would bind a pricefeed to a token bid/ask automated marketmaking.
Funds deposited into CC address for a specific peg would then be used to fund the bid/ask as the pricefeed changes the price. Profits/losses would accumulate in the associated address.
In the event funds exceed a specified level, it can be spent into a collection address. The idea is that the collection address can further be used for revshares.
int64_t OraclePrice(int32_t height,uint256 reforacletxid,char *markeraddr,char *format);
OraclePrice is very useful for pegs.
*/

File diff suppressed because it is too large Load Diff

View File

@@ -35,7 +35,7 @@
* for both bitcoind and bitcoin-core, to make it harder for attackers to
* target servers or GUI users specifically.
*/
const std::string CLIENT_NAME = GetArg("-ac_clientname", "MagicBean");
const std::string CLIENT_NAME = GetArg("-clientname", "MagicBean");
/**
* Client version number

View File

@@ -367,6 +367,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-blocknotify=<cmd>", _("Execute command when the best block changes (%s in cmd is replaced by block hash)"));
strUsage += HelpMessageOpt("-checkblocks=<n>", strprintf(_("How many blocks to check at startup (default: %u, 0 = all)"), 288));
strUsage += HelpMessageOpt("-checklevel=<n>", strprintf(_("How thorough the block verification of -checkblocks is (0-4, default: %u)"), 3));
strUsage += HelpMessageOpt("-clientname=<SomeName>", _("Full node client name, default 'MagicBean'"));
strUsage += HelpMessageOpt("-conf=<file>", strprintf(_("Specify configuration file (default: %s)"), "komodo.conf"));
if (mode == HMM_BITCOIND)
{
@@ -571,7 +572,6 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += HelpMessageOpt("-ac_cclib", _("Cryptoconditions dynamicly loadable library"));
strUsage += HelpMessageOpt("-ac_ccenable", _("Cryptoconditions to enable"));
strUsage += HelpMessageOpt("-ac_ccactivate", _("Block height to enable Cryptoconditions"));
strUsage += HelpMessageOpt("-ac_clientname", _("Full node client name, default 'MagicBean'"));
strUsage += HelpMessageOpt("-ac_decay", _("Percentage of block reward decrease at each halving"));
strUsage += HelpMessageOpt("-ac_end", _("Block height at which block rewards will end"));
strUsage += HelpMessageOpt("-ac_eras", _("Block reward eras"));

View File

@@ -37,6 +37,7 @@
#define KOMODO_MAXNVALUE (((uint64_t)1 << 63) - 1)
#define KOMODO_BIT63SET(x) ((x) & ((uint64_t)1 << 63))
#define KOMODO_VALUETOOBIG(x) ((x) > (uint64_t)10000000001*COIN)
#define PRICES_DAYWINDOW ((3600*24/ASSETCHAINS_BLOCKTIME) + 1)
extern uint8_t ASSETCHAINS_TXPOW,ASSETCHAINS_PUBLIC;
int32_t MAX_BLOCK_SIZE(int32_t height);
@@ -59,6 +60,7 @@ extern uint32_t ASSETCHAINS_VERUSHASH, ASSETCHAINS_VERUSHASHV1_1, ASSETCHAINS_NO
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
extern std::string NOTARY_PUBKEY,ASSETCHAINS_OVERRIDE_PUBKEY,ASSETCHAINS_SCRIPTPUB;
extern uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],ASSETCHAINS_MARMARA;
extern std::vector<std::string> ASSETCHAINS_PRICES;
extern char ASSETCHAINS_SYMBOL[65];
extern int32_t VERUS_BLOCK_POSUNITS, VERUS_CONSECUTIVE_POS_THRESHOLD, VERUS_NOPOS_THRESHHOLD;
@@ -82,5 +84,6 @@ int tx_height( const uint256 &hash );
extern char NOTARYADDRS[64][36];
extern uint8_t NUM_NOTARIES;
void komodo_netevent(std::vector<uint8_t> payload);
int32_t komodo_priceind(char *symbol);
#endif

View File

@@ -1551,11 +1551,35 @@ void komodo_passport_iteration()
extern std::vector<uint8_t> Mineropret; // opreturn data set by the data gathering code
#define PRICES_MAXCHANGE (COIN / 100) // maximum acceptable change, set at 1%
#define PRICES_SIZEBIT0 (sizeof(uint32_t) * 4) // 4 uint32_t unixtimestamp, BTCUSD, BTCGBP and BTCEUR
#define KOMODO_LOCALPRICE_CACHESIZE 7
#define KOMODO_MAXPRICES 2048
#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"CBCOINBASE",cmdstr,0,0,0)
const char *Cryptos[] = { "KMD", "ETH" }; // must be on binance (for now)
// "LTC", "BCHABC", "XMR", "IOTA", "ZEC", "WAVES", "LSK", "DCR", "RVN", "DASH", "XEM", "BTS", "ICX", "HOT", "STEEM", "ENJ", "STRAT"
const char *Forex[] =
{ "BGN","NZD","ILS","RUB","CAD","PHP","CHF","AUD","JPY","TRY","HKD","MYR","HRK","CZK","IDR","DKK","NOK","HUF","GBP","MXN","THB","ISK","ZAR","BRL","SGD","PLN","INR","KRW","RON","CNY","SEK","EUR"
}; // must be in ECB list
uint32_t PriceCache[KOMODO_LOCALPRICE_CACHESIZE][KOMODO_MAXPRICES];//4+sizeof(Cryptos)/sizeof(*Cryptos)+sizeof(Forex)/sizeof(*Forex)];
int64_t PriceMult[KOMODO_MAXPRICES];
int32_t komodo_cbopretsize(uint64_t flags);
void komodo_PriceCache_shift()
{
int32_t i;
for (i=KOMODO_LOCALPRICE_CACHESIZE-1; i>0; i--)
memcpy(PriceCache[i],PriceCache[i-1],sizeof(PriceCache[i]));
memcpy(PriceCache[0],Mineropret.data(),Mineropret.size());
}
// komodo_heightpricebits() extracts the price data in the coinbase for nHeight
int32_t komodo_heightpricebits(uint32_t prevbits[4],int32_t nHeight)
int32_t komodo_heightpricebits(uint64_t *seedp,uint32_t *heightbits,int32_t nHeight)
{
CBlockIndex *pindex; CBlock block; CTransaction tx; int32_t numvouts; std::vector<uint8_t> vopret;
if ( seedp != 0 )
*seedp = 0;
if ( (pindex= komodo_chainactive(nHeight)) != 0 )
{
if ( komodo_blockload(block,pindex) == 0 )
@@ -1565,8 +1589,10 @@ int32_t komodo_heightpricebits(uint32_t prevbits[4],int32_t nHeight)
GetOpReturnData(tx.vout[numvouts-1].scriptPubKey,vopret);
if ( vopret.size() >= PRICES_SIZEBIT0 )
{
memcpy(prevbits,vopret.data(),vopret.size());
return(0);
if ( seedp != 0 )
memcpy(seedp,&pindex->hashMerkleRoot,sizeof(*seedp));
memcpy(heightbits,vopret.data(),vopret.size());
return((int32_t)(vopret.size()/sizeof(uint32_t)));
}
}
}
@@ -1590,7 +1616,7 @@ uint32_t komodo_pricenew(char *maxflagp,uint32_t price,uint32_t refprice,int64_t
lowprice--;
if ( price >= highprice )
{
fprintf(stderr,"high %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance);
//fprintf(stderr,"high %u vs h%llu l%llu tolerance.%llu\n",price,(long long)highprice,(long long)lowprice,(long long)tolerance);
if ( price > highprice ) // return non-zero only if we violate the tolerance
{
*maxflagp = 2;
@@ -1629,7 +1655,7 @@ int32_t komodo_pricecmp(int32_t nHeight,int32_t n,char *maxflags,uint32_t *price
// komodo_priceclamp() clamps any price that is beyond tolerance
int32_t komodo_priceclamp(int32_t n,uint32_t *pricebits,uint32_t *refprices,int64_t tolerance)
{
int32_t i; uint32_t newprice; char maxflags[2048];
int32_t i; uint32_t newprice; char maxflags[KOMODO_MAXPRICES];
memset(maxflags,0,sizeof(maxflags));
for (i=1; i<n; i++)
{
@@ -1645,7 +1671,7 @@ int32_t komodo_priceclamp(int32_t n,uint32_t *pricebits,uint32_t *refprices,int6
// komodo_mineropret() returns a valid pricedata to add to the coinbase opreturn for nHeight
CScript komodo_mineropret(int32_t nHeight)
{
CScript opret; char maxflags[2048]; uint32_t pricebits[2048],prevbits[2048]; int32_t maxflag,i,n,numzero=0;
CScript opret; char maxflags[KOMODO_MAXPRICES]; uint32_t pricebits[KOMODO_MAXPRICES],prevbits[KOMODO_MAXPRICES]; int32_t maxflag,i,n,numzero=0;
if ( Mineropret.size() >= PRICES_SIZEBIT0 )
{
n = (int32_t)(Mineropret.size() / sizeof(uint32_t));
@@ -1655,11 +1681,18 @@ CScript komodo_mineropret(int32_t nHeight)
memcpy(pricebits,Mineropret.data(),Mineropret.size());
for (i=numzero=0; i<n; i++)
if ( pricebits[i] == 0 )
{
fprintf(stderr,"%d ",i);
numzero++;
}
if ( numzero != 0 )
fprintf(stderr,"numzero.%d\n",numzero);
{
fprintf(stderr," komodo_mineropret numzero.%d vs n.%d\n",numzero,n);
komodo_cbopretupdate(1);
sleep(61);
}
}
if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 )
if ( komodo_heightpricebits(0,prevbits,nHeight-1) > 0 )
{
memcpy(pricebits,Mineropret.data(),Mineropret.size());
memset(maxflags,0,sizeof(maxflags));
@@ -1667,7 +1700,7 @@ CScript komodo_mineropret(int32_t nHeight)
{
// if the new prices are outside tolerance, update Mineropret with clamped prices
komodo_priceclamp(n,pricebits,prevbits,PRICES_MAXCHANGE);
fprintf(stderr,"update Mineropret to clamped prices\n");
//fprintf(stderr,"update Mineropret to clamped prices\n");
memcpy(Mineropret.data(),pricebits,Mineropret.size());
}
}
@@ -1687,18 +1720,16 @@ CScript komodo_mineropret(int32_t nHeight)
The only way komodo_opretvalidate() doesnt return an error is if maxflag is set or it is within tolerance of both the prior block and the local data. The local data validation only happens if it is a recent block and not a block from the past as the local node is only getting the current price data.
*/
// reconsiderblock 002aca768b09dfcf36bd934ab34b23983148b116e12cb0b6e1a3f895d1db63aa
// for PRICES: reconsiderblock 002aca768b09dfcf36bd934ab34b23983148b116e12cb0b6e1a3f895d1db63aa
// and
// reconsiderblock 0034cf582018eacc0b4ae001491ce460113514cb1a3f217567ef4a2207de361a
// reconsiderbloc 000abf51c023b64af327c50c1b060797b8cb281c696d30ab92fd002a8b8c9aea
// are needed to sync past initial blocks with different data set
// pass in blockhash and nTime, latch if it is rejected due to local price, then if localprice changes in a way that would validate then issue reconsiderblock
// add rpc call for extracting rawprices
int32_t komodo_opretvalidate(const CBlock *block,CBlockIndex * const previndex,int32_t nHeight,CScript scriptPubKey)
{
int32_t testchain_exemption = 350;
std::vector<uint8_t> vopret; char maxflags[2048]; double btcusd,btcgbp,btceur; uint32_t localbits[2048],pricebits[2048],prevbits[2048],newprice; int32_t i,prevtime,maxflag,lag,lag2,lag3,n; uint32_t now = (uint32_t)time(NULL);
int32_t testchain_exemption = 0;
std::vector<uint8_t> vopret; char maxflags[KOMODO_MAXPRICES]; double btcusd,btcgbp,btceur; uint32_t localbits[KOMODO_MAXPRICES],pricebits[KOMODO_MAXPRICES],prevbits[KOMODO_MAXPRICES],newprice; int32_t i,j,prevtime,maxflag,lag,lag2,lag3,n,errflag,iter; uint32_t now = (uint32_t)time(NULL);
if ( ASSETCHAINS_CBOPRET != 0 && nHeight > 0 )
{
GetOpReturnData(scriptPubKey,vopret);
@@ -1718,7 +1749,7 @@ int32_t komodo_opretvalidate(const CBlock *block,CBlockIndex * const previndex,i
fprintf(stderr,"A ht.%d now.%u htstamp.%u %u - pricebits[0] %u -> lags.%d %d %d\n",nHeight,now,prevtime,block->nTime,pricebits[0],lag,lag2,lag3);
return(-1);
}
if ( lag2 < -ASSETCHAINS_BLOCKTIME ) // must be close to last block timestamp
if ( lag2 < -60 ) //testchain_exemption ) // must be close to last block timestamp
{
fprintf(stderr,"B ht.%d now.%u htstamp.%u %u - pricebits[0] %u -> lags.%d %d %d vs %d cmp.%d\n",nHeight,now,prevtime,block->nTime,pricebits[0],lag,lag2,lag3,ASSETCHAINS_BLOCKTIME,lag2<-ASSETCHAINS_BLOCKTIME);
if ( nHeight > testchain_exemption )
@@ -1734,7 +1765,7 @@ int32_t komodo_opretvalidate(const CBlock *block,CBlockIndex * const previndex,i
btcgbp = (double)pricebits[2]/10000;
btceur = (double)pricebits[3]/10000;
fprintf(stderr,"ht.%d: lag.%d %.4f USD, %.4f GBP, %.4f EUR, GBPUSD %.6f, EURUSD %.6f, EURGBP %.6f [%d]\n",nHeight,lag,btcusd,btcgbp,btceur,btcusd/btcgbp,btcusd/btceur,btcgbp/btceur,lag2);
if ( komodo_heightpricebits(prevbits,nHeight-1) == 0 )
if ( komodo_heightpricebits(0,prevbits,nHeight-1) > 0 )
{
if ( nHeight < testchain_exemption )
{
@@ -1764,16 +1795,51 @@ int32_t komodo_opretvalidate(const CBlock *block,CBlockIndex * const previndex,i
if ( localbits[i] == 0 )
localbits[i] = prevbits[i];
}
for (i=1; i<n; i++)
for (iter=0; iter<2; iter++) // first iter should just refresh prices if out of tolerance
{
if ( (maxflag= maxflags[i]) != 0 )
for (i=1; i<n; i++)
{
// make sure local price is moving in right direction
fprintf(stderr,"maxflag.%d i.%d localbits.%u vs pricebits.%u prevbits.%u\n",maxflag,i,localbits[i],pricebits[i],prevbits[i]);
if ( maxflag > 0 && localbits[i] < prevbits[i] )
return(-1);
else if ( maxflag < 0 && localbits[i] > prevbits[i] )
return(-1);
if ( (maxflag= maxflags[i]) != 0 && localbits[i] != 0 )
{
// make sure local price is moving in right direction
fprintf(stderr,"maxflag.%d i.%d localbits.%u vs pricebits.%u prevbits.%u\n",maxflag,i,localbits[i],pricebits[i],prevbits[i]);
if ( maxflag > 0 && localbits[i] < prevbits[i] )
{
if ( iter == 0 )
break;
// second iteration checks recent prices to see if within local volatility
for (j=0; j<KOMODO_LOCALPRICE_CACHESIZE; j++)
if ( PriceCache[j][i] >= prevbits[i] )
{
fprintf(stderr,"i.%d within recent localprices[%d] %u >= %u\n",i,j,PriceCache[j][i],prevbits[i]);
break;
}
if ( j == KOMODO_LOCALPRICE_CACHESIZE )
break;
}
else if ( maxflag < 0 && localbits[i] > prevbits[i] )
{
if ( iter == 0 )
break;
for (j=0; j<KOMODO_LOCALPRICE_CACHESIZE; j++)
if ( PriceCache[j][i] <= prevbits[i] )
{
fprintf(stderr,"i.%d within recent localprices[%d] %u <= prev %u\n",i,j,PriceCache[j][i],prevbits[i]);
break;
}
if ( j == KOMODO_LOCALPRICE_CACHESIZE )
break;
}
}
}
if ( i != n )
{
if ( iter == 0 )
{
fprintf(stderr,"force update prices\n");
komodo_cbopretupdate(1);
memcpy(localbits,Mineropret.data(),Mineropret.size());
} else return(-1);
}
}
}
@@ -1882,13 +1948,6 @@ cJSON *send_curl(char *url,char *fname)
// get_urljson just returns the JSON returned by the URL using issue_curl
#define issue_curl(cmdstr) bitcoind_RPC(0,(char *)"CBCOINBASE",cmdstr,0,0,0)
const char *Cryptos[] = { "KMD", "ETH", "LTC", "BCHABC", "XMR", "IOTA", "DASH", "XEM", "ZEC", "WAVES", "RVN", "LSK", "DCR", "BTS", "ICX", "HOT", "STEEM", "ENJ", "STRAT" };
const char *Forex[] =
{ "BGN","NZD","ILS","RUB","CAD","PHP","CHF","AUD","JPY","TRY","HKD","MYR","HRK","CZK","IDR","DKK","NOK","HUF","GBP","MXN","THB","ISK","ZAR","BRL","SGD","PLN","INR","KRW","RON","CNY","SEK","EUR"
};
/*
const char *Techstocks[] =
@@ -1965,14 +2024,17 @@ uint32_t get_binanceprice(const char *symbol)
return(price);
}
int32_t get_cryptoprices(uint32_t *prices,const char *list[],int32_t n)
int32_t get_cryptoprices(uint32_t *prices,const char *list[],int32_t n,std::vector<std::string> strvec)
{
int32_t i,errs=0; uint32_t price;
for (i=0; i<n; i++)
int32_t i,errs=0; uint32_t price; char *symbol;
for (i=0; i<n+strvec.size(); i++)
{
if ( (price= get_binanceprice(list[i])) == 0 )
if ( i < n )
symbol = (char *)list[i];
else symbol = (char *)strvec[i - n].c_str();
if ( (price= get_binanceprice(symbol)) == 0 )
errs++;
fprintf(stderr,"(%s %.8f) ",list[i],(double)price/SATOSHIDEN);
fprintf(stderr,"(%s %.8f) ",symbol,(double)price/SATOSHIDEN);
prices[i] = price;
}
fprintf(stderr," errs.%d\n",errs);
@@ -2043,53 +2105,90 @@ int32_t get_btcusd(uint32_t pricebits[4])
// komodo_cbopretupdate() obtains the external price data and encodes it into Mineropret, which will then be used by the miner and validation
// save history, use new data to approve past rejection, where is the auto-reconsiderblock?
// 51% correlation, smoothing
void komodo_cbopretupdate()
int32_t komodo_cbopretsize(uint64_t flags)
{
static uint32_t lasttime,lastcrypto,lastbtc;
static uint32_t pricebits[4],cryptoprices[sizeof(Cryptos)/sizeof(*Cryptos)],forexprices[sizeof(Forex)/sizeof(*Forex)];
int32_t size; uint32_t now = (uint32_t)time(NULL);
int32_t size = 0;
if ( (ASSETCHAINS_CBOPRET & 1) != 0 )
{
if ( komodo_nextheight() > 333 )
ASSETCHAINS_CBOPRET = 7;
size = PRICES_SIZEBIT0;
if ( (ASSETCHAINS_CBOPRET & 2) != 0 )
size += sizeof(forexprices);
size += (sizeof(Forex)/sizeof(*Forex)) * sizeof(uint32_t);
if ( (ASSETCHAINS_CBOPRET & 4) != 0 )
size += sizeof(cryptoprices);
size += (sizeof(Cryptos)/sizeof(*Cryptos) + ASSETCHAINS_PRICES.size())*sizeof(uint32_t);
}
return(size);
}
void komodo_cbopretupdate(int32_t forceflag)
{
static uint32_t lasttime,lastcrypto,lastbtc,pending;
static uint32_t pricebits[4],cryptoprices[KOMODO_MAXPRICES],forexprices[sizeof(Forex)/sizeof(*Forex)];
int32_t size; uint32_t flags=0,now;
if ( forceflag != 0 && pending != 0 )
{
while ( pending != 0 )
fprintf(stderr,"pricewait "), sleep(1);
return;
}
pending = 1;
now = (uint32_t)time(NULL);
if ( (ASSETCHAINS_CBOPRET & 1) != 0 )
{
//if ( komodo_nextheight() > 333 ) // for debug only!
// ASSETCHAINS_CBOPRET = 7;
size = komodo_cbopretsize(ASSETCHAINS_CBOPRET);
if ( Mineropret.size() < size )
Mineropret.resize(size);
size = PRICES_SIZEBIT0;
if ( now > lastbtc+120 && get_btcusd(pricebits) == 0 )
if ( (forceflag != 0 || now > lastbtc+120) && get_btcusd(pricebits) == 0 )
{
memcpy(Mineropret.data(),pricebits,PRICES_SIZEBIT0);
lastbtc = (uint32_t)time(NULL);
if ( flags == 0 )
komodo_PriceCache_shift();
memcpy(PriceCache[0],pricebits,PRICES_SIZEBIT0);
flags |= 1;
}
if ( (ASSETCHAINS_CBOPRET & 2) != 0 )
{
if ( now > lasttime+3600*5 || forexprices[0] == 0 )
if ( now > lasttime+3600*5 || forexprices[0] == 0 ) // cant assume timestamp is valid for forex price as it is a daily weekday changing thing anyway.
{
get_dailyfx(forexprices);
memcpy(&Mineropret.data()[size],forexprices,sizeof(forexprices));
lasttime = (uint32_t)time(NULL);
if ( flags == 0 )
komodo_PriceCache_shift();
flags |= 2;
memcpy(&PriceCache[0][size/sizeof(uint32_t)],forexprices,sizeof(forexprices));
}
size += sizeof(forexprices);
size += (sizeof(Forex)/sizeof(*Forex)) * sizeof(uint32_t);
}
if ( (ASSETCHAINS_CBOPRET & 4) != 0 )
{
if ( now > lastcrypto+100 )
if ( forceflag != 0 || flags != 0 )
{
get_cryptoprices(cryptoprices,Cryptos,(int32_t)(sizeof(Cryptos)/sizeof(*Cryptos)));
memcpy(&Mineropret.data()[size],cryptoprices,sizeof(cryptoprices));
lastcrypto = (uint32_t)time(NULL);
get_cryptoprices(cryptoprices,Cryptos,(int32_t)(sizeof(Cryptos)/sizeof(*Cryptos)),ASSETCHAINS_PRICES);
if ( flags == 0 )
komodo_PriceCache_shift();
memcpy(&PriceCache[0][size/sizeof(uint32_t)],cryptoprices,(sizeof(Cryptos)/sizeof(*Cryptos)+ASSETCHAINS_PRICES.size()) * sizeof(uint32_t));
flags |= 4; // very rarely we can see flags == 6 case
}
size += sizeof(cryptoprices);
size += (sizeof(Cryptos)/sizeof(*Cryptos)+ASSETCHAINS_PRICES.size()) * sizeof(uint32_t);
}
if ( flags != 0 )
{
now = (uint32_t)time(NULL);
if ( (flags & 1) != 0 )
lastbtc = now;
if ( (flags & 2) != 0 )
lasttime = now;
if ( (flags & 4) != 0 )
lastcrypto = now;
memcpy(Mineropret.data(),PriceCache[0],size);
// high volatility still strands nodes so we need to check new prices to approve a stuck block
// scan list of stuck blocks (one?) and auto reconsiderblock if it changed state
//int32_t i; for (i=0; i<Mineropret.size(); i++)
// fprintf(stderr,"%02x",Mineropret[i]);
//fprintf(stderr," <- set Mineropret[%d] size.%d %ld\n",(int32_t)Mineropret.size(),size,sizeof(PriceCache[0]));
}
//int32_t i; for (i=0; i<Mineropret.size(); i++)
// fprintf(stderr,"%02x",Mineropret[i]);
//fprintf(stderr," <- set Mineropret[%d]\n",(int32_t)Mineropret.size());
/*
if ( (ASSETCHAINS_CBOPRET & 4) != 0 )
{
@@ -2104,4 +2203,290 @@ void komodo_cbopretupdate()
get_stocks(Techstocks,(int32_t)(sizeof(Techstocks)/sizeof(*Techstocks)));
}*/
}
pending = 0;
}
int64_t komodo_pricemult(int32_t ind)
{
int32_t i,j;
if ( (ASSETCHAINS_CBOPRET & 1) != 0 && ind < KOMODO_MAXPRICES )
{
if ( PriceMult[0] == 0 )
{
for (i=0; i<4; i++)
PriceMult[i] = 10000;
if ( (ASSETCHAINS_CBOPRET & 2) != 0 )
{
for (j=0; j<sizeof(Forex)/sizeof(*Forex); j++)
PriceMult[i++] = 10000;
}
if ( (ASSETCHAINS_CBOPRET & 4) != 0 )
{
for (j=0; j<sizeof(Cryptos)/sizeof(*Cryptos)+ASSETCHAINS_PRICES.size(); j++)
PriceMult[i++] = 1;
}
}
return(PriceMult[ind]);
}
return(0);
}
char *komodo_pricename(char *name,int32_t ind)
{
strcpy(name,"error");
if ( (ASSETCHAINS_CBOPRET & 1) != 0 && ind < KOMODO_MAXPRICES )
{
if ( ind < 4 )
{
switch ( ind )
{
case 0: strcpy(name,"timestamp"); break;
case 1: strcpy(name,"BTCUSD"); break;
case 2: strcpy(name,"BTCGBP"); break;
case 3: strcpy(name,"BTCEUR"); break;
default: return(0); break;
}
return(name);
}
else
{
ind -= 4;
if ( (ASSETCHAINS_CBOPRET & 2) != 0 )
{
if ( ind < 0 )
return(0);
if ( ind < sizeof(Forex)/sizeof(*Forex) )
{
name[0] = 'U', name[1] = 'S', name[2] = 'D';
strcpy(name+3,Forex[ind]);
return(name);
} else ind -= sizeof(Forex)/sizeof(*Forex);
}
if ( (ASSETCHAINS_CBOPRET & 4) != 0 )
{
if ( ind < 0 )
return(0);
if ( ind < sizeof(Cryptos)/sizeof(*Cryptos) + ASSETCHAINS_PRICES.size() )
{
if ( ind < sizeof(Cryptos)/sizeof(*Cryptos) )
strcpy(name,Cryptos[ind]);
else
{
ind -= (sizeof(Cryptos)/sizeof(*Cryptos));
strcpy(name,ASSETCHAINS_PRICES[ind].c_str());
}
strcat(name,"BTC");
return(name);
} else ind -= (sizeof(Cryptos)/sizeof(*Cryptos) + ASSETCHAINS_PRICES.size());
}
}
}
return(0);
}
int32_t komodo_priceind(char *symbol)
{
char name[65]; int32_t i,n = (int32_t)(komodo_cbopretsize(ASSETCHAINS_CBOPRET) / sizeof(uint32_t));
for (i=1; i<n; i++)
{
komodo_pricename(name,i);
if ( strcmp(name,symbol) == 0 )
return(i);
}
return(-1);
}
int64_t komodo_pricecorrelated(uint64_t seed,int32_t ind,uint32_t *rawprices,int32_t rawskip,uint32_t *nonzprices,int32_t smoothwidth)
{
int32_t i,j,k,n,iter,correlation,maxcorrelation=0; int64_t firstprice,price,sum,den,mult,refprice,lowprice,highprice;
if ( PRICES_DAYWINDOW < 2 || ind >= KOMODO_MAXPRICES )
return(-1);
mult = PriceMult[ind];
if ( nonzprices != 0 )
memset(nonzprices,0,sizeof(*nonzprices)*PRICES_DAYWINDOW);
for (iter=0; iter<PRICES_DAYWINDOW; iter++)
{
correlation = 0;
i = (iter + seed) % PRICES_DAYWINDOW;
refprice = rawprices[i*rawskip];
highprice = (refprice * (COIN + PRICES_MAXCHANGE*5)) / COIN;
lowprice = (refprice * (COIN - PRICES_MAXCHANGE*5)) / COIN;
if ( highprice == refprice )
highprice++;
if ( lowprice == refprice )
lowprice--;
sum = 0;
//fprintf(stderr,"firsti.%d: ",i);
for (j=0; j<PRICES_DAYWINDOW; j++,i++)
{
if ( i >= PRICES_DAYWINDOW )
i = 0;
if ( (price= rawprices[i*rawskip]) == 0 )
{
fprintf(stderr,"null rawprice.[%d]\n",i);
return(-1);
}
if ( price >= lowprice && price <= highprice )
{
//fprintf(stderr,"%.1f ",(double)price/10000);
sum += price;
correlation++;
if ( correlation > (PRICES_DAYWINDOW>>1) )
{
if ( nonzprices == 0 )
return(refprice * mult);
//fprintf(stderr,"-> %.4f\n",(double)sum*mult/correlation);
//return(sum*mult/correlation);
n = 0;
i = (iter + seed) % PRICES_DAYWINDOW;
for (k=0; k<PRICES_DAYWINDOW; k++,i++)
{
if ( i >= PRICES_DAYWINDOW )
i = 0;
if ( n > (PRICES_DAYWINDOW>>1) )
nonzprices[i] = 0;
else
{
price = rawprices[i*rawskip];
if ( price < lowprice || price > highprice )
nonzprices[i] = 0;
else
{
nonzprices[i] = price;
//fprintf(stderr,"(%d %u) ",i,rawprices[i*rawskip]);
n++;
}
}
}
//fprintf(stderr,"ind.%d iter.%d j.%d i.%d n.%d correlation.%d ref %llu -> %llu\n",ind,iter,j,i,n,correlation,(long long)refprice,(long long)sum/correlation);
if ( n != correlation )
return(-1);
sum = den = n = 0;
for (i=0; i<PRICES_DAYWINDOW; i++)
if ( nonzprices[i] != 0 )
break;
firstprice = nonzprices[i];
//fprintf(stderr,"firsti.%d: ",i);
for (i=0; i<PRICES_DAYWINDOW; i++)
{
if ( (price= nonzprices[i]) != 0 )
{
den += (PRICES_DAYWINDOW - i);
sum += ((PRICES_DAYWINDOW - i) * (price + firstprice*4)) / 5;
n++;
}
}
if ( n != correlation || sum == 0 || den == 0 )
{
fprintf(stderr,"seed.%llu n.%d vs correlation.%d sum %llu, den %llu\n",(long long)seed,n,correlation,(long long)sum,(long long)den);
return(-1);
}
//fprintf(stderr,"firstprice.%llu weighted -> %.8f\n",(long long)firstprice,((double)(sum*mult) / den) / COIN);
return((sum * mult) / den);
}
}
}
if ( correlation > maxcorrelation )
maxcorrelation = correlation;
}
fprintf(stderr,"ind.%d iter.%d maxcorrelation.%d ref.%llu high.%llu low.%llu\n",ind,iter,maxcorrelation,(long long)refprice,(long long)highprice,(long long)lowprice);
return(0);
}
int64_t _pairave64(int64_t valA,int64_t valB)
{
if ( valA != 0 && valB != 0 )
return((valA + valB) / 2);
else if ( valA != 0 ) return(valA);
else return(valB);
}
int64_t _pairdiff64(register int64_t valA,register int64_t valB)
{
if ( valA != 0 && valB != 0 )
return(valA - valB);
else return(0);
}
int64_t balanced_ave64(int64_t buf[],int32_t i,int32_t width)
{
register int32_t nonz,j; register int64_t sum,price;
nonz = 0;
sum = 0;
for (j=-width; j<=width; j++)
{
price = buf[i + j];
if ( price != 0 )
{
sum += price;
nonz++;
}
}
if ( nonz != 0 )
sum /= nonz;
return(sum);
}
void buf_trioave64(int64_t dest[],int64_t src[],int32_t n)
{
register int32_t i,j,width = 3;
for (i=0; i<128; i++)
src[i] = 0;
//for (i=n-width-1; i>width; i--)
// dest[i] = balanced_ave(src,i,width);
//for (i=width; i>0; i--)
// dest[i] = balanced_ave(src,i,i);
for (i=1; i<width; i++)
dest[i] = balanced_ave64(src,i,i);
for (i=width; i<n-width; i++)
dest[i] = balanced_ave64(src,i,width);
dest[0] = _pairave64(dest[0],dest[1] - _pairdiff64(dest[2],dest[1]));
j = width-1;
for (i=n-width; i<n-1; i++,j--)
dest[i] = balanced_ave64(src,i,j);
if ( dest[n-3] != 0. && dest[n-2] != 0. )
dest[n-1] = ((2 * dest[n-2]) - dest[n-3]);
else dest[n-1] = 0;
}
void smooth64(int64_t dest[],int64_t src[],int32_t width,int32_t smoothiters)
{
int64_t smoothbufA[1024],smoothbufB[1024]; int32_t i;
if ( width < sizeof(smoothbufA)/sizeof(*smoothbufA) )
{
buf_trioave64(smoothbufA,src,width);
for (i=0; i<smoothiters; i++)
{
buf_trioave64(smoothbufB,smoothbufA,width);
buf_trioave64(smoothbufA,smoothbufB,width);
}
buf_trioave64(dest,smoothbufA,width);
} else memcpy(dest,src,width*sizeof(*dest));
}
int64_t komodo_pricesmoothed(int64_t *correlated,int32_t cskip,int64_t *rawprices,int32_t numprices)
{
//const int64_t coeffs[7] = { -2, 0, 18, 32, 18, 0, -2 };
int32_t i; int64_t sum=0,nonzprice,price;
if ( PRICES_DAYWINDOW < 2 )
return(0);
for (i=0; i<PRICES_DAYWINDOW; i++)
{
if ( (nonzprice= correlated[i*cskip]) != 0 )
break;
}
if ( nonzprice == 0 )
return(-1);
for (i=0; i<PRICES_DAYWINDOW; i++)
{
if ( (price= correlated[i*cskip]) != 0 )
nonzprice = price;
//correlated2[i] = nonzprice / PRICES_DAYWINDOW; // reduce precision
sum += nonzprice;
}
price = sum / PRICES_DAYWINDOW;
// improve smoothing with correlated2 processing
// price = smooth(correlated2,PRICES_DAYWINDOW,price/daywindow) * PRICES_DAYWINDOW;
return(price);
}

View File

@@ -72,6 +72,7 @@ uint64_t ASSETCHAINS_TIMEUNLOCKFROM = 0, ASSETCHAINS_TIMEUNLOCKTO = 0,ASSETCHAIN
uint64_t ASSETCHAINS_LASTERA = 1;
uint64_t ASSETCHAINS_ENDSUBSIDY[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_HALVING[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_DECAY[ASSETCHAINS_MAX_ERAS],ASSETCHAINS_NOTARY_PAY[ASSETCHAINS_MAX_ERAS];
uint8_t ASSETCHAINS_CCDISABLES[256];
std::vector<std::string> ASSETCHAINS_PRICES;
#define _ASSETCHAINS_EQUIHASH 0
uint32_t ASSETCHAINS_NUMALGOS = 3;

View File

@@ -1664,12 +1664,13 @@ uint64_t komodo_ac_block_subsidy(int nHeight)
}
extern int64_t MAX_MONEY;
void komodo_cbopretupdate();
void komodo_cbopretupdate(int32_t forceflag);
void SplitStr(const std::string& strVal, std::vector<std::string> &outVals);
void komodo_args(char *argv0)
{
extern const char *Notaries_elected1[][2];
std::string name,addn,hexstr; char *dirname,fname[512],arg0str[64],magicstr[9]; uint8_t magic[4],extrabuf[8192],disablebits[32],*extraptr=0; FILE *fp; uint64_t val; uint16_t port; int32_t i,nonz=0,baseid,len,n,extralen = 0; uint64_t ccenables[256];
std::string name,addn,hexstr,symbol; char *dirname,fname[512],arg0str[64],magicstr[9]; uint8_t magic[4],extrabuf[8192],disablebits[32],*extraptr=0; FILE *fp; uint64_t val; uint16_t port; int32_t i,nonz=0,baseid,len,n,extralen = 0; uint64_t ccenables[256];
IS_KOMODO_NOTARY = GetBoolArg("-notary", false);
IS_STAKED_NOTARY = GetArg("-stakednotary", -1);
if ( IS_STAKED_NOTARY != -1 && IS_KOMODO_NOTARY == true ) {
@@ -1734,7 +1735,7 @@ void komodo_args(char *argv0)
{
printf("KOMODO_REWIND %d\n",KOMODO_REWIND);
}
if ( name.c_str()[0] != 0 )
if ( name.c_str()[0] != 0 )
{
std::string selectedAlgo = GetArg("-ac_algo", std::string(ASSETCHAINS_ALGORITHMS[0]));
@@ -1812,6 +1813,13 @@ void komodo_args(char *argv0)
ASSETCHAINS_CODAPORT = GetArg("-ac_coda",0);
ASSETCHAINS_MARMARA = GetArg("-ac_marmara",0);
ASSETCHAINS_CBOPRET = GetArg("-ac_cbopret",0);
if ( ASSETCHAINS_CBOPRET != 0 )
{
SplitStr(GetArg("-ac_prices",""), ASSETCHAINS_PRICES);
for (i=0; i<ASSETCHAINS_PRICES.size(); i++)
fprintf(stderr,"%s ",ASSETCHAINS_PRICES[i].c_str());
fprintf(stderr,"%d -ac_prices\n",(int32_t)ASSETCHAINS_PRICES.size());
}
hexstr = GetArg("-ac_mineropret","");
if ( hexstr.size() != 0 )
{
@@ -2067,7 +2075,16 @@ void komodo_args(char *argv0)
if ( ASSETCHAINS_CBOPRET != 0 )
{
extralen += iguana_rwnum(1,&extraptr[extralen],sizeof(ASSETCHAINS_CBOPRET),(void *)&ASSETCHAINS_CBOPRET);
komodo_cbopretupdate(); // will set Mineropret
if ( ASSETCHAINS_PRICES.size() != 0 )
{
for (i=0; i<ASSETCHAINS_PRICES.size(); i++)
{
symbol = ASSETCHAINS_PRICES[i];
memcpy(&extraptr[extralen],(char *)symbol.c_str(),symbol.size());
extralen += symbol.size();
}
}
komodo_cbopretupdate(1); // will set Mineropret
fprintf(stderr,"This blockchain uses data produced from CoinDesk Bitcoin Price Index\n");
}
}

View File

@@ -1174,38 +1174,161 @@ UniValue paxprice(const UniValue& params, bool fHelp)
return ret;
}
UniValue paxprices(const UniValue& params, bool fHelp)
int32_t komodo_heightpricebits(uint64_t *seedp,uint32_t *heightbits,int32_t nHeight);
char *komodo_pricename(char *name,int32_t ind);
int64_t komodo_pricesmoothed(int64_t *correlated,int32_t cskip,int64_t *correlated2,int32_t numprices);
int64_t komodo_pricecorrelated(uint64_t seed,int32_t ind,uint32_t *rawprices,int32_t rawskip,uint32_t *nonzprices,int32_t smoothwidth);
int32_t komodo_nextheight();
uint32_t komodo_heightstamp(int32_t height);
int64_t komodo_pricemult(int32_t ind);
#define PRICES_SMOOTHWIDTH 1
int32_t prices_extract(int64_t *pricedata,int32_t firstheight,int32_t numblocks,int32_t ind)
{
if ( fHelp || params.size() != 3 )
throw runtime_error("paxprices \"base\" \"rel\" maxsamples\n");
int32_t height,i,n,width,numpricefeeds = -1; uint64_t seed,ignore,rngval; int64_t *correlated2; uint32_t rawprices[1440*6],*ptr;
//daywindow = (3600*24/ASSETCHAINS_BLOCKTIME) + 1;
//pricedata = (uint32_t *)calloc(sizeof(*prices)*3,numblocks + daywindow*2 + PRICES_SMOOTHWIDTH);
width = numblocks+PRICES_DAYWINDOW*2+PRICES_SMOOTHWIDTH;
komodo_heightpricebits(&seed,rawprices,firstheight + numblocks - 1);
if ( firstheight < width )
return(-1);
for (i=0; i<width; i++)
{
if ( (n= komodo_heightpricebits(&ignore,rawprices,firstheight + numblocks - 1 - i)) < 0 )
return(-1);
if ( numpricefeeds < 0 )
numpricefeeds = n;
if ( n != numpricefeeds )
return(-2);
ptr = (uint32_t *)&pricedata[i*3];
ptr[0] = rawprices[ind];
ptr[1] = rawprices[0]; // timestamp
}
rngval = seed;
correlated2 = (int64_t *)calloc(sizeof(*correlated2),width);
for (i=0; i<numblocks+PRICES_DAYWINDOW+PRICES_SMOOTHWIDTH; i++)
{
rngval = (rngval*11109 + 13849);
ptr = (uint32_t *)&pricedata[i*3];
correlated2[i] = ptr[0];
if ( (pricedata[i*3+1]= komodo_pricecorrelated(rngval,ind,(uint32_t *)&pricedata[i*3],6,0,PRICES_SMOOTHWIDTH)) < 0 )
{
free(correlated2);
return(-3);
}
}
for (i=0; i<numblocks; i++)
pricedata[i*3+2] = komodo_pricesmoothed(&pricedata[i*3+1],3,correlated2,numblocks+PRICES_DAYWINDOW+PRICES_SMOOTHWIDTH);
return(0);
}
UniValue prices(const UniValue& params, bool fHelp)
{
if ( fHelp || params.size() != 1 )
throw runtime_error("prices maxsamples\n");
LOCK(cs_main);
UniValue ret(UniValue::VOBJ); uint64_t relvolume,prices[4096]; uint32_t i,n; int32_t heights[sizeof(prices)/sizeof(*prices)];
std::string base = params[0].get_str();
std::string rel = params[1].get_str();
int32_t maxsamples = atoi(params[2].get_str().c_str());
UniValue ret(UniValue::VOBJ); uint64_t seed,rngval; int64_t smoothed,*correlated,*correlated2; char name[64],*str; uint32_t rawprices[1440*6],*prices; uint32_t i,width,j,numpricefeeds=-1,n,numsamples,nextheight,offset,ht;
if ( ASSETCHAINS_CBOPRET == 0 )
throw JSONRPCError(RPC_INVALID_PARAMETER, "only -ac_cbopret chains have prices");
int32_t maxsamples = atoi(params[0].get_str().c_str());
if ( maxsamples < 1 )
maxsamples = 1;
else if ( maxsamples > sizeof(heights)/sizeof(*heights) )
maxsamples = sizeof(heights)/sizeof(*heights);
ret.push_back(Pair("base", base));
ret.push_back(Pair("rel", rel));
n = komodo_paxprices(heights,prices,maxsamples,(char *)base.c_str(),(char *)rel.c_str());
nextheight = komodo_nextheight();
UniValue a(UniValue::VARR);
for (i=0; i<n; i++)
if ( PRICES_DAYWINDOW < 7 )
throw JSONRPCError(RPC_INVALID_PARAMETER, "daywindow is too small");
width = maxsamples+2*PRICES_DAYWINDOW+PRICES_SMOOTHWIDTH;
numpricefeeds = komodo_heightpricebits(&seed,rawprices,nextheight-1);
if ( numpricefeeds <= 0 )
throw JSONRPCError(RPC_INVALID_PARAMETER, "illegal numpricefeeds");
prices = (uint32_t *)calloc(sizeof(*prices),width*numpricefeeds);
correlated = (int64_t *)calloc(sizeof(*correlated),width);
correlated2 = (int64_t *)calloc(sizeof(*correlated2),width);
//prices2 = (uint32_t *)calloc(sizeof(*prices2),width);
i = 0;
for (ht=nextheight-1,i=0; i<width&&ht>2; i++,ht--)
{
UniValue item(UniValue::VOBJ);
if ( heights[i] < 0 || heights[i] > chainActive.Height() )
if ( ht < 0 || ht > chainActive.Height() )
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
else
{
CBlockIndex *pblockindex = chainActive[heights[i]];
item.push_back(Pair("t", (int64_t)pblockindex->nTime));
item.push_back(Pair("p", (double)prices[i] / COIN));
a.push_back(item);
if ( (n= komodo_heightpricebits(0,rawprices,ht)) > 0 )
{
if ( n != numpricefeeds )
throw JSONRPCError(RPC_INVALID_PARAMETER, "numprices != first numprices");
else
{
for (j=0; j<numpricefeeds; j++)
prices[j*width + i] = rawprices[j];
}
} else throw JSONRPCError(RPC_INVALID_PARAMETER, "no komodo_rawprices found");
}
}
ret.push_back(Pair("array", a));
numsamples = i;
ret.push_back(Pair("firstheight", (int64_t)nextheight-1-i));
UniValue timestamps(UniValue::VARR);
for (i=0; i<maxsamples; i++)
timestamps.push_back((int64_t)prices[i]);
ret.push_back(Pair("timestamps",timestamps));
rngval = seed;
//for (i=0; i<PRICES_DAYWINDOW; i++)
// fprintf(stderr,"%.4f ",(double)prices[width+i]/10000);
//fprintf(stderr," maxsamples.%d\n",maxsamples);
for (j=1; j<numpricefeeds; j++)
{
UniValue item(UniValue::VOBJ),p(UniValue::VARR);
if ( (str= komodo_pricename(name,j)) != 0 )
{
item.push_back(Pair("name",str));
if ( numsamples >= width )
{
for (i=0; i<maxsamples+PRICES_DAYWINDOW+PRICES_SMOOTHWIDTH&&i<numsamples; i++)
{
offset = j*width + i;
rngval = (rngval*11109 + 13849);
correlated2[i] = prices[offset];
if ( (correlated[i]= komodo_pricecorrelated(rngval,j,&prices[offset],1,0,PRICES_SMOOTHWIDTH)) < 0 )
throw JSONRPCError(RPC_INVALID_PARAMETER, "null correlated price");
}
for (i=0; i<maxsamples&&i<numsamples; i++)
{
offset = j*width + i;
smoothed = komodo_pricesmoothed(&correlated[i],1,correlated2,maxsamples+PRICES_DAYWINDOW+PRICES_SMOOTHWIDTH);
UniValue parr(UniValue::VARR);
parr.push_back(ValueFromAmount((int64_t)prices[offset] * komodo_pricemult(j)));
parr.push_back(ValueFromAmount(correlated[i]));
parr.push_back(ValueFromAmount(smoothed));
// compare to alternate method
p.push_back(parr);
}
}
else
{
for (i=0; i<maxsamples&&i<numsamples; i++)
{
offset = j*width + i;
UniValue parr(UniValue::VARR);
parr.push_back(ValueFromAmount((int64_t)prices[offset] * komodo_pricemult(j)));
p.push_back(parr);
}
}
item.push_back(Pair("prices",p));
} else item.push_back(Pair("name","error"));
a.push_back(item);
}
ret.push_back(Pair("pricefeeds",a));
ret.push_back(Pair("result","success"));
ret.push_back(Pair("seed",(int64_t)seed));
ret.push_back(Pair("height",(int64_t)nextheight-1));
ret.push_back(Pair("maxsamples",(int64_t)maxsamples));
ret.push_back(Pair("width",(int64_t)width));
ret.push_back(Pair("daywindow",(int64_t)PRICES_DAYWINDOW));
ret.push_back(Pair("numpricefeeds",(int64_t)numpricefeeds));
free(prices);
//free(prices2);
free(correlated);
free(correlated2);
return ret;
}

View File

@@ -441,14 +441,10 @@ static const CRPCCommand vRPCCommands[] =
{ "oracles", "oraclessamples", &oraclessamples, true },
// Prices
{ "prices", "prices", &prices, true },
{ "prices", "pricesaddress", &pricesaddress, true },
{ "prices", "priceslist", &priceslist, true },
{ "prices", "pricesinfo", &pricesinfo, true },
{ "prices", "pricescreate", &pricescreate, true },
{ "prices", "pricesaddfunding", &pricesaddfunding, true },
{ "prices", "pricesbet", &pricesbet, true },
{ "prices", "pricesstatus", &pricesstatus, true },
{ "prices", "pricesfinish", &pricesfinish, true },
// Pegs
{ "pegs", "pegsaddress", &pegsaddress, true },

View File

@@ -272,11 +272,6 @@ extern UniValue oraclessamples(const UniValue& params, bool fHelp);
extern UniValue pricesaddress(const UniValue& params, bool fHelp);
extern UniValue priceslist(const UniValue& params, bool fHelp);
extern UniValue pricesinfo(const UniValue& params, bool fHelp);
extern UniValue pricescreate(const UniValue& params, bool fHelp);
extern UniValue pricesaddfunding(const UniValue& params, bool fHelp);
extern UniValue pricesbet(const UniValue& params, bool fHelp);
extern UniValue pricesstatus(const UniValue& params, bool fHelp);
extern UniValue pricesfinish(const UniValue& params, bool fHelp);
extern UniValue pegsaddress(const UniValue& params, bool fHelp);
extern UniValue marmaraaddress(const UniValue& params, bool fHelp);
extern UniValue marmara_poolpayout(const UniValue& params, bool fHelp);
@@ -486,6 +481,8 @@ extern UniValue paxprices(const UniValue& params, bool fHelp);
extern UniValue paxdeposit(const UniValue& params, bool fHelp);
extern UniValue paxwithdraw(const UniValue& params, bool fHelp);
extern UniValue prices(const UniValue& params, bool fHelp);
// test rpc:
extern UniValue test_ac(const UniValue& params, bool fHelp);
extern UniValue test_heirmarker(const UniValue& params, bool fHelp);

View File

@@ -438,17 +438,125 @@ bool CBlockTreeDB::ReadAddressIndex(uint160 addressHash, int type,
bool getAddressFromIndex(const int &type, const uint160 &hash, std::string &address);
uint32_t komodo_segid32(char *coinaddr);
#define DECLARE_IGNORELIST std::map <std::string,int> ignoredMap = { \
{"RReUxSs5hGE39ELU23DfydX8riUuzdrHAE", 1}, \
{"RMUF3UDmzWFLSKV82iFbMaqzJpUnrWjcT4", 1}, \
{"RA5imhVyJa7yHhggmBytWuDr923j2P1bxx", 1}, \
{"RBM5LofZFodMeewUzoMWcxedm3L3hYRaWg", 1}, \
{"RAdcko2d94TQUcJhtFHZZjMyWBKEVfgn4J", 1}, \
{"RLzUaZ934k2EFCsAiVjrJqM8uU1vmMRFzk", 1}, \
{"RMSZMWZXv4FhUgWhEo4R3AQXmRDJ6rsGyt", 1}, \
{"RUDrX1v5toCsJMUgtvBmScKjwCB5NaR8py", 1}, \
{"RMSZMWZXv4FhUgWhEo4R3AQXmRDJ6rsGyt", 1}, \
{"RRvwmbkxR5YRzPGL5kMFHMe1AH33MeD8rN", 1}, \
{"RQLQvSgpPAJNPgnpc8MrYsbBhep95nCS8L", 1}, \
{"RK8JtBV78HdvEPvtV5ckeMPSTojZPzHUTe", 1}, \
{"RHVs2KaCTGUMNv3cyWiG1jkEvZjigbCnD2", 1}, \
{"RE3SVaDgdjkRPYA6TRobbthsfCmxQedVgF", 1}, \
{"RW6S5Lw5ZCCvDyq4QV9vVy7jDHfnynr5mn", 1}, \
{"RTkJwAYtdXXhVsS3JXBAJPnKaBfMDEswF8", 1}, \
{"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY", 1} \
};
int32_t CBlockTreeDB::Snapshot2(int64_t dustthreshold,int32_t top,std::vector <std::pair<CAmount, std::string>> &vaddr)
{
int64_t total = 0; int64_t totalAddresses = 0; std::string address;
int64_t utxos = 0; int64_t ignoredAddresses = 0;
DECLARE_IGNORELIST
boost::scoped_ptr<CDBIterator> iter(NewIterator());
std::map <std::string, CAmount> addressAmounts;
for (iter->SeekToLast(); iter->Valid(); iter->Prev())
{
boost::this_thread::interruption_point();
try
{
std::vector<unsigned char> slKey = std::vector<unsigned char>();
pair<char, CAddressIndexIteratorKey> keyObj;
iter->GetKey(keyObj);
char chType = keyObj.first;
CAddressIndexIteratorKey indexKey = keyObj.second;
//fprintf(stderr, "chType=%d\n", chType);
if (chType == DB_ADDRESSUNSPENTINDEX)
{
try {
CAmount nValue;
iter->GetValue(nValue);
getAddressFromIndex(indexKey.type, indexKey.hashBytes, address);
if ( nValue > dustthreshold )
{
std::map <std::string, int>::iterator ignored = ignoredMap.find(address);
if (ignored != ignoredMap.end())
{
fprintf(stderr,"ignoring %s\n", address.c_str());
ignoredAddresses++;
continue;
}
std::map <std::string, CAmount>::iterator pos = addressAmounts.find(address);
if ( pos == addressAmounts.end() )
{
// insert new address + utxo amount
//fprintf(stderr, "inserting new address %s with amount %li\n", address.c_str(), nValue);
addressAmounts[address] = nValue;
totalAddresses++;
}
else
{
// update unspent tally for this address
//fprintf(stderr, "updating address %s with new utxo amount %li\n", address.c_str(), nValue);
addressAmounts[address] += nValue;
}
//fprintf(stderr,"{\"%s\", %.8f},\n",address.c_str(),(double)nValue/COIN);
// total += nValue;
utxos++;
} else fprintf(stderr,"ignoring amount=0 UTXO for %s\n", address.c_str());
}
catch (const std::exception& e)
{
fprintf(stderr, "DONE %s: LevelDB addressindex exception! - %s\n", __func__, e.what());
break;
}
}
}
catch (const std::exception& e)
{
fprintf(stderr, "DONE reading index entries\n");
break;
}
}
fprintf(stderr, "total=%f, totalAddresses=%li, utxos=%li, ignored=%li\n", (double) total / COIN, totalAddresses, utxos, ignoredAddresses);
for (std::pair<std::string, CAmount> element : addressAmounts)
vaddr.push_back( make_pair(element.second, element.first) );
std::sort(vaddr.rbegin(), vaddr.rend());
int topN = 0;
for (std::vector<std::pair<CAmount, std::string>>::iterator it = vaddr.begin(); it!=vaddr.end(); ++it)
{
//obj.push_back( make_pair("addr", it->second.c_str() ) );
//char amount[32];
//sprintf(amount, "%.8f", (double) it->first / COIN);
//obj.push_back( make_pair("amount", amount) );
//obj.push_back( make_pair("segid",(int32_t)komodo_segid32((char *)it->second.c_str()) & 0x3f) );
//addressesSorted.push_back(obj);
total += it->first;
topN++;
// If requested, only show top N addresses in output JSON
if ( top == topN )
break;
}
return(topN);
}
UniValue CBlockTreeDB::Snapshot(int top)
{
int64_t total = 0; int64_t totalAddresses = 0; std::string address;
int64_t utxos = 0; int64_t ignoredAddresses = 0;
DECLARE_IGNORELIST
boost::scoped_ptr<CDBIterator> iter(NewIterator());
std::map <std::string, CAmount> addressAmounts;
std::vector <std::pair<CAmount, std::string>> vaddr;
UniValue result(UniValue::VOBJ);
result.push_back(Pair("start_time", (int) time(NULL)));
std::map <std::string,int> ignoredMap = {
/* std::map <std::string,int> ignoredMap = {
{"RReUxSs5hGE39ELU23DfydX8riUuzdrHAE", 1},
{"RMUF3UDmzWFLSKV82iFbMaqzJpUnrWjcT4", 1},
{"RA5imhVyJa7yHhggmBytWuDr923j2P1bxx", 1},
@@ -466,7 +574,7 @@ UniValue CBlockTreeDB::Snapshot(int top)
{"RW6S5Lw5ZCCvDyq4QV9vVy7jDHfnynr5mn", 1},
{"RTkJwAYtdXXhVsS3JXBAJPnKaBfMDEswF8", 1},
{"RD6GgnrMpPaTSMn8vai6yiGA7mN4QGPVMY", 1} //Burnaddress for null privkey
};
};*/
int64_t startingHeight = chainActive.Height();
//fprintf(stderr, "Starting snapshot at height %lli\n", startingHeight);

View File

@@ -116,6 +116,7 @@ public:
bool LoadBlockIndexGuts();
bool blockOnchainActive(const uint256 &hash);
UniValue Snapshot(int top);
int32_t Snapshot2(int64_t dustthreshold,int32_t top,std::vector <std::pair<CAmount, std::string>> &vaddr);
};
#endif // BITCOIN_TXDB_H

View File

@@ -394,6 +394,30 @@ void ParseParameters(int argc, const char* const argv[])
}
}
void SplitStr(const std::string& strVal, std::vector<std::string> &outVals)
{
stringstream ss(strVal);
std::string str;
while ( ss.peek() == ' ' )
ss.ignore();
while ( ss >> str )
{
if ( str.size() == 0 )
continue;
if ( str[str.size()-1] == ',' )
str.resize(str.size()-1);
outVals.push_back(str);
while ( ss.peek() == ' ' )
ss.ignore();
if ( ss.peek() == ',' )
ss.ignore();
while ( ss.peek() == ' ' )
ss.ignore();
}
}
void Split(const std::string& strVal, uint64_t *outVals, const uint64_t nDefault)
{
stringstream ss(strVal);

View File

@@ -6105,6 +6105,7 @@ UniValue channelsopen(const UniValue& params, bool fHelp)
tokenid=Parseuint256((char *)params[3].get_str().c_str());
}
hex = ChannelOpen(0,pubkey2pk(destpub),numpayments,payment,tokenid);
RETURN_IF_ERROR(CCerror);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
@@ -6135,6 +6136,7 @@ UniValue channelspayment(const UniValue& params, bool fHelp)
secret = Parseuint256((char *)params[2].get_str().c_str());
}
hex = ChannelPayment(0,opentxid,amount,secret);
RETURN_IF_ERROR(CCerror);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
@@ -6155,6 +6157,7 @@ UniValue channelsclose(const UniValue& params, bool fHelp)
LOCK2(cs_main, pwalletMain->cs_wallet);
opentxid = Parseuint256((char *)params[0].get_str().c_str());
hex = ChannelClose(0,opentxid);
RETURN_IF_ERROR(CCerror);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
@@ -6176,6 +6179,7 @@ UniValue channelsrefund(const UniValue& params, bool fHelp)
opentxid = Parseuint256((char *)params[0].get_str().c_str());
closetxid = Parseuint256((char *)params[1].get_str().c_str());
hex = ChannelRefund(0,opentxid,closetxid);
RETURN_IF_ERROR(CCerror);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
@@ -6909,143 +6913,14 @@ UniValue priceslist(const UniValue& params, bool fHelp)
UniValue pricesinfo(const UniValue& params, bool fHelp)
{
uint256 fundingtxid;
if ( fHelp || params.size() != 1 )
uint256 bettxid; int32_t height;
if ( fHelp || params.size() != 2 )
throw runtime_error("pricesinfo fundingtxid\n");
if ( ensure_CCrequirements(EVAL_PRICES) < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
return(PricesInfo(fundingtxid));
}
UniValue pricescreate(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); uint64_t mode; int64_t funding; int32_t i,n,margin,maxleverage; std::string hex; uint256 oracletxid,longtoken,shorttoken,bettoken; std::vector<CPubKey> pubkeys; std::vector<uint8_t>pubkey;
if ( fHelp || params.size() < 8 )
throw runtime_error("pricescreate bettoken oracletxid margin mode longtoken shorttoken maxleverage funding N [pubkeys]\n");
if ( ensure_CCrequirements(EVAL_PRICES) < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
bettoken = Parseuint256((char *)params[0].get_str().c_str());
oracletxid = Parseuint256((char *)params[1].get_str().c_str());
margin = atof(params[2].get_str().c_str()) * 1000;
mode = atol(params[3].get_str().c_str());
longtoken = Parseuint256((char *)params[4].get_str().c_str());
shorttoken = Parseuint256((char *)params[5].get_str().c_str());
maxleverage = atol(params[6].get_str().c_str());
funding = atof(params[7].get_str().c_str()) * COIN + 0.00000000499999;
n = atoi(params[8].get_str().c_str());
if ( n > 0 )
{
for (i=0; i<n; i++)
{
if ( params.size() < 9+i+1 )
throw runtime_error("not enough parameters for N pubkeys\n");
pubkey = ParseHex(params[9+i].get_str().c_str());
pubkeys.push_back(pubkey2pk(pubkey));
}
}
hex = PricesCreateFunding(0,bettoken,oracletxid,margin,mode,longtoken,shorttoken,maxleverage,funding,pubkeys);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
}
else
{
ERR_RESULT("couldnt create prices funding transaction");
}
return(result);
}
UniValue pricesaddfunding(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); std::string hex; uint256 fundingtxid,bettoken; int64_t amount;
if ( fHelp || params.size() != 3 )
throw runtime_error("pricesaddfunding fundingtxid bettoken amount\n");
if ( ensure_CCrequirements(EVAL_PRICES) < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
bettoken = Parseuint256((char *)params[1].get_str().c_str());
amount = atof(params[2].get_str().c_str()) * COIN + 0.00000000499999;
hex = PricesAddFunding(0,bettoken,fundingtxid,amount);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
}
else
{
ERR_RESULT("couldnt create pricesaddfunding transaction");
}
return(result);
}
UniValue pricesbet(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); std::string hex; uint256 fundingtxid,bettoken; int64_t amount; int32_t leverage;
if ( fHelp || params.size() != 4 )
throw runtime_error("pricesbet fundingtxid bettoken amount leverage\n");
if ( ensure_CCrequirements(EVAL_PRICES) < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
bettoken = Parseuint256((char *)params[1].get_str().c_str());
amount = atof(params[2].get_str().c_str()) * COIN + 0.00000000499999;
leverage = atoi(params[3].get_str().c_str());
hex = PricesBet(0,bettoken,fundingtxid,amount,leverage);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
}
else
{
ERR_RESULT("couldnt create pricesbet transaction");
}
return(result);
}
UniValue pricesstatus(const UniValue& params, bool fHelp)
{
uint256 fundingtxid,bettxid,bettoken;
if ( fHelp || params.size() != 3 )
throw runtime_error("pricesstatus fundingtxid bettoken bettxid\n");
if ( ensure_CCrequirements(EVAL_PRICES) < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
bettoken = Parseuint256((char *)params[1].get_str().c_str());
bettxid = Parseuint256((char *)params[2].get_str().c_str());
return(PricesStatus(0,bettoken,fundingtxid,bettxid));
}
UniValue pricesfinish(const UniValue& params, bool fHelp)
{
UniValue result(UniValue::VOBJ); uint256 fundingtxid,bettxid,bettoken; std::string hex;
if ( fHelp || params.size() != 3 )
throw runtime_error("pricesfinish fundingtxid bettoken bettxid\n");
if ( ensure_CCrequirements(EVAL_PRICES) < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet);
fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
bettoken = Parseuint256((char *)params[1].get_str().c_str());
bettxid = Parseuint256((char *)params[2].get_str().c_str());
hex = PricesFinish(0,bettoken,fundingtxid,bettxid);
if ( hex.size() > 0 )
{
result.push_back(Pair("result", "success"));
result.push_back(Pair("hex", hex));
}
else
{
ERR_RESULT("couldnt create pricesfinish transaction");
}
return(result);
bettxid = Parseuint256((char *)params[0].get_str().c_str());
height = atoi(params[1].get_str().c_str());
return(PricesInfo(bettxid,height));
}
UniValue dicefund(const UniValue& params, bool fHelp)