From 489485252b68597bc9173328ed21674b58f90b8b Mon Sep 17 00:00:00 2001 From: blackjok3r Date: Mon, 22 Apr 2019 18:02:19 +0800 Subject: [PATCH] fixes for TESTHC chain and add notes for others to make similar chains. --- src/cc/hempcoin_notes.txt | 65 +++++++++++++++++++++++++++++++ src/cc/payments.cpp | 80 +++++++-------------------------------- src/komodo_bitcoind.h | 3 +- src/wallet/rpcwallet.cpp | 20 +++++----- 4 files changed, 91 insertions(+), 77 deletions(-) create mode 100644 src/cc/hempcoin_notes.txt diff --git a/src/cc/hempcoin_notes.txt b/src/cc/hempcoin_notes.txt new file mode 100644 index 000000000..f8003ac95 --- /dev/null +++ b/src/cc/hempcoin_notes.txt @@ -0,0 +1,65 @@ +How this works: + - earlytxid must be a transaction included in the chain before block 100. The chain MUST not have any other of these type of tx before block 100, or someone may be able to change it and mess things up. + - When it gets to block 100, it takes the txid specified by the -earlytxid param (does not affect magic) + - Looks up the transaction searches for the opreturn, then permenantly appends it to the end of ac_script in RAM. + - After every daemon restart, the first time the daemon mines a block, or receives a block that pays ac_script it will look up the op_return and save it again. + - this enables it to always reach consensus but doesnt need to constantly keep looking up the tx in the chain. + - The trick is to use ac_founders=101 or higher so that nothing is ever paid to the unspendable CC address. Although it should still work without this it burns coins. + +-ac_script can be any Global CC address you can spend to with an OP_RETURN. Here we use example of paymentsCC being used to fund a rewards plan, and a set of founders address's. + you can get the ac_script from another chain, but the op_return payload must generated on the chain itself. this command gives you the needed info to get the scripPubKey Hex: + ./komodo-cli -ac_name=TEST paymentsfund '["5d536f54332db09f2be04593c54f764cf569e225f4d8df5155658c679e663682",1000]' + append: b8, to the end of ac_script, this changes magic value for -earlytxid chains vs normal ac_script and allows bypass of ac_supply paid to the scritpt as it would be unspendable and you would be unable to create the needed plans with no coins. + -ac_script=2ea22c8020987fad30df055db6fd922c3a57e55d76601229ed3da3b31340112e773df3d0d28103120c008203000401ccb8 + +-testnode=1 is not affecting magic and allows mining on a single node, we can use this to bootstrap the chain before syncing a second node to save time. + +start chain and make sure to do the following steps before block 100 (set generate false/true is a good idea between steps) + ./komodod -ac_name=TESTHC -ac_supply=1000000 -ac_reward=100000000000 -ac_cc=2 -ac_script=2ea22c8020987fad30df055db6fd922c3a57e55d76601229ed3da3b31340112e773df3d0d28103120c008203000401ccb8 -ac_founders=150 -ac_blocktime=20 -ac_nk=96,5 -testnode=1 + +create rewards plan and fund it with all or a % of the premine. Must be some amount. eg. + ./komodo-cli -ac_name=TESTHC rewardscreatefunding test 50000 25 0 2 500 + +do rewards add funding: + ./komodo-cli -ac_name=TESTHC rewardsaddfunding test 47a3150150bd196bd2086cae5e0c6b01a23785a04139fa660d169121a534b38e 1000 + +and get the script pubkey and op_return from this tx (no need to send it) +./komodo-cli -ac_name=TESTHC decoderawtransaction 010000000204ca4c7aaae62bb8fc9412ac010e047fa8d33c3f87d2adeb3e02170642ddfe370000000049483045022100d7b9a +4f28ca3a35f34dcdb6075e905cde1eaa962bd0619d0a8ed8e17e952bc99022077308e12325fc2a02c752ec3df9aeee1fc219ea54a4d3884834582b75c89815e01ffffffff08800132da3233d80c65e87b6db6a76dcf +188e4fdfa23198d69f647e67754cfb0000000049483045022100d6a8f7a1c4f6013f5897768ae0117fe61dfb72352d3e6652e64a6588db3ffcb102202aa1d041b24f9cbbf7028295b7c5e7f18b4f95ae39c13031dab +7f06634438e6801ffffffff0300e8764817000000302ea22c802065686d47a4049c2c845a71895a915eb84c04445896eec5dc0be40df0b31372da8103120c008203000401ccf0c0764817000000232103bbec93af84 +0933ae2d35fc56eff24f34dbe26871402552f84c44f690945ccd79ac00000000000000002c6a2ae54174657374000000008eb334a52191160d66fa3941a08537a2016b0c5eae6c08d26b19bd500115a34700000000 + +From the return of this you need the scriptpubkey hex of vout 0: + scriptPubKey: 2ea22c802065686d47a4049c2c845a71895a915eb84c04445896eec5dc0be40df0b31372da8103120c008203000401cc +and the scriptpubkey hex of the OP_RETURN in vout 2. + OP_RETURN: 6a2ae54174657374000000008eb334a52191160d66fa3941a08537a2016b0c5eae6c08d26b19bd500115a347 + +create txidopreturn for this payment: + ./komodo-cli -ac_name=TESTHC paymentstxidopret '[50,"2ea22c802065686d47a4049c2c845a71895a915eb84c04445896eec5dc0be40df0b31372da8103120c008203000401cc","6a2ae54174657374000000008eb334a52191160d66fa3941a08537a2016b0c5eae6c08d26b19bd500115a347"]' + +create the txidopret for the founders reward(s) pubkeys: should be able to be a few here, not sure of max number yet. These can pay anything that does not need an opreturn. allocation and scriptpubkey hex. + ./komodo-cli -ac_name=TESTHC paymentstxidopret '[50,"76a9146bf5dd9f679c87a3f83ea176f82148d26653c04388ac"]' + +create payments plan: + ./komodo-cli -ac_name=TESTHC paymentscreate '[0,0,"61f55f2f87dad3a37d42731a8cb73b3ebea1817abfa176218162c360a8bd7145","0550014823ffa0aa99d7dd7ca5292f4dd0a1b9156eddec03412c953f095181bc"]' +gives plan txid: ee7765be874fb084c00538b1b0488e8ecb857de253f09a9ba6ea8d3579b77d33 + +paymentsfund: + To do this you first need to change the type of tx generated by paymentsfund RPC. in payments.cpp go to line: 639 and comment it out, then uncomment the block of code under this. + change the line 646 to line 647 with comments, and line 650/651 aswell. This enables the RPC to generate the ccvout opreturn payload you need without sending the payment on the chain. Just decode the raw hex. + ./komodo-cli -ac_name=TESTHC paymentsfund '["ee7765be874fb084c00538b1b0488e8ecb857de253f09a9ba6ea8d3579b77d33",1000,1]' + +get the payment fund scriptpubkey hex from vout 0: (the split it at OP_CHECKCRYPTOCONDITION or 'cc' ) + 2ea22c8020987fad30df055db6fd922c3a57e55d76601229ed3da3b31340112e773df3d0d28103120c008203000401cc 2a0401f00101246a22f046337db779358deaa69b9af053e27d85cb8e8e48b0b13805c084b04f87be6577ee75 + + put the second half into an OP_RETURN: (the remaining part of the the above scriptpubkey) eg. + ./komodo-cli -ac_name=TESTHC opreturn_burn 1 2a0401f00101246a22f046337db779358deaa69b9af053e27d85cb8e8e48b0b13805c084b04f87be6577ee75 + opret_burn takes any burn amount and arbitrary hex string. (RPC works, but may have bugs, likely use this for LABS too with some fixes) + this gives a raw hex. Decode it and check the OP_RETURN is right before sending (using this RPC currently adds 3 extra bytes to the front (6a2d2c), which is truncated later on, this should be fixed if possible before making any real chains as its consensus code. Need to try diffrent methods to decode the hex correctly.) + -earlytxid=810bd62fb8353fad20267ff2050684b8829affa3edf6b366633931530791dfce + restart the chain with earlytxid param before height 100 on all nodes (if not using -testnode=1) + ./komodod -ac_name=TESTHC -ac_supply=1000000 -ac_reward=100000000000 -ac_cc=2 -ac_script=2ea22c8020987fad30df055db6fd922c3a57e55d76601229ed3da3b31340112e773df3d0d28103120c008203000401ccb8 -ac_founders=150 -ac_blocktime=20 -ac_nk=96,5 -earlytxid=810bd62fb8353fad20267ff2050684b8829affa3edf6b366633931530791dfce + +once the payments plan has been funded with the mined coinbase you can issue payments release when conditions of the plan are met to fund founders reward/rewards plan. eg. + ./komodo-cli -ac_name=TESTHC paymentsrelease '["ee7765be874fb084c00538b1b0488e8ecb857de253f09a9ba6ea8d3579b77d33",500]' diff --git a/src/cc/payments.cpp b/src/cc/payments.cpp index 7d6fcba32..ba915e586 100644 --- a/src/cc/payments.cpp +++ b/src/cc/payments.cpp @@ -16,60 +16,6 @@ #include "CCPayments.h" /* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -ac_script + -earlytxid instructions with payments cc + rewards CC as an example. -How this works: - - earlytxid must be a transaction included in the chain before block 100. The chain MUST not have any other of these type of tx before block 100, or someone may be able to change it and mess things up. - - When it gets to block 100, it takes the txid specified by the -earlytxid param (does not affect magic) - - Looks up the transaction searches for the opreturn, then permenantly appends it to the end of ac_script in RAM. - - After every daemon restart, the first time the daemon mines a block, or receives a block that pays ac_script it will look up the op_return and save it again. - - this enables it to always reach consensus but doesnt need to constantly keep looking up the tx in the chain. - - The trick is to use ac_founders=101 or higher so that nothing is ever paid to the unspendable CC address. Although it should still work without this it burns coins. - --ac_script can be any Global CC address you can spend to with an OP_RETURN. Here we use example of paymentsCC being used to fund a rewards plan, and a set of founders address's. - you can get the ac_script from another chain, but the op_return payload must generated on the chain itself. this command gives you the needed info to get the scripPubKey Hex: - ./komodo-cli -ac_name=TEST paymentsfund '["5d536f54332db09f2be04593c54f764cf569e225f4d8df5155658c679e663682",1000]' - append: b8, to the end of ac_script, this changes magic value for -earlytxid chains vs normal ac_script and allows bypass of ac_supply paid to the scritpt as it would be unspendable and you would be unable to create the needed plans with no coins. - -ac_script=2ea22c8020987fad30df055db6fd922c3a57e55d76601229ed3da3b31340112e773df3d0d28103120c008203000401ccb8 - -start chain and make sure to do the following steps before block 100 (set generate false/true is a good idea between steps) -create rewards plan and fund it with all or a % of the premine. Must be some amount. eg. - ./komodo-cli -ac_name=TEST rewardscreatefunding test 1000 10 0 10 10 - -do rewards add funding and get the script pubkey and op_return from this tx (no need to send it) eg. - scriptPubKey: 2ea22c802065686d47a4049c2c845a71895a915eb84c04445896eec5dc0be40df0b31372da8103120c008203000401cc - OP_RETURN: 6a2ae541746573740000000061e7063fa8f99ef92a47e4aebf7ea28c59aeadaf3c1784312de64e4bcb3666f1 - -create txidopreturn for this payment: - ./komodo-cli -ac_name=TEST paymentstxidopret '[50,"2ea22c802065686d47a4049c2c845a71895a915eb84c04445896eec5dc0be40df0b31372da8103120c008203000401cc","6a2ae541746573740000000061e7063fa8f99ef92a47e4aebf7ea28c59aeadaf3c1784312de64e4bcb3666f1"]' - -create the txidopret for the founders reward(s) pubkeys: should be able to be a few here, not sure of max number yet. These can pay anything that does not need an opreturn. allocation and scriptpubkey hex. - ./komodo-cli -ac_name=TEST paymentstxidopret '[50,"76a9146bf5dd9f679c87a3f83ea176f82148d26653c04388ac"]' - -create payments plan: - ./komodo-cli -ac_name=TEST paymentscreate '[0,0,"273d193e5d09928e471926827dcac1f06c4801bdaa5524a84b17a00f4eaf8d38","81264daf7874b2041802ac681e49618413313cc2f29b47d47bd8e63dc2a06cad"]' -gives plan txid eg. 5d536f54332db09f2be04593c54f764cf569e225f4d8df5155658c679e663682 - -paymentsfund: - send some of the premine to this payments fund to get the rest of the scriptpubkey payload. (could skip send and just gen/decode the tx if required.) - send opret path this time to get the required script pubkey. For payments this mode is enabled by default rather than a traditional OP_RETURN, - for other CC we would need to modify daemon to get the correct info. - ./komodo-cli -ac_name=TEST paymentsfund '["5d536f54332db09f2be04593c54f764cf569e225f4d8df5155658c679e663682",1000,1]' - -get the payment fund script pubkey: (the split it at OP_CHECKCRYPTOCONDITION or 'cc' ) - 2ea22c8020987fad30df055db6fd922c3a57e55d76601229ed3da3b31340112e773df3d0d28103120c008203000401cc 2a0401f00101246a22f0466b75e35aa4d8ea6c3dd1b76141a0acbd06dfb4897288a62b8a8ec31b75a5b6cb75 - - put the second half into an OP_RETURN: (the remaining part of the the above scriptpubkey) eg. - ./komodo-cli -ac_name=TEST opreturn_burn 1 2a0401f00101246a22f0466b75e35aa4d8ea6c3dd1b76141a0acbd06dfb4897288a62b8a8ec31b75a5b6cb75 - opret_burn takes any burn amount and arbitrary hex string. (RPC works, but may have bugs, likely use this for LABS too with some fixes) - this gives a txid to locate it in the chain eg: - -earlytxid=1acd0b9b728feaea37a3f52d4106c35b0f8cfd19f9f3e64815d23ace0721d69d - restart the chain with earlytxid param before height 100 on BOTH NODES! - -once the payments plan has been funded with the mined coinbase you can issue payments release when conditions of the plan are met to fund founders reward/rewards plan. eg. - ./komodo-cli -ac_name=TEST paymentsrelease '["5d536f54332db09f2be04593c54f764cf569e225f4d8df5155658c679e663682",500]' ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - 0) txidopret <- allocation, scriptPubKey, opret 1) create <- locked_blocks, minrelease, list of txidopret @@ -347,14 +293,14 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & CScript opret; uint256 checktxid; int32_t opret_ind; if ( (opret_ind= has_opret(txin, EVAL_PAYMENTS)) == 0 ) { - // get op_return from CCvout - opret = getCCopret(txin.vout[0].scriptPubKey); + // get op_return from CCvout, + opret = getCCopret(txin.vout[vin.prevout.n].scriptPubKey); } else { // get op_return from the op_return opret = txin.vout[opret_ind].scriptPubKey; - } // else return(eval->Invalid("vin has wrong amount of vouts")); // dont think this is needed? + } if ( DecodePaymentsFundOpRet(opret,checktxid) != 'F' || checktxid != createtxid ) { fprintf(stderr, "vin.%i is not a payments CC vout: txid.%s\n", i, txin.GetHash().ToString().c_str()); @@ -381,7 +327,7 @@ bool PaymentsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction & int64_t AddPaymentsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey txidpk,int64_t total,int32_t maxinputs,uint256 createtxid,int32_t latestheight) { - char coinaddr[64]; CPubKey Paymentspk; int64_t nValue,threshold,price,totalinputs = 0; uint256 txid,checktxid,hashBlock; std::vector origpubkey; CTransaction vintx,tx; int32_t iter,vout,ht,n = 0; + char coinaddr[64]; CPubKey Paymentspk; int64_t nValue,threshold,price,totalinputs = 0; uint256 txid,checktxid,hashBlock; std::vector origpubkey; CTransaction vintx; int32_t iter,vout,ht,n = 0; std::vector > unspentOutputs; if ( maxinputs > CC_MAXVINS ) maxinputs = CC_MAXVINS; @@ -400,7 +346,7 @@ int64_t AddPaymentsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP txid = it->first.txhash; vout = (int32_t)it->first.index; //fprintf(stderr,"iter.%d %s/v%d %s\n",iter,txid.GetHex().c_str(),vout,coinaddr); - if ( vout == 0 && GetTransaction(txid,vintx,hashBlock,false) != 0 ) + if ( (vout == 0 || vout == 1) && GetTransaction(txid,vintx,hashBlock,false) != 0 ) { if ( latestheight != 0 ) { @@ -421,14 +367,14 @@ int64_t AddPaymentsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP if ( (opret_ind= has_opret(vintx, EVAL_PAYMENTS)) == 0 ) { // get op_return from CCvout - opret = getCCopret(vintx.vout[0].scriptPubKey); + opret = getCCopret(vintx.vout[vout].scriptPubKey); } else { // get op_return from the op_return opret = vintx.vout[opret_ind].scriptPubKey; } - if ( myGetTransaction(txid,tx,hashBlock) == 0 || DecodePaymentsFundOpRet(opret,checktxid) != 'F' || checktxid != createtxid ) + if ( DecodePaymentsFundOpRet(opret,checktxid) != 'F' || checktxid != createtxid ) { fprintf(stderr,"bad opret %s vs %s\n",checktxid.GetHex().c_str(),createtxid.GetHex().c_str()); continue; @@ -690,16 +636,18 @@ UniValue PaymentsFund(struct CCcontract_info *cp,char *jsonstr) } else { - opret = EncodePaymentsFundOpRet(txid); + mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,amount,Paymentspk)); + // Use the below one along with other FinalizeCCTx/return, to get the ccvout scriptpubkey + /*opret = EncodePaymentsFundOpRet(txid); std::vector> vData = std::vector>(); if ( makeCCopret(opret, vData) ) - mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,amount,Paymentspk,&vData)); - //fprintf(stderr, "scriptpubkey.%s\n", mtx.vout.back().scriptPubKey.ToString().c_str()); - //fprintf(stderr, "hex.%s\n", HexStr(mtx.vout.back().scriptPubKey.begin(), mtx.vout.back().scriptPubKey.end()).c_str()); + mtx.vout.push_back(MakeCC1vout(EVAL_PAYMENTS,amount,Paymentspk,&vData)); */ } - rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,CScript()); + rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,EncodePaymentsFundOpRet(txid)); + //rawtx = FinalizeCCTx(0,cp,mtx,mypk,PAYMENTS_TXFEE,CScript()); // use this one to get ccvout scriptpubkey. if ( params != 0 ) free_json(params); + //return(payments_rawtxresult(result,rawtx,0)); // disable sending for CCvout, as we only need to decode the tx. return(payments_rawtxresult(result,rawtx,1)); } else diff --git a/src/komodo_bitcoind.h b/src/komodo_bitcoind.h index 3dd590417..788f3795a 100644 --- a/src/komodo_bitcoind.h +++ b/src/komodo_bitcoind.h @@ -2047,7 +2047,8 @@ bool komodo_appendACscriptpub() { ASSETCHAINS_SCRIPTPUB.pop_back(); ASSETCHAINS_SCRIPTPUB.pop_back(); // remove last 2 chars. // get OP_RETURN from txid and append the HexStr of it to scriptpub - ASSETCHAINS_SCRIPTPUB.append(HexStr(tx.vout[i].scriptPubKey.begin()+3, tx.vout[i].scriptPubKey.end())); + // encoded opreturn incorrectly on TESTHC chain, once we no longer need this it can be changed to a straight +1 to drop OP_RETURN opcode. + ASSETCHAINS_SCRIPTPUB.append(HexStr(tx.vout[i].scriptPubKey.begin()+(strcmp("TESTHC",ASSETCHAINS_SYMBOL) == 0 ? 3 : 1), tx.vout[i].scriptPubKey.end())); //fprintf(stderr, "ac_script.%s\n",ASSETCHAINS_SCRIPTPUB.c_str()); didinit = true; return true; diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index de446390e..8152e22b8 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -8014,13 +8014,13 @@ UniValue test_heirmarker(const UniValue& params, bool fHelp) UniValue opreturn_burn(const UniValue& params, bool fHelp) { + if (fHelp || (params.size() != 2)) + throw runtime_error("amount to burn, hexstring to send\n"); struct CCcontract_info *cp, C; UniValue ret(UniValue::VOBJ); if (ensure_CCrequirements(EVAL_PAYMENTS) < 0) throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); cp = CCinit(&C, EVAL_PAYMENTS); - if (fHelp || (params.size() != 2)) - throw runtime_error("amount to burn, hexstring to send\n"); - + CAmount nAmount = AmountFromValue(params[0]); if (nAmount <= 10000) throw JSONRPCError(RPC_TYPE_ERROR, "must send at least 10000 sat"); @@ -8032,13 +8032,13 @@ UniValue opreturn_burn(const UniValue& params, bool fHelp) if (normalInputs < nAmount) throw runtime_error("not enough normals\n"); - CScript opret; uint8_t scripthex[8192]; - - decode_hex(scripthex,strHex.size()/2,(char *)strHex.c_str()); - std::string test; - test.append((char*)scripthex); - std::vector opretdata(test.begin(), test.end()); - opret << OP_RETURN << E_MARSHAL(ss << opretdata); + CScript opret; uint8_t *ptr; + opret << OP_RETURN; + int32_t len = strlen(strHex.c_str()); + len >>=1; + opret.resize(len+1); + ptr = (uint8_t *)&opret[1]; + decode_hex(ptr,len,(char *)strHex.c_str()); mtx.vout.push_back(CTxOut(nAmount,opret)); ret.push_back(Pair("hex",FinalizeCCTx(0, cp, mtx, myPubkey, 10000, CScript()))); return(ret);