From fb132238f0f0fcece0e0d657700852aa0edee441 Mon Sep 17 00:00:00 2001 From: "Anton \"TonyL\" Lysakov" Date: Wed, 27 Mar 2019 23:36:58 +0700 Subject: [PATCH 1/5] Create cryptoconditions.py Forgot that we using it as a "library" for other CC tests. So deletion was a mistake. --- qa/rpc-tests/cryptoconditions.py | 690 +++++++++++++++++++++++++++++++ 1 file changed, 690 insertions(+) create mode 100644 qa/rpc-tests/cryptoconditions.py diff --git a/qa/rpc-tests/cryptoconditions.py b/qa/rpc-tests/cryptoconditions.py new file mode 100644 index 000000000..d5456e801 --- /dev/null +++ b/qa/rpc-tests/cryptoconditions.py @@ -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() From f6acb611122551d7a096ac18d5d859c7556c6cc8 Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Thu, 28 Mar 2019 15:57:16 +0100 Subject: [PATCH 2/5] Updated ChannelsCC validation (#20) - More constrained vins/vouts - Fixed CC marker value - Added validation of ChannelsOpen in all tx - Switched to LOGSTREAM for logging --- src/cc/channels.cpp | 284 ++++++++++++++++++++++---------------------- 1 file changed, 142 insertions(+), 142 deletions(-) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index 504ba629a..08dedb3f9 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -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[0],1,channeladdress,(numpayments-param2)*payment)==0 ) + return eval->Invalid("vout.0 is CC or invalid CC change amount 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 ((*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,23 @@ 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 0) + 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 +562,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 +582,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 +605,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 +619,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 +645,40 @@ 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 (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 +699,48 @@ 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 (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 ((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 +748,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 +781,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') { From 180ca470b0a9f79f7a8964f4224e62ac218c0c0e Mon Sep 17 00:00:00 2001 From: Mihailo Milenkovic Date: Thu, 28 Mar 2019 17:16:09 +0100 Subject: [PATCH 3/5] Fix CC change calculation for channelspayment --- src/cc/channels.cpp | 28 ++++++++++++++++++++++++++-- src/wallet/rpcwallet.cpp | 4 ++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/cc/channels.cpp b/src/cc/channels.cpp index 08dedb3f9..2887c18e1 100644 --- a/src/cc/channels.cpp +++ b/src/cc/channels.cpp @@ -254,8 +254,6 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & 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 ( ConstrainVout(tx.vout[0],1,channeladdress,(numpayments-param2)*payment)==0 ) - return eval->Invalid("vout.0 is CC or invalid CC change amount 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 ) @@ -283,6 +281,8 @@ bool ChannelsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & { 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 ( 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) @@ -550,6 +550,12 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2 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 (AddNormalinputs(mtx,mypk,txfee+CC_MARKER_VALUE,3) > 0) { if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid,mypk)) !=0 && (change=funds-amount)>=0) @@ -654,6 +660,12 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid) 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"); @@ -708,6 +720,12 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) 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"); @@ -720,6 +738,12 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid) 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"); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 107508c18..5456f3b9c 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -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")); From bf4a8750f3a18c2cdf814ac6c89e28b585d3c32b Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 3 Apr 2019 20:44:46 -1100 Subject: [PATCH 4/5] Change correlation factor to 4 --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 6862fcf14..7076f7808 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -2266,8 +2266,8 @@ int64_t komodo_pricecorrelated(uint64_t seed,int32_t ind,uint32_t *rawprices,int correlation = 0; i = (iter + seed) % daywindow; refprice = rawprices[i]; - highprice = (refprice * (COIN + PRICES_MAXCHANGE*3)) / COIN; - lowprice = (refprice * (COIN - PRICES_MAXCHANGE*3)) / COIN; + highprice = (refprice * (COIN + PRICES_MAXCHANGE*4)) / COIN; + lowprice = (refprice * (COIN - PRICES_MAXCHANGE*4)) / COIN; if ( highprice == refprice ) highprice++; if ( lowprice == refprice ) From 9561e30a283b42def4621ad3e3c94fab8cc52cd4 Mon Sep 17 00:00:00 2001 From: jl777 Date: Wed, 3 Apr 2019 20:48:38 -1100 Subject: [PATCH 5/5] 5% --- src/komodo_gateway.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/komodo_gateway.h b/src/komodo_gateway.h index 7076f7808..e42b8aa4b 100644 --- a/src/komodo_gateway.h +++ b/src/komodo_gateway.h @@ -2266,8 +2266,8 @@ int64_t komodo_pricecorrelated(uint64_t seed,int32_t ind,uint32_t *rawprices,int correlation = 0; i = (iter + seed) % daywindow; refprice = rawprices[i]; - highprice = (refprice * (COIN + PRICES_MAXCHANGE*4)) / COIN; - lowprice = (refprice * (COIN - PRICES_MAXCHANGE*4)) / COIN; + highprice = (refprice * (COIN + PRICES_MAXCHANGE*5)) / COIN; + lowprice = (refprice * (COIN - PRICES_MAXCHANGE*5)) / COIN; if ( highprice == refprice ) highprice++; if ( lowprice == refprice )