Merge pull request #124 from jl777/jl777

sync cclib_dyn->jl777:jl777
This commit is contained in:
ca333
2019-01-26 13:11:17 +01:00
committed by GitHub
45 changed files with 3061 additions and 1781 deletions

View File

@@ -13,12 +13,14 @@ export BITCOIND=${REAL_BITCOIND}
testScripts=( testScripts=(
'cryptoconditions_faucet.py' 'cryptoconditions_faucet.py'
'cryptoconditions_channels.py'
'cryptoconditions_dice.py' 'cryptoconditions_dice.py'
'cryptoconditions_oracles.py' 'cryptoconditions_oracles.py'
'cryptoconditions_rewards.py' 'cryptoconditions_rewards.py'
'cryptoconditions_token.py' 'cryptoconditions_token.py'
#'cryptoconditions_gateways.py' #'cryptoconditions_gateways.py'
'cryptoconditions_heir.py'
# TODO: cant reconnect nodes back in channels test because of crash (seems regtest only specific)
'cryptoconditions_channels.py'
); );
extArg="-extended" extArg="-extended"

View File

@@ -4,6 +4,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php. # file COPYING or http://www.opensource.org/licenses/mit-license.php.
import time
from test_framework.test_framework import CryptoconditionsTestFramework from test_framework.test_framework import CryptoconditionsTestFramework
from test_framework.authproxy import JSONRPCException from test_framework.authproxy import JSONRPCException
from test_framework.util import assert_equal, assert_greater_than, \ from test_framework.util import assert_equal, assert_greater_than, \
@@ -71,6 +72,58 @@ class CryptoconditionsChannelsTest(CryptoconditionsTestFramework):
result = rpc.channelsinfo(channel_txid) result = rpc.channelsinfo(channel_txid)
assert_equal(result["Transactions"][1]["Payment"], payment_tx_id) assert_equal(result["Transactions"][1]["Payment"], payment_tx_id)
# number of payments should be equal 1 (one denomination used)
result = rpc.channelsinfo(channel_txid)["Transactions"][1]["Number of payments"]
assert_equal(result, 1)
# payments left param should reduce 1 and be equal 9 now ( 10 - 1 = 9 )
result = rpc.channelsinfo(channel_txid)["Transactions"][1]["Payments left"]
assert_equal(result, 9)
# lets try payment with x2 amount to ensure that counters works correct
result = rpc.channelspayment(channel_txid, "200000")
assert_success(result)
payment_tx_id = self.send_and_mine(result["hex"], rpc)
assert payment_tx_id, "got txid"
result = rpc.channelsinfo(channel_txid)
assert_equal(result["Transactions"][2]["Payment"], payment_tx_id)
result = rpc.channelsinfo(channel_txid)["Transactions"][2]["Number of payments"]
assert_equal(result, 2)
result = rpc.channelsinfo(channel_txid)["Transactions"][2]["Payments left"]
assert_equal(result, 7)
# check if payment value really transferred
raw_transaction = rpc.getrawtransaction(payment_tx_id, 1)
result = raw_transaction["vout"][3]["valueSat"]
assert_equal(result, 200000)
result = rpc1.validateaddress(raw_transaction["vout"][3]["scriptPubKey"]["addresses"][0])["ismine"]
assert_equal(result, True)
# have to check that second node have coins to cover txfee at least
rpc.sendtoaddress(rpc1.getnewaddress(), 1)
rpc.sendtoaddress(rpc1.getnewaddress(), 1)
rpc.generate(2)
self.sync_all()
result = rpc1.getbalance()
assert_greater_than(result, 0.1)
# trying to initiate channels payment from node B without any secret
# TODO: have to add RPC validation
payment_hex = rpc1.channelspayment(channel_txid, "100000")
try:
result = rpc1.sendrawtransaction(payment_hex["hex"])
except Exception as e:
pass
# trying to initiate channels payment from node B with secret from previous payment
result = rpc1.channelspayment(channel_txid, "100000", rpc1.channelsinfo(channel_txid)["Transactions"][1]["Secret"])
#result = rpc1.sendrawtransaction(payment_hex["hex"])
assert_error(result)
# executing channel close # executing channel close
result = rpc.channelsclose(channel_txid) result = rpc.channelsclose(channel_txid)
assert_success(result) assert_success(result)
@@ -82,7 +135,7 @@ class CryptoconditionsChannelsTest(CryptoconditionsTestFramework):
# now in channelinfo closed flag should appear # now in channelinfo closed flag should appear
result = rpc.channelsinfo(channel_txid) result = rpc.channelsinfo(channel_txid)
assert_equal(result["Transactions"][2]["Close"], channel_close_txid) assert_equal(result["Transactions"][3]["Close"], channel_close_txid)
# executing channel refund # executing channel refund
result = rpc.channelsrefund(channel_txid, channel_close_txid) result = rpc.channelsrefund(channel_txid, channel_close_txid)
@@ -90,6 +143,92 @@ class CryptoconditionsChannelsTest(CryptoconditionsTestFramework):
refund_txid = self.send_and_mine(result["hex"], rpc) refund_txid = self.send_and_mine(result["hex"], rpc)
assert refund_txid, "got txid" assert refund_txid, "got txid"
# TODO: check if it refunded to opener address
raw_transaction = rpc.getrawtransaction(refund_txid, 1)
result = raw_transaction["vout"][2]["valueSat"]
assert_equal(result, 700000)
result = rpc.validateaddress(raw_transaction["vout"][2]["scriptPubKey"]["addresses"][0])["ismine"]
assert_equal(result, True)
# creating and draining channel (10 payment by 100000 satoshies in total to fit full capacity)
new_channel_hex1 = rpc.channelsopen(self.pubkey1, "10", "100000")
assert_success(new_channel_hex1)
channel1_txid = self.send_and_mine(new_channel_hex1["hex"], rpc)
assert channel1_txid, "got channel txid"
# need to have 2+ confirmations in the test mode
rpc.generate(2)
self.sync_all()
for i in range(10):
result = rpc.channelspayment(channel1_txid, "100000")
assert_success(result)
payment_tx_id = self.send_and_mine(result["hex"], rpc)
assert payment_tx_id, "got txid"
# last payment should indicate that 0 payments left
result = rpc.channelsinfo(channel1_txid)["Transactions"][10]["Payments left"]
assert_equal(result, 0)
# no more payments possible
result = rpc.channelspayment(channel1_txid, "100000")
assert_error(result)
# creating new channel to test the case when node B initiate payment when node A revealed secret in offline
# 10 payments, 100000 sat denomination channel opening with second node pubkey
new_channel_hex2 = rpc.channelsopen(self.pubkey1, "10", "100000")
assert_success(new_channel_hex)
channel2_txid = self.send_and_mine(new_channel_hex2["hex"], rpc)
assert channel2_txid, "got channel txid"
rpc.generate(2)
self.sync_all()
# disconnecting first node from network
rpc.setban("127.0.0.0/24","add")
assert_equal(rpc.getinfo()["connections"], 0)
assert_equal(rpc1.getinfo()["connections"], 0)
rpc1.generate(1)
# sending one payment to mempool to reveal the secret but not mine it
payment_hex = rpc.channelspayment(channel2_txid, "100000")
result = rpc.sendrawtransaction(payment_hex["hex"])
assert result, "got payment txid"
secret = rpc.channelsinfo(channel2_txid)["Transactions"][1]["Secret"]
assert secret, "Secret revealed"
# secret shouldn't be available for node B
secret_not_revealed = None
try:
rpc1.channelsinfo(channel2_txid)["Transactions"][1]["Secret"]
except Exception:
secret_not_revealed = True
assert_equal(secret_not_revealed, True)
# trying to initiate payment from second node with revealed secret
assert_equal(rpc1.getinfo()["connections"], 0)
dc_payment_hex = rpc1.channelspayment(channel2_txid, "100000", secret)
assert_success(dc_payment_hex)
result = rpc1.sendrawtransaction(dc_payment_hex["hex"])
assert result, "got channelspayment transaction id"
# TODO: it crash first node after block generating on mempools merging
# # restoring connection between nodes
# rpc.setban("127.0.0.0/24","remove")
# #rpc.generate(1)
# #rpc1.generate(1)
# sync_blocks(self.nodes)
# rpc.generate(1)
# sync_blocks(self.nodes)
# sync_mempools(self.nodes)
# assert_equal(rpc.getinfo()["connections"], 1)
# assert_equal(rpc1.getinfo()["connections"], 1)
def run_test(self): def run_test(self):
print("Mining blocks...") print("Mining blocks...")
rpc = self.nodes[0] rpc = self.nodes[0]

View File

@@ -0,0 +1,121 @@
#!/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.
import time
from test_framework.test_framework import CryptoconditionsTestFramework
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
from cryptoconditions import assert_success, assert_error, generate_random_string
class CryptoconditionsHeirTest(CryptoconditionsTestFramework):
def run_heir_tests(self):
rpc = self.nodes[0]
rpc1 = self.nodes[1]
result = rpc.heiraddress()
assert_success(result)
# verify all keys look like valid AC addrs, could be better
for x in ['myCCaddress', 'HeirCCaddress', 'Heirmarker', 'myaddress']:
assert_equal(result[x][0], 'R')
result = rpc.heiraddress(self.pubkey)
assert_success(result)
# test that additional CCaddress key is returned
for x in ['myCCaddress', 'HeirCCaddress', 'Heirmarker', 'myaddress', 'CCaddress']:
assert_equal(result[x][0], 'R')
# getting empty heir list
result = rpc.heirlist()
assert_equal(len(result), 1)
assert_success(result)
# valid heirfund case with coins
result = rpc.heirfund("0", "1000", "UNITHEIR", self.pubkey1, "10")
assert_success(result)
heir_fund_txid = self.send_and_mine(result["hextx"], rpc)
assert heir_fund_txid, "got heir funding txid"
# heir fund txid should be in heirlist now
result = rpc.heirlist()
assert_equal(len(result), 2)
assert_success(result)
assert_equal(result["fundingtxid"], heir_fund_txid)
# checking heirinfo
result = rpc.heirinfo(heir_fund_txid)
assert_success(result)
assert_equal(result["fundingtxid"], heir_fund_txid)
assert_equal(result["name"], "UNITHEIR")
assert_equal(result["owner"], self.pubkey)
assert_equal(result["heir"], self.pubkey1)
assert_equal(result["funding total in coins"], "1000.00000000")
assert_equal(result["funding available in coins"], "1000.00000000")
assert_equal(result["inactivity time setting, sec"], "10")
assert_equal(result["spending allowed for the heir"], "false")
# TODO: heirlist keys are duplicating now
# waiting for 11 seconds to be sure that needed time passed for heir claiming
time.sleep(11)
rpc.generate(1)
self.sync_all()
result = rpc.heirinfo(heir_fund_txid)
assert_equal(result["funding available in coins"], "1000.00000000")
assert_equal(result["spending allowed for the heir"], "true")
# have to check that second node have coins to cover txfee at least
rpc.sendtoaddress(rpc1.getnewaddress(), 1)
rpc.sendtoaddress(rpc1.getnewaddress(), 1)
rpc.generate(2)
self.sync_all()
second_node_balance = rpc1.getbalance()
assert_greater_than(second_node_balance, 0.1)
# let's claim whole heir sum from second node
result = rpc1.heirclaim("0", "1000", heir_fund_txid)
assert_success(result)
heir_claim_txid = self.send_and_mine(result["hextx"], rpc1)
assert heir_claim_txid, "got claim txid"
# balance of second node after heirclaim should increase for 1000 coins - txfees
# + get one block reward when broadcasted heir_claim_txid
result = round(rpc1.getbalance()) - round(second_node_balance)
assert_greater_than(result, 100999)
self.sync_all()
# no more funds should be available for claiming
result = rpc.heirinfo(heir_fund_txid)
assert_equal(result["funding available in coins"], "0.00000000")
# TODO: valid heirfund case with tokens
def run_test(self):
print("Mining blocks...")
rpc = self.nodes[0]
rpc1 = self.nodes[1]
# utxos from block 1 become mature in block 101
if not self.options.noshutdown:
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_heir_tests()
if __name__ == '__main__':
CryptoconditionsHeirTest().main()

View File

@@ -15,21 +15,35 @@ from cryptoconditions import assert_success, assert_error, generate_random_strin
class CryptoconditionsTokenTest(CryptoconditionsTestFramework): class CryptoconditionsTokenTest(CryptoconditionsTestFramework):
def run_token_tests(self): def run_token_tests(self):
rpc = self.nodes[0] rpc = self.nodes[0]
rpc1 = self.nodes[1]
result = rpc.tokenaddress() result = rpc.tokenaddress()
assert_success(result) assert_success(result)
for x in ['AssetsCCaddress', 'myCCaddress', 'Assetsmarker', 'myaddress']: for x in ['TokensCCaddress', 'myCCaddress', 'Tokensmarker', 'myaddress']:
assert_equal(result[x][0], 'R') assert_equal(result[x][0], 'R')
result = rpc.tokenaddress(self.pubkey) result = rpc.tokenaddress(self.pubkey)
assert_success(result) assert_success(result)
for x in ['TokensCCaddress', 'myCCaddress', 'Tokensmarker', 'myaddress', 'CCaddress']:
assert_equal(result[x][0], 'R')
result = rpc.assetsaddress()
assert_success(result)
for x in ['AssetsCCaddress', 'myCCaddress', 'Assetsmarker', 'myaddress']:
assert_equal(result[x][0], 'R')
result = rpc.assetsaddress(self.pubkey)
assert_success(result)
for x in ['AssetsCCaddress', 'myCCaddress', 'Assetsmarker', 'myaddress', 'CCaddress']: for x in ['AssetsCCaddress', 'myCCaddress', 'Assetsmarker', 'myaddress', 'CCaddress']:
assert_equal(result[x][0], 'R') assert_equal(result[x][0], 'R')
# there are no tokens created yet # there are no tokens created yet
result = rpc.tokenlist() result = rpc.tokenlist()
assert_equal(result, []) assert_equal(result, [])
# trying to create token with negaive supply # trying to create token with negative supply
result = rpc.tokencreate("NUKE", "-1987420", "no bueno supply") result = rpc.tokencreate("NUKE", "-1987420", "no bueno supply")
assert_error(result) assert_error(result)
@@ -50,12 +64,9 @@ class CryptoconditionsTokenTest(CryptoconditionsTestFramework):
result = rpc.tokenorders() result = rpc.tokenorders()
assert_equal(result, []) assert_equal(result, [])
# getting token balance for pubkey # getting token balance for non existing tokenid
result = rpc.tokenbalance(self.pubkey) result = rpc.tokenbalance(self.pubkey)
assert_success(result) assert_error(result)
assert_equal(result['balance'], 0)
assert_equal(result['CCaddress'], 'RCRsm3VBXz8kKTsYaXKpy7pSEzrtNNQGJC')
assert_equal(result['tokenid'], self.pubkey)
# get token balance for token with pubkey # get token balance for token with pubkey
result = rpc.tokenbalance(tokenid, self.pubkey) result = rpc.tokenbalance(tokenid, self.pubkey)
@@ -131,11 +142,25 @@ class CryptoconditionsTokenTest(CryptoconditionsTestFramework):
# checking ask cancellation # checking ask cancellation
testorder = rpc.tokenask("100", tokenid, "7.77") testorder = rpc.tokenask("100", tokenid, "7.77")
testorderid = self.send_and_mine(testorder['hex'], rpc) testorderid = self.send_and_mine(testorder['hex'], rpc)
# from other node (ensuring that second node have enough balance to cover txfee
# to get the actual error - not "not enough balance" one
rpc.sendtoaddress(rpc1.getnewaddress(), 1)
rpc.sendtoaddress(rpc1.getnewaddress(), 1)
rpc.generate(2)
self.sync_all()
result = rpc1.getbalance()
assert_greater_than(result, 0.1)
result = rpc1.tokencancelask(tokenid, testorderid)
assert_error(result)
# from valid node
cancel = rpc.tokencancelask(tokenid, testorderid) cancel = rpc.tokencancelask(tokenid, testorderid)
self.send_and_mine(cancel["hex"], rpc) self.send_and_mine(cancel["hex"], rpc)
result = rpc.tokenorders() result = rpc.tokenorders()
assert_equal(result, []) assert_equal(result, [])
# invalid numtokens bid # invalid numtokens bid
result = rpc.tokenbid("-1", tokenid, "1") result = rpc.tokenbid("-1", tokenid, "1")
assert_error(result) assert_error(result)
@@ -184,6 +209,15 @@ class CryptoconditionsTokenTest(CryptoconditionsTestFramework):
# checking bid cancellation # checking bid cancellation
testorder = rpc.tokenbid("100", tokenid, "7.77") testorder = rpc.tokenbid("100", tokenid, "7.77")
testorderid = self.send_and_mine(testorder['hex'], rpc) testorderid = self.send_and_mine(testorder['hex'], rpc)
# from other node
result = rpc1.getbalance()
assert_greater_than(result, 0.1)
result = rpc1.tokencancelbid(tokenid, testorderid)
assert_error(result)
# from valid node
cancel = rpc.tokencancelbid(tokenid, testorderid) cancel = rpc.tokencancelbid(tokenid, testorderid)
self.send_and_mine(cancel["hex"], rpc) self.send_and_mine(cancel["hex"], rpc)
result = rpc.tokenorders() result = rpc.tokenorders()
@@ -220,5 +254,6 @@ class CryptoconditionsTokenTest(CryptoconditionsTestFramework):
rpc1.importprivkey(self.privkey1) rpc1.importprivkey(self.privkey1)
self.run_token_tests() self.run_token_tests()
if __name__ == '__main__': if __name__ == '__main__':
CryptoconditionsTokenTest().main() CryptoconditionsTokenTest().main()

View File

@@ -94,7 +94,8 @@ void WaitForShutdown(boost::thread_group* threadGroup)
// //
// Start // Start
// //
extern int32_t IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,ASSETCHAIN_INIT; extern int32_t IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY;
extern uint32_t ASSETCHAIN_INIT;
extern std::string NOTARY_PUBKEY; extern std::string NOTARY_PUBKEY;
int32_t komodo_is_issuer(); int32_t komodo_is_issuer();
void komodo_passport_iteration(); void komodo_passport_iteration();

View File

@@ -212,7 +212,7 @@ bool FaucetExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction
bool FaucetValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx) bool FaucetValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx)
int64_t AddFaucetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs) int64_t AddFaucetInputs(struct CCcontract_infoCC_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
std::string FaucetGet(uint64_t txfee) std::string FaucetGet(uint64_t txfee)

View File

@@ -27,10 +27,10 @@ bool HeirValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,
class CoinHelper; class CoinHelper;
class TokenHelper; class TokenHelper;
UniValue HeirFundCoinCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid); UniValue HeirFundCoinCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid);
UniValue HeirFundTokenCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid); UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid);
UniValue HeirClaimCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount); UniValue HeirClaimCaller(uint256 fundingtxid, int64_t txfee, std::string amount);
UniValue HeirAddCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount); UniValue HeirAddCaller(uint256 fundingtxid, int64_t txfee, std::string amount);
UniValue HeirInfo(uint256 fundingtxid); UniValue HeirInfo(uint256 fundingtxid);
UniValue HeirList(); UniValue HeirList();

View File

@@ -477,14 +477,10 @@ std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 a
std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid) std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid)
{ {
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CTransaction vintx; CTransaction vintx; uint64_t mask;
uint64_t mask; uint256 hashBlock; int64_t bidamount;
uint256 hashBlock; CPubKey mypk; struct CCcontract_info *cpAssets, C;
int64_t bidamount; uint8_t funcid,dummyEvalCode; uint256 dummyAssetid, dummyAssetid2; int64_t dummyPrice; std::vector<uint8_t> dummyOrigpubkey;
CPubKey mypk;
struct CCcontract_info *cpAssets, C;
uint8_t dummyEvalCode; uint256 dummyAssetid, dummyAssetid2; int64_t dummyPrice; std::vector<uint8_t> dummyOrigpubkey;
cpAssets = CCinit(&C, EVAL_ASSETS); cpAssets = CCinit(&C, EVAL_ASSETS);
@@ -501,9 +497,12 @@ std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid)
bidamount = vintx.vout[0].nValue; bidamount = vintx.vout[0].nValue;
mtx.vin.push_back(CTxIn(bidtxid, 0, CScript())); // coins in Assets mtx.vin.push_back(CTxIn(bidtxid, 0, CScript())); // coins in Assets
if( DecodeAssetTokenOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, dummyEvalCode, dummyAssetid, dummyAssetid2, dummyPrice, dummyOrigpubkey) == 'b') if((funcid=DecodeAssetTokenOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, dummyEvalCode, dummyAssetid, dummyAssetid2, dummyPrice, dummyOrigpubkey))!=0)
mtx.vin.push_back(CTxIn(bidtxid, 1, CScript())); // spend marker if funcid='b' (not 'B') {
// TODO: spend it also in FillBuyOffer?
if (funcid == 's') mtx.vin.push_back(CTxIn(bidtxid, 1, CScript())); // spend marker if funcid='b'
else if (funcid=='S') mtx.vin.push_back(CTxIn(bidtxid, 3, CScript())); // spend marker if funcid='B'
}
mtx.vout.push_back(CTxOut(bidamount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); mtx.vout.push_back(CTxOut(bidamount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
@@ -523,12 +522,9 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid)
{ {
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CTransaction vintx; uint64_t mask; CTransaction vintx; uint64_t mask;
uint256 hashBlock; uint256 hashBlock; int64_t askamount;
int64_t askamount; CPubKey mypk; struct CCcontract_info *cpTokens, *cpAssets, tokensC, assetsC;
CPubKey mypk; uint8_t funcid,dummyEvalCode; uint256 dummyAssetid, dummyAssetid2; int64_t dummyPrice; std::vector<uint8_t> dummyOrigpubkey;
struct CCcontract_info *cpTokens, *cpAssets, tokensC, assetsC;
uint8_t dummyEvalCode; uint256 dummyAssetid, dummyAssetid2; int64_t dummyPrice; std::vector<uint8_t> dummyOrigpubkey;
cpAssets = CCinit(&assetsC, EVAL_ASSETS); cpAssets = CCinit(&assetsC, EVAL_ASSETS);
@@ -545,9 +541,11 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid)
askamount = vintx.vout[0].nValue; askamount = vintx.vout[0].nValue;
mtx.vin.push_back(CTxIn(asktxid, 0, CScript())); mtx.vin.push_back(CTxIn(asktxid, 0, CScript()));
if (DecodeAssetTokenOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, dummyEvalCode, dummyAssetid, dummyAssetid2, dummyPrice, dummyOrigpubkey) == 's') if ((funcid=DecodeAssetTokenOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, dummyEvalCode, dummyAssetid, dummyAssetid2, dummyPrice, dummyOrigpubkey))!=0)
mtx.vin.push_back(CTxIn(asktxid, 1, CScript())); // marker if funcid='s' (not 'S') {
// TODO: spend it also in FillSell? if (funcid == 's') mtx.vin.push_back(CTxIn(asktxid, 1, CScript())); // marker if funcid='s'
else if (funcid=='S') mtx.vin.push_back(CTxIn(asktxid, 3, CScript())); // marker if funcid='S'
}
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, askamount, mypk)); // one-eval token vout mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, askamount, mypk)); // one-eval token vout
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
@@ -607,7 +605,7 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f
mypk = pubkey2pk(Mypubkey()); mypk = pubkey2pk(Mypubkey());
if (AddNormalinputs(mtx, mypk, txfee, 3) > 0) if (AddNormalinputs(mtx, mypk, 2*txfee, 3) > 0)
{ {
mask = ~((1LL << mtx.vin.size()) - 1); mask = ~((1LL << mtx.vin.size()) - 1);
if (GetTransaction(bidtxid, vintx, hashBlock, false) != 0) if (GetTransaction(bidtxid, vintx, hashBlock, false) != 0)
@@ -637,9 +635,10 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount - paid_amount, unspendableAssetsPk)); // vout0 coins remainder mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount - paid_amount, unspendableAssetsPk)); // vout0 coins remainder
mtx.vout.push_back(CTxOut(paid_amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); // vout1 coins to normal mtx.vout.push_back(CTxOut(paid_amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); // vout1 coins to normal
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, fillamount, pubkey2pk(origpubkey))); // vout2 single-eval tokens sent to the buyer mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, fillamount, pubkey2pk(origpubkey))); // vout2 single-eval tokens sent to the buyer
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,txfee,origpubkey)); // vout3 marker to origpubkey
if (CCchange != 0) if (CCchange != 0)
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); // vout3 change in single-eval tokens mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); // vout4 change in single-eval tokens
fprintf(stderr,"FillBuyOffer remaining %llu -> origpubkey\n", (long long)remaining_required); fprintf(stderr,"FillBuyOffer remaining %llu -> origpubkey\n", (long long)remaining_required);
@@ -698,7 +697,7 @@ std::string FillSell(int64_t txfee, uint256 assetid, uint256 assetid2, uint256 a
txfee = 10000; txfee = 10000;
mypk = pubkey2pk(Mypubkey()); mypk = pubkey2pk(Mypubkey());
if (AddNormalinputs(mtx, mypk, txfee, 3) > 0) if (AddNormalinputs(mtx, mypk, 2*txfee, 3) > 0)
{ {
mask = ~((1LL << mtx.vin.size()) - 1); mask = ~((1LL << mtx.vin.size()) - 1);
if (GetTransaction(asktxid, vintx, hashBlock, false) != 0) if (GetTransaction(asktxid, vintx, hashBlock, false) != 0)
@@ -747,6 +746,7 @@ std::string FillSell(int64_t txfee, uint256 assetid, uint256 assetid2, uint256 a
//std::cerr << "FillSell() paid_value=" << paid_nValue << " origpubkey=" << HexStr(pubkey2pk(origpubkey)) << std::endl; //std::cerr << "FillSell() paid_value=" << paid_nValue << " origpubkey=" << HexStr(pubkey2pk(origpubkey)) << std::endl;
mtx.vout.push_back(CTxOut(paid_nValue, CScript() << origpubkey << OP_CHECKSIG)); //vout.2 coins to tokens seller's normal addr mtx.vout.push_back(CTxOut(paid_nValue, CScript() << origpubkey << OP_CHECKSIG)); //vout.2 coins to tokens seller's normal addr
} }
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,txfee,origpubkey)); //vout.3 marker to origpubkey
// not implemented // not implemented
if (CCchange != 0) { if (CCchange != 0) {

View File

@@ -234,6 +234,34 @@ uint8_t TokensCCpriv[32] = { 0x1d, 0x0d, 0x0d, 0xce, 0x2d, 0xd2, 0xe1, 0x9d, 0xf
#undef FUNCNAME #undef FUNCNAME
#undef EVALCODE #undef EVALCODE
#define FUNCNAME IsCClibInput
#define EVALCODE EVAL_FIRSTUSER
const char *CClibNormaladdr = "RVVeUg43rNcq3mZFnvZ8yqagyzqFgUnq4u";
char CClibCChexstr[67] = { "032447d97655da079729dc024c61088ea415b22f4c15d4810ddaf2069ac6468d2f" };
uint8_t CClibCCpriv[32] = { 0x57, 0xcf, 0x49, 0x71, 0x7d, 0xb4, 0x15, 0x1b, 0x4f, 0x98, 0xc5, 0x45, 0x8d, 0x26, 0x52, 0x4b, 0x7b, 0xe9, 0xbd, 0x55, 0xd8, 0x20, 0xd6, 0xc4, 0x82, 0x0f, 0xf5, 0xec, 0x6c, 0x1c, 0xa0, 0xc0 };
#include "CCcustom.inc"
#undef FUNCNAME
#undef EVALCODE
int32_t CClib_initcp(struct CCcontract_info *cp,uint8_t evalcode)
{
CPubKey pk; uint8_t pub33[33]; char CCaddr[64];
if ( evalcode == EVAL_FIRSTUSER ) // eventually make a hashchain for each evalcode
{
cp->evalcode = evalcode;
cp->ismyvin = IsCClibInput;
strcpy(cp->CChexstr,CClibCChexstr);
memcpy(cp->CCpriv,CClibCCpriv,32);
decode_hex(pub33,33,cp->CChexstr);
pk = buf2pk(pub33);
Getscriptaddress(cp->normaladdr,CScript() << ParseHex(HexStr(pk)) << OP_CHECKSIG);
if ( strcmp(cp->normaladdr,CClibNormaladdr) != 0 )
fprintf(stderr,"CClib_initcp addr mismatch %s vs %s\n",cp->normaladdr,CClibNormaladdr);
GetCCaddress(cp,cp->unspendableCCaddr,pk);
return(0);
}
return(-1);
}
struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode) struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode)
{ {
@@ -369,6 +397,10 @@ struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode)
cp->validate = TokensValidate; cp->validate = TokensValidate;
cp->ismyvin = IsTokensInput; cp->ismyvin = IsTokensInput;
break; break;
default:
if ( CClib_initcp(cp,evalcode) < 0 )
return(0);
break;
} }
return(cp); return(cp);
} }

View File

@@ -51,11 +51,6 @@ one other technical note is that komodod has the insight-explorer extensions bui
#include "../utlist.h" #include "../utlist.h"
#include "../uthash.h" #include "../uthash.h"
extern int32_t KOMODO_CONNECTING,KOMODO_CCACTIVATE,KOMODO_DEALERNODE;
extern uint32_t ASSETCHAINS_CC;
extern char ASSETCHAINS_SYMBOL[];
extern std::string CCerror,ASSETCHAINS_CCLIB;
extern uint8_t ASSETCHAINS_CCDISABLES[256];
#define CC_MAXVINS 1024 #define CC_MAXVINS 1024
@@ -69,6 +64,7 @@ extern uint8_t ASSETCHAINS_CCDISABLES[256];
typedef union _bits256 bits256; typedef union _bits256 bits256;
#endif #endif
#include "../komodo_cJSON.h"
struct CC_utxo struct CC_utxo
{ {
@@ -134,6 +130,9 @@ CBlockIndex *komodo_getblockindex(uint256 hash);
int32_t komodo_nextheight(); int32_t komodo_nextheight();
int32_t CCgetspenttxid(uint256 &spenttxid,int32_t &vini,int32_t &height,uint256 txid,int32_t vout); int32_t CCgetspenttxid(uint256 &spenttxid,int32_t &vini,int32_t &height,uint256 txid,int32_t vout);
void CCclearvars(struct CCcontract_info *cp);
UniValue CClib(struct CCcontract_info *cp,char *method,cJSON *params);
UniValue CClib_info(struct CCcontract_info *cp);
static const uint256 zeroid; static const uint256 zeroid;
bool myGetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock); bool myGetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock);
@@ -200,6 +199,7 @@ CC *MakeTokensCCcond1(uint8_t evalcode, CPubKey pk);
bool GetTokensCCaddress(struct CCcontract_info *cp, char *destaddr, CPubKey pk); bool GetTokensCCaddress(struct CCcontract_info *cp, char *destaddr, CPubKey pk);
bool GetTokensCCaddress1of2(struct CCcontract_info *cp, char *destaddr, CPubKey pk, CPubKey pk2); bool GetTokensCCaddress1of2(struct CCcontract_info *cp, char *destaddr, CPubKey pk, CPubKey pk2);
void CCaddrTokens1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr); void CCaddrTokens1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr);
int32_t CClib_initcp(struct CCcontract_info *cp,uint8_t evalcode);
bool IsCCInput(CScript const& scriptSig); bool IsCCInput(CScript const& scriptSig);
int32_t unstringbits(char *buf,uint64_t bits); int32_t unstringbits(char *buf,uint64_t bits);

View File

@@ -404,7 +404,6 @@ int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *c
uint8_t evalCodeInOpret; uint8_t evalCodeInOpret;
if (vopretExtra.size() >= 2 /*|| vopretExtra.size() != vopretExtra.begin()[0] <-- shold we check this?*/) { if (vopretExtra.size() >= 2 /*|| vopretExtra.size() != vopretExtra.begin()[0] <-- shold we check this?*/) {
std::cerr << "IsTokensvout() empty or incorrect contract opret" << std::endl;
evalCodeInOpret = vopretExtra.begin()[1]; evalCodeInOpret = vopretExtra.begin()[1];
} }
else { else {

View File

@@ -493,39 +493,10 @@ CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv)
return(pubkey2pk(ParseHex(cp->CChexstr))); return(pubkey2pk(ParseHex(cp->CChexstr)));
} }
bool ProcessCC(struct CCcontract_info *cp,Eval* eval, std::vector<uint8_t> paramsNull,const CTransaction &ctx, unsigned int nIn) void CCclearvars(struct CCcontract_info *cp)
{ {
CTransaction createTx; uint256 assetid,assetid2,hashBlock; uint8_t funcid; int32_t height,i,n,from_mempool = 0; int64_t amount; std::vector<uint8_t> origpubkey;
height = KOMODO_CONNECTING;
if ( KOMODO_CONNECTING < 0 ) // always comes back with > 0 for final confirmation
return(true);
if ( ASSETCHAINS_CC == 0 || (height & ~(1<<30)) < KOMODO_CCACTIVATE )
return eval->Invalid("CC are disabled or not active yet");
if ( (KOMODO_CONNECTING & (1<<30)) != 0 )
{
from_mempool = 1;
height &= ((1<<30) - 1);
}
//fprintf(stderr,"KOMODO_CONNECTING.%d mempool.%d vs CCactive.%d\n",height,from_mempool,KOMODO_CCACTIVATE);
// there is a chance CC tx is valid in mempool, but invalid when in block, so we cant filter duplicate requests. if any of the vins are spent, for example
//txid = ctx.GetHash();
//if ( txid == cp->prevtxid )
// return(true);
//fprintf(stderr,"process CC %02x\n",cp->evalcode);
cp->evalcode2 = cp->evalcode3 = 0; cp->evalcode2 = cp->evalcode3 = 0;
cp->unspendableaddr2[0] = cp->unspendableaddr3[0] = 0; cp->unspendableaddr2[0] = cp->unspendableaddr3[0] = 0;
if ( paramsNull.size() != 0 ) // Don't expect params
return eval->Invalid("Cannot have params");
//else if ( ctx.vout.size() == 0 ) // spend can go to z-addresses
// return eval->Invalid("no-vouts");
else if ( (*cp->validate)(cp,eval,ctx,nIn) != 0 )
{
//fprintf(stderr,"done CC %02x\n",cp->evalcode);
//cp->prevtxid = txid;
return(true);
}
//fprintf(stderr,"invalid CC %02x\n",cp->evalcode);
return(false);
} }
int64_t CCduration(int32_t &numblocks,uint256 txid) int64_t CCduration(int32_t &numblocks,uint256 txid)
@@ -602,7 +573,6 @@ bool komodo_txnotarizedconfirmed(uint256 txid)
CPubKey check_signing_pubkey(CScript scriptSig) CPubKey check_signing_pubkey(CScript scriptSig)
{ {
bool found = false; bool found = false;
CPubKey pubkey; CPubKey pubkey;
@@ -630,3 +600,79 @@ CPubKey check_signing_pubkey(CScript scriptSig)
} }
return CPubKey(); return CPubKey();
} }
bool ProcessCC(struct CCcontract_info *cp,Eval* eval, std::vector<uint8_t> paramsNull,const CTransaction &ctx, unsigned int nIn)
{
CTransaction createTx; uint256 assetid,assetid2,hashBlock; uint8_t funcid; int32_t height,i,n,from_mempool = 0; int64_t amount; std::vector<uint8_t> origpubkey;
height = KOMODO_CONNECTING;
if ( KOMODO_CONNECTING < 0 ) // always comes back with > 0 for final confirmation
return(true);
if ( ASSETCHAINS_CC == 0 || (height & ~(1<<30)) < KOMODO_CCACTIVATE )
return eval->Invalid("CC are disabled or not active yet");
if ( (KOMODO_CONNECTING & (1<<30)) != 0 )
{
from_mempool = 1;
height &= ((1<<30) - 1);
}
//fprintf(stderr,"KOMODO_CONNECTING.%d mempool.%d vs CCactive.%d\n",height,from_mempool,KOMODO_CCACTIVATE);
// there is a chance CC tx is valid in mempool, but invalid when in block, so we cant filter duplicate requests. if any of the vins are spent, for example
//txid = ctx.GetHash();
//if ( txid == cp->prevtxid )
// return(true);
//fprintf(stderr,"process CC %02x\n",cp->evalcode);
CCclearvars(cp);
if ( paramsNull.size() != 0 ) // Don't expect params
return eval->Invalid("Cannot have params");
//else if ( ctx.vout.size() == 0 ) // spend can go to z-addresses
// return eval->Invalid("no-vouts");
else if ( (*cp->validate)(cp,eval,ctx,nIn) != 0 )
{
//fprintf(stderr,"done CC %02x\n",cp->evalcode);
//cp->prevtxid = txid;
return(true);
}
//fprintf(stderr,"invalid CC %02x\n",cp->evalcode);
return(false);
}
extern struct CCcontract_info CCinfos[0x100];
extern std::string MYCCLIBNAME;
bool CClib_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx,unsigned int nIn);
bool CClib_Dispatch(const CC *cond,Eval *eval,std::vector<uint8_t> paramsNull,const CTransaction &txTo,unsigned int nIn)
{
uint8_t evalcode; int32_t height,from_mempool; struct CCcontract_info *cp;
if ( ASSETCHAINS_CCLIB != MYCCLIBNAME )
{
fprintf(stderr,"-ac_cclib=%s vs myname %s\n",ASSETCHAINS_CCLIB.c_str(),MYCCLIBNAME.c_str());
return eval->Invalid("-ac_cclib name mismatches myname");
}
height = KOMODO_CONNECTING;
if ( KOMODO_CONNECTING < 0 ) // always comes back with > 0 for final confirmation
return(true);
if ( ASSETCHAINS_CC == 0 || (height & ~(1<<30)) < KOMODO_CCACTIVATE )
return eval->Invalid("CC are disabled or not active yet");
if ( (KOMODO_CONNECTING & (1<<30)) != 0 )
{
from_mempool = 1;
height &= ((1<<30) - 1);
}
evalcode = cond->code[0];
if ( evalcode >= EVAL_FIRSTUSER && evalcode <= EVAL_LASTUSER )
{
cp = &CCinfos[(int32_t)evalcode];
if ( cp->didinit == 0 )
{
if ( CClib_initcp(cp,evalcode) == 0 )
cp->didinit = 1;
else return eval->Invalid("unsupported CClib evalcode");
}
CCclearvars(cp);
if ( paramsNull.size() != 0 ) // Don't expect params
return eval->Invalid("Cannot have params");
else if ( CClib_validate(cp,height,eval,txTo,nIn) != 0 )
return(true);
return(false); //eval->Invalid("error in CClib_validate");
}
return eval->Invalid("cclib CC must have evalcode between 16 and 127");
}

View File

@@ -153,8 +153,9 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
return eval->Invalid("AssetValidate: invalid opreturn payload"); return eval->Invalid("AssetValidate: invalid opreturn payload");
// find dual-eval tokens unspendable addr: // find dual-eval tokens unspendable addr:
char tokensUnspendableAddr[64]; char tokensUnspendableAddr[64],origpubkeyCCaddr[64];
GetTokensCCaddress(cpAssets, tokensUnspendableAddr, GetUnspendable(cpAssets, NULL)); GetTokensCCaddress(cpAssets, tokensUnspendableAddr, GetUnspendable(cpAssets, NULL));
GetCCaddress(cpAssets, origpubkeyCCaddr, origpubkey);
// we need this for validating single-eval tokens' vins/vous: // we need this for validating single-eval tokens' vins/vous:
struct CCcontract_info *cpTokens, tokensC; struct CCcontract_info *cpTokens, tokensC;
@@ -258,7 +259,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
if( (nValue = AssetValidateBuyvin(cpAssets, eval, totalunits, tmporigpubkey, assetsCCaddr, origaddr, tx, assetid)) == 0 ) if( (nValue = AssetValidateBuyvin(cpAssets, eval, totalunits, tmporigpubkey, assetsCCaddr, origaddr, tx, assetid)) == 0 )
return(false); return(false);
else if( numvouts < 3 ) else if( numvouts < 4 )
return eval->Invalid("not enough vouts for fillbuy"); return eval->Invalid("not enough vouts for fillbuy");
else if( tmporigpubkey != origpubkey ) else if( tmporigpubkey != origpubkey )
return eval->Invalid("mismatched origpubkeys for fillbuy"); return eval->Invalid("mismatched origpubkeys for fillbuy");
@@ -266,17 +267,19 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
{ {
if( nValue != tx.vout[0].nValue + tx.vout[1].nValue ) if( nValue != tx.vout[0].nValue + tx.vout[1].nValue )
return eval->Invalid("locked value doesnt match vout0+1 fillbuy"); return eval->Invalid("locked value doesnt match vout0+1 fillbuy");
else if( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 ) else if( tx.vout[4].scriptPubKey.IsPayToCryptoCondition() != 0 )
{ {
if( ConstrainVout(tx.vout[2], 1, assetsCCaddr, 0) == 0 ) // tokens on user cc addr if( ConstrainVout(tx.vout[2], 1, assetsCCaddr, 0) == 0 ) // tokens on user cc addr
return eval->Invalid("vout2 doesnt go to origpubkey fillbuy"); return eval->Invalid("vout2 doesnt go to origpubkey fillbuy");
else if ( inputs != tx.vout[2].nValue + tx.vout[3].nValue ) else if ( inputs != tx.vout[2].nValue + tx.vout[4].nValue )
return eval->Invalid("asset inputs doesnt match vout2+3 fillbuy"); return eval->Invalid("asset inputs doesnt match vout2+3 fillbuy");
} }
else if( ConstrainVout(tx.vout[2], 1, assetsCCaddr, inputs) == 0 ) // tokens on user cc addr else if( ConstrainVout(tx.vout[2], 1, assetsCCaddr, inputs) == 0 ) // tokens on user cc addr
return eval->Invalid("vout2 doesnt match inputs fillbuy"); return eval->Invalid("vout2 doesnt match inputs fillbuy");
else if( ConstrainVout(tx.vout[1],0,0,0) == 0 ) else if( ConstrainVout(tx.vout[1],0,0,0) == 0 )
return eval->Invalid("vout1 is CC for fillbuy"); return eval->Invalid("vout1 is CC for fillbuy");
else if( ConstrainVout(tx.vout[3], 1, origpubkeyCCaddr, 10000) == 0 )
return eval->Invalid("invalid marker for original pubkey");
else if( ValidateBidRemainder(remaining_price, tx.vout[0].nValue, nValue, tx.vout[1].nValue, tx.vout[2].nValue, totalunits) == false ) else if( ValidateBidRemainder(remaining_price, tx.vout[0].nValue, nValue, tx.vout[1].nValue, tx.vout[2].nValue, totalunits) == false )
return eval->Invalid("mismatched remainder for fillbuy"); return eval->Invalid("mismatched remainder for fillbuy");
else if( remaining_price != 0 ) else if( remaining_price != 0 )
@@ -345,7 +348,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
if( (assetoshis = AssetValidateSellvin(cpAssets, eval, totalunits, tmporigpubkey, userTokensCCaddr, origaddr, tx, assetid)) == 0 ) if( (assetoshis = AssetValidateSellvin(cpAssets, eval, totalunits, tmporigpubkey, userTokensCCaddr, origaddr, tx, assetid)) == 0 )
return(false); return(false);
else if( numvouts < 3 ) else if( numvouts < 4 )
return eval->Invalid("not enough vouts for fillask"); return eval->Invalid("not enough vouts for fillask");
else if( tmporigpubkey != origpubkey ) else if( tmporigpubkey != origpubkey )
return eval->Invalid("mismatched origpubkeys for fillask"); return eval->Invalid("mismatched origpubkeys for fillask");
@@ -359,6 +362,8 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
return eval->Invalid("normal vout1 for fillask"); return eval->Invalid("normal vout1 for fillask");
else if( ConstrainVout(tx.vout[2], 0, origaddr, 0) == 0 ) else if( ConstrainVout(tx.vout[2], 0, origaddr, 0) == 0 )
return eval->Invalid("normal vout1 for fillask"); return eval->Invalid("normal vout1 for fillask");
else if( ConstrainVout(tx.vout[3], 1, origpubkeyCCaddr, 10000) == 0 )
return eval->Invalid("invalid marker for original pubkey");
else if( remaining_price != 0 ) else if( remaining_price != 0 )
{ {
//char tokensUnspendableAddr[64]; //char tokensUnspendableAddr[64];

View File

@@ -27,32 +27,291 @@
#include "core_io.h" #include "core_io.h"
#include "crosschain.h" #include "crosschain.h"
#define MYCCLIBNAME ((char *)"stub") #define FAUCET2SIZE COIN
char *CClib_name() { return(MYCCLIBNAME); } struct CClib_rpcinfo
{
char *method,*help;
int32_t numrequiredargs,maxargs; // frontloaded with required
uint8_t funcid;
}
CClib_methods[] =
{
{ (char *)"faucet2_fund", (char *)"amount", 1, 1, 'F' },
{ (char *)"faucet2_get", (char *)"<no args>", 0, 0, 'G' },
};
bool CClib_Dispatch(const CC *cond,Eval *eval,std::vector<uint8_t> paramsNull,const CTransaction &txTo,unsigned int nIn) std::string MYCCLIBNAME = (char *)"faucet2";
char *CClib_name() { return((char *)MYCCLIBNAME.c_str()); }
std::string CClib_rawtxgen(struct CCcontract_info *cp,uint8_t funcid,cJSON *params);
UniValue CClib_info(struct CCcontract_info *cp)
{ {
uint8_t evalcode; int32_t height,from_mempool; UniValue result(UniValue::VOBJ),a(UniValue::VARR); int32_t i; char str[2];
if ( ASSETCHAINS_CCLIB != MYCCLIBNAME ) result.push_back(Pair("result","success"));
result.push_back(Pair("CClib",CClib_name()));
for (i=0; i<sizeof(CClib_methods)/sizeof(*CClib_methods); i++)
{ {
fprintf(stderr,"-ac_cclib=%s vs myname %s\n",ASSETCHAINS_CCLIB.c_str(),MYCCLIBNAME); UniValue obj(UniValue::VOBJ);
return eval->Invalid("-ac_cclib name mismatches myname"); if ( CClib_methods[i].funcid < ' ' || CClib_methods[i].funcid >= 128 )
} obj.push_back(Pair("funcid",CClib_methods[i].funcid));
height = KOMODO_CONNECTING; else
if ( KOMODO_CONNECTING < 0 ) // always comes back with > 0 for final confirmation
return(true);
if ( ASSETCHAINS_CC == 0 || (height & ~(1<<30)) < KOMODO_CCACTIVATE )
return eval->Invalid("CC are disabled or not active yet");
if ( (KOMODO_CONNECTING & (1<<30)) != 0 )
{ {
from_mempool = 1; str[0] = CClib_methods[i].funcid;
height &= ((1<<30) - 1); str[1] = 0;
obj.push_back(Pair("funcid",str));
} }
evalcode = cond->code[0]; obj.push_back(Pair("name",CClib_methods[i].method));
if ( evalcode >= EVAL_FIRSTUSER && evalcode <= EVAL_LASTUSER ) obj.push_back(Pair("help",CClib_methods[i].help));
obj.push_back(Pair("params_required",CClib_methods[i].numrequiredargs));
obj.push_back(Pair("params_max",CClib_methods[i].maxargs));
a.push_back(obj);
}
result.push_back(Pair("methods",a));
return(result);
}
UniValue CClib(struct CCcontract_info *cp,char *method,cJSON *params)
{ {
return(true); UniValue result(UniValue::VOBJ); int32_t i; std::string rawtx;
for (i=0; i<sizeof(CClib_methods)/sizeof(*CClib_methods); i++)
{
if ( strcmp(method,CClib_methods[i].method) == 0 )
{
result.push_back(Pair("result","success"));
result.push_back(Pair("method",CClib_methods[i].method));
rawtx = CClib_rawtxgen(cp,CClib_methods[i].funcid,params);
result.push_back(Pair("rawtx",rawtx));
return(result);
} }
return eval->Invalid("cclib CC must have evalcode between 16 and 127"); }
result.push_back(Pair("result","error"));
result.push_back(Pair("method",CClib_methods[i].method));
result.push_back(Pair("error","method not found"));
return(result);
}
int64_t IsCClibvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
{
char destaddr[64];
if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
{
if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
return(tx.vout[v].nValue);
}
return(0);
}
bool CClibExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,int32_t minage,uint64_t txfee)
{
static uint256 zerohash;
CTransaction vinTx; uint256 hashBlock,activehash; int32_t i,numvins,numvouts; int64_t inputs=0,outputs=0,assetoshis;
numvins = tx.vin.size();
numvouts = tx.vout.size();
for (i=0; i<numvins; i++)
{
//fprintf(stderr,"vini.%d\n",i);
if ( (*cp->ismyvin)(tx.vin[i].scriptSig) != 0 )
{
//fprintf(stderr,"vini.%d check mempool\n",i);
if ( eval->GetTxUnconfirmed(tx.vin[i].prevout.hash,vinTx,hashBlock) == 0 )
return eval->Invalid("cant find vinTx");
else
{
//fprintf(stderr,"vini.%d check hash and vout\n",i);
if ( hashBlock == zerohash )
return eval->Invalid("cant faucet2 from mempool");
if ( (assetoshis= IsCClibvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
inputs += assetoshis;
}
}
}
for (i=0; i<numvouts; i++)
{
//fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
if ( (assetoshis= IsCClibvout(cp,tx,i)) != 0 )
outputs += assetoshis;
}
if ( inputs != outputs+FAUCET2SIZE+txfee )
{
fprintf(stderr,"inputs %llu vs outputs %llu\n",(long long)inputs,(long long)outputs);
return eval->Invalid("mismatched inputs != outputs + FAUCET2SIZE + txfee");
}
else return(true);
}
bool CClib_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx,unsigned int nIn)
{
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
numvins = tx.vin.size();
numvouts = tx.vout.size();
preventCCvins = preventCCvouts = -1;
if ( numvouts < 1 )
return eval->Invalid("no vouts");
else
{
for (i=0; i<numvins; i++)
{
if ( IsCCInput(tx.vin[0].scriptSig) == 0 )
{
fprintf(stderr,"faucetget invalid vini\n");
return eval->Invalid("illegal normal vini");
}
}
//fprintf(stderr,"check amounts\n");
if ( CClibExactAmounts(cp,eval,tx,1,10000) == false )
{
fprintf(stderr,"faucetget invalid amount\n");
return false;
}
else
{
preventCCvouts = 1;
if ( IsCClibvout(cp,tx,0) != 0 )
{
preventCCvouts++;
i = 1;
} else i = 0;
txid = tx.GetHash();
memcpy(hash,&txid,sizeof(hash));
fprintf(stderr,"check faucetget txid %s %02x/%02x\n",uint256_str(str,txid),hash[0],hash[31]);
if ( tx.vout[i].nValue != FAUCET2SIZE )
return eval->Invalid("invalid faucet output");
else if ( (hash[0] & 0xff) != 0 || (hash[31] & 0xff) != 0 )
return eval->Invalid("invalid faucetget txid");
Getscriptaddress(destaddr,tx.vout[i].scriptPubKey);
SetCCtxids(txids,destaddr);
for (std::vector<std::pair<CAddressIndexKey, CAmount> >::const_iterator it=txids.begin(); it!=txids.end(); it++)
{
//int height = it->first.blockHeight;
if ( CCduration(numblocks,it->first.txhash) > 0 && numblocks > 3 )
{
//fprintf(stderr,"would return error %s numblocks.%d ago\n",uint256_str(str,it->first.txhash),numblocks);
return eval->Invalid("faucet2 is only for brand new addresses");
}
}
retval = PreventCC(eval,tx,preventCCvins,numvins,preventCCvouts,numvouts);
if ( retval != 0 )
fprintf(stderr,"faucet2get validated\n");
else fprintf(stderr,"faucet2get invalid\n");
return(retval);
}
}
}
int64_t AddCClibInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
{
char coinaddr[64]; int64_t threshold,nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
threshold = total/(maxinputs+1);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
if ( it->second.satoshis < threshold )
continue;
//char str[65]; fprintf(stderr,"check %s/v%d %.8f`\n",uint256_str(str,txid),vout,(double)it->second.satoshis/COIN);
// no need to prevent dup
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
if ( (nValue= IsCClibvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(txid,vout) == 0 )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
nValue = it->second.satoshis;
totalinputs += nValue;
n++;
if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
break;
} else fprintf(stderr,"nValue too small or already spent in mempool\n");
} else fprintf(stderr,"couldnt get tx\n");
}
return(totalinputs);
}
std::string Faucet2Fund(struct CCcontract_info *cp,uint64_t txfee,int64_t funds)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CPubKey mypk,cclibpk; CScript opret;
if ( txfee == 0 )
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
cclibpk = GetUnspendable(cp,0);
if ( AddNormalinputs(mtx,mypk,funds+txfee,64) > 0 )
{
mtx.vout.push_back(MakeCC1vout(cp->evalcode,funds,cclibpk));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,opret));
}
return("");
}
/*UniValue FaucetInfo()
{
UniValue result(UniValue::VOBJ); char numstr[64];
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CPubKey faucetpk; struct CCcontract_info *cp,C; int64_t funding;
result.push_back(Pair("result","success"));
result.push_back(Pair("name","Faucet"));
cp = CCinit(&C,EVAL_FAUCET);
faucetpk = GetUnspendable(cp,0);
funding = AddFaucetInputs(cp,mtx,faucetpk,0,0);
sprintf(numstr,"%.8f",(double)funding/COIN);
result.push_back(Pair("funding",numstr));
return(result);
}*/
std::string CClib_rawtxgen(struct CCcontract_info *cp,uint8_t funcid,cJSON *params)
{
CMutableTransaction tmpmtx,mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CPubKey mypk,cclibpk; int64_t funds,txfee=0,inputs,CCchange=0,nValue=FAUCET2SIZE; std::string rawhex; uint32_t j; int32_t i,len; uint8_t buf[32768]; bits256 hash;
if ( txfee == 0 )
txfee = 10000;
if ( funcid == 'F' )
{
if ( cJSON_GetArraySize(params) > 0 )
{
funds = (int64_t)jdouble(jitem(params,0),0)*COIN + 0.0000000049;
return(Faucet2Fund(cp,0,funds));
} else return("");
}
else if ( funcid != 'G' )
return("");
cclibpk = GetUnspendable(cp,0);
mypk = pubkey2pk(Mypubkey());
if ( (inputs= AddCClibInputs(cp,mtx,cclibpk,nValue+txfee,60)) > 0 )
{
if ( inputs > nValue )
CCchange = (inputs - nValue - txfee);
if ( CCchange != 0 )
mtx.vout.push_back(MakeCC1vout(EVAL_FIRSTUSER,CCchange,cclibpk));
mtx.vout.push_back(CTxOut(nValue,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
fprintf(stderr,"start at %u\n",(uint32_t)time(NULL));
j = rand() & 0xfffffff;
for (i=0; i<1000000; i++,j++)
{
tmpmtx = mtx;
rawhex = FinalizeCCTx(-1LL,cp,tmpmtx,mypk,txfee,CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_FIRSTUSER << (uint8_t)'G' << j));
if ( (len= (int32_t)rawhex.size()) > 0 && len < 65536 )
{
len >>= 1;
decode_hex(buf,len,(char *)rawhex.c_str());
hash = bits256_doublesha256(0,buf,len);
if ( (hash.bytes[0] & 0xff) == 0 && (hash.bytes[31] & 0xff) == 0 )
{
fprintf(stderr,"found valid txid after %d iterations %u\n",i,(uint32_t)time(NULL));
return(rawhex);
}
//fprintf(stderr,"%02x%02x ",hash.bytes[0],hash.bytes[31]);
}
}
fprintf(stderr,"couldnt generate valid txid %u\n",(uint32_t)time(NULL));
return("");
} else fprintf(stderr,"cant find faucet inputs\n");
return("");
} }

View File

@@ -502,6 +502,8 @@ std::string ChannelOpen(uint64_t txfee,CPubKey destpub,int32_t numpayments,int64
if (tokenid!=zeroid && tokens>funds) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,tokens-funds,mypk)); 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))); 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());
return(""); return("");
} }
@@ -520,25 +522,29 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2
mypk = pubkey2pk(Mypubkey()); mypk = pubkey2pk(Mypubkey());
if (GetTransaction(opentxid,channelOpenTx,hashblock,false) == 0) if (GetTransaction(opentxid,channelOpenTx,hashblock,false) == 0)
{ {
fprintf(stderr, "invalid channel open txid\n"); CCerror = strprintf("invalid channel open txid");
fprintf(stderr,"%s\n",CCerror.c_str());
return(""); return("");
} }
if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tokenid, txid, srcpub, destpub, totalnumpayments, payment, hashchain)=='O') if ((numvouts=channelOpenTx.vout.size()) > 0 && DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey, tokenid, txid, srcpub, destpub, totalnumpayments, payment, hashchain)=='O')
{ {
if (mypk != srcpub && mypk != destpub) if (mypk != srcpub && mypk != destpub)
{ {
fprintf(stderr,"this is not our channel\n"); CCerror = strprintf("this is not our channel");
fprintf(stderr,"%s\n",CCerror.c_str());
return(""); return("");
} }
else if (amount % payment != 0 || amount<payment) else if (amount % payment != 0 || amount<payment)
{ {
fprintf(stderr,"invalid amount, not a magnitude of payment size\n"); CCerror = strprintf("invalid amount, not a magnitude of payment size");
fprintf(stderr,"%s\n",CCerror.c_str());
return (""); return ("");
} }
} }
else else
{ {
fprintf(stderr, "invalid channel open tx\n"); CCerror = strprintf("invalid channel open tx");
fprintf(stderr,"%s\n",CCerror.c_str());
return (""); return ("");
} }
if (AddNormalinputs(mtx,mypk,2*txfee,3) > 0) if (AddNormalinputs(mtx,mypk,2*txfee,3) > 0)
@@ -552,11 +558,13 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2
{ {
if (numpayments > prevdepth) if (numpayments > prevdepth)
{ {
fprintf(stderr,"not enough funds in channel for that amount\n"); CCerror = strprintf("not enough funds in channel for that amount");
fprintf(stderr,"%s\n",CCerror.c_str());
return (""); return ("");
} else if (numpayments == 0) } else if (numpayments == 0)
{ {
fprintf(stderr,"invalid amount\n"); CCerror = strprintf("invalid amount");
fprintf(stderr,"%s\n",CCerror.c_str());
return (""); return ("");
} }
if (secret!=zeroid) if (secret!=zeroid)
@@ -570,7 +578,8 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2
endiancpy((uint8_t * ) & gensecret, hashdest, 32); endiancpy((uint8_t * ) & gensecret, hashdest, 32);
if (gensecret!=hashchain) if (gensecret!=hashchain)
{ {
fprintf(stderr,"invalid secret supplied\n"); CCerror = strprintf("invalid secret supplied");
fprintf(stderr,"%s\n",CCerror.c_str());
return(""); return("");
} }
} }
@@ -592,7 +601,8 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2
} }
else else
{ {
fprintf(stderr,"invalid previous tx\n"); CCerror = strprintf("invalid previous tx");
fprintf(stderr,"%s\n",CCerror.c_str());
return(""); return("");
} }
if (tokenid!=zeroid) mtx.vout.push_back(MakeTokensCC1of2vout(EVAL_CHANNELS, change, srcpub, destpub)); if (tokenid!=zeroid) mtx.vout.push_back(MakeTokensCC1of2vout(EVAL_CHANNELS, change, srcpub, destpub));
@@ -605,11 +615,13 @@ std::string ChannelPayment(uint64_t txfee,uint256 opentxid,int64_t amount, uint2
} }
else else
{ {
fprintf(stderr,"error adding CC inputs\n"); CCerror = strprintf("error adding CC inputs");
fprintf(stderr,"%s\n",CCerror.c_str());
return(""); return("");
} }
} }
fprintf(stderr,"error adding normal inputs\n"); CCerror = strprintf("error adding normal inputs");
fprintf(stderr,"%s\n",CCerror.c_str());
return(""); return("");
} }
@@ -629,36 +641,41 @@ std::string ChannelClose(uint64_t txfee,uint256 opentxid)
mypk = pubkey2pk(Mypubkey()); mypk = pubkey2pk(Mypubkey());
if (GetTransaction(opentxid,channelOpenTx,hashblock,false) == 0) if (GetTransaction(opentxid,channelOpenTx,hashblock,false) == 0)
{ {
fprintf(stderr, "invalid channel open txid\n"); CCerror = strprintf("invalid channel open txid");
fprintf(stderr,"%s\n",CCerror.c_str());
return (""); return ("");
} }
if ((numvouts=channelOpenTx.vout.size()) < 1 || DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,numpayments,payment,hashchain)!='O') if ((numvouts=channelOpenTx.vout.size()) < 1 || DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,tokenid,tmp_txid,srcpub,destpub,numpayments,payment,hashchain)!='O')
{ {
fprintf(stderr, "invalid channel open tx\n"); CCerror = strprintf("invalid channel open tx");
fprintf(stderr,"%s\n",CCerror.c_str());
return (""); return ("");
} }
if (mypk != srcpub) if (mypk != srcpub)
{ {
fprintf(stderr,"cannot close, you are not channel owner\n"); CCerror = strprintf("cannot close, you are not channel owner");
fprintf(stderr,"%s\n",CCerror.c_str());
return(""); return("");
} }
if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 ) if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 )
{ {
if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid,mypk)) !=0 && funds-txfee>0) if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid,mypk)) !=0 && funds>0)
{ {
if (tokenid!=zeroid) mtx.vout.push_back(MakeTokensCC1of2vout(EVAL_CHANNELS, funds-txfee, mypk, destpub)); if (tokenid!=zeroid) mtx.vout.push_back(MakeTokensCC1of2vout(EVAL_CHANNELS, funds, mypk, destpub));
else mtx.vout.push_back(MakeCC1of2vout(EVAL_CHANNELS, funds-txfee, 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,mypk));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub)); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub));
return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('C',tokenid,opentxid,mypk,destpub,(funds-txfee)/payment,payment,zeroid))); return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('C',tokenid,opentxid,mypk,destpub,funds/payment,payment,zeroid)));
} }
else else
{ {
fprintf(stderr,"error adding CC inputs\n"); CCerror = strprintf("error adding CC inputs");
fprintf(stderr,"%s\n",CCerror.c_str());
return(""); return("");
} }
} }
fprintf(stderr,"error adding normal inputs\n"); CCerror = strprintf("error adding normal inputs");
fprintf(stderr,"%s\n",CCerror.c_str());
return(""); return("");
} }
@@ -678,61 +695,72 @@ std::string ChannelRefund(uint64_t txfee,uint256 opentxid,uint256 closetxid)
mypk = pubkey2pk(Mypubkey()); mypk = pubkey2pk(Mypubkey());
if (GetTransaction(closetxid,channelCloseTx,hashblock,false) == 0) if (GetTransaction(closetxid,channelCloseTx,hashblock,false) == 0)
{ {
fprintf(stderr, "invalid channel close txid\n"); CCerror = strprintf("invalid channel close txid");
fprintf(stderr,"%s\n",CCerror.c_str());
return (""); return ("");
} }
if ((numvouts=channelCloseTx.vout.size()) < 1 || DecodeChannelsOpRet(channelCloseTx.vout[numvouts-1].scriptPubKey,tokenid,txid,srcpub,destpub,param1,param2,param3)!='C') if ((numvouts=channelCloseTx.vout.size()) < 1 || DecodeChannelsOpRet(channelCloseTx.vout[numvouts-1].scriptPubKey,tokenid,txid,srcpub,destpub,param1,param2,param3)!='C')
{ {
fprintf(stderr, "invalid channel close tx\n"); CCerror = strprintf("invalid channel close tx");
fprintf(stderr,"%s\n",CCerror.c_str());
return (""); return ("");
} }
if (txid!=opentxid) if (txid!=opentxid)
{ {
fprintf(stderr, "open and close txid are not from same channel\n"); CCerror = strprintf("open and close txid are not from same channel");
fprintf(stderr,"%s\n",CCerror.c_str());
return (""); return ("");
} }
if (GetTransaction(opentxid,channelOpenTx,hashblock,false) == 0) if (GetTransaction(opentxid,channelOpenTx,hashblock,false) == 0)
{ {
fprintf(stderr, "invalid channel open txid\n"); CCerror = strprintf("invalid channel open txid");
fprintf(stderr,"%s\n",CCerror.c_str());
return (""); return ("");
} }
if ((numvouts=channelOpenTx.vout.size()) < 1 || DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,tokenid,txid,srcpub,destpub,numpayments,payment,hashchain)!='O') if ((numvouts=channelOpenTx.vout.size()) < 1 || DecodeChannelsOpRet(channelOpenTx.vout[numvouts-1].scriptPubKey,tokenid,txid,srcpub,destpub,numpayments,payment,hashchain)!='O')
{ {
fprintf(stderr, "invalid channel open tx\n"); CCerror = strprintf("invalid channel open tx");
fprintf(stderr,"%s\n",CCerror.c_str());
return (""); return ("");
} }
if (mypk != srcpub) if (mypk != srcpub)
{ {
fprintf(stderr,"cannot refund, you are not the channel owenr\n"); CCerror = strprintf("cannot refund, you are not the channel owner");
fprintf(stderr,"%s\n",CCerror.c_str());
return(""); return("");
} }
if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 ) if ( AddNormalinputs(mtx,mypk,2*txfee,3) > 0 )
{ {
if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid,mypk)) !=0 && funds-txfee>0) if ((funds=AddChannelsInputs(cp,mtx,channelOpenTx,prevtxid,mypk)) !=0 && funds>0)
{ {
if ((GetTransaction(prevtxid,prevTx,hashblock,false) != 0) && (numvouts=prevTx.vout.size()) > 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) 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,mypk));
mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub)); mtx.vout.push_back(MakeCC1vout(EVAL_CHANNELS,txfee,destpub));
if (tokenid!=zeroid) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,funds-txfee,mypk)); if (tokenid!=zeroid) mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS,funds,mypk));
else mtx.vout.push_back(CTxOut(funds-txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); 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,param1,payment,closetxid))); return(FinalizeCCTx(0,cp,mtx,mypk,txfee,EncodeChannelsOpRet('R',tokenid,opentxid,mypk,destpub,funds/payment,payment,closetxid)));
} }
else else
{ {
fprintf(stderr,"previous tx is invalid\n"); CCerror = strprintf("previous tx is invalid");
fprintf(stderr,"%s\n",CCerror.c_str());
return(""); return("");
} }
} }
else else
{ {
fprintf(stderr,"error adding CC inputs\n"); CCerror = strprintf("error adding CC inputs");
fprintf(stderr,"%s\n",CCerror.c_str());
return(""); return("");
} }
} }
CCerror = strprintf("error adding normal inputs");
fprintf(stderr,"%s\n",CCerror.c_str());
return(""); return("");
} }
UniValue ChannelsList() UniValue ChannelsList()
{ {
UniValue result(UniValue::VOBJ); std::vector<std::pair<CAddressIndexKey, CAmount> > txids; struct CCcontract_info *cp,C; uint256 txid,hashBlock,tmp_txid,param3,tokenid; UniValue result(UniValue::VOBJ); std::vector<std::pair<CAddressIndexKey, CAmount> > txids; struct CCcontract_info *cp,C; uint256 txid,hashBlock,tmp_txid,param3,tokenid;

View File

@@ -649,21 +649,21 @@ int64_t z_getbalance(char *refcoin,char *acname,char *coinaddr)
int32_t z_exportkey(char *privkey,char *refcoin,char *acname,char *zaddr) int32_t z_exportkey(char *privkey,char *refcoin,char *acname,char *zaddr)
{ {
cJSON *retjson; char *retstr,cmpstr[64]; int64_t amount=0; int32_t retval = -1; cJSON *retjson; char *retstr,cmpstr[64]; int64_t amount=0;
privkey[0] = 0; privkey[0] = 0;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_exportkey",zaddr,"","","")) != 0 ) if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_exportkey",zaddr,"","","")) != 0 )
{ {
fprintf(stderr,"z_exportkey.(%s) %s returned json!\n",refcoin,acname); fprintf(stderr,"z_exportkey.(%s) %s returned json!\n",refcoin,acname);
free_json(retjson); free_json(retjson);
return(-1);
} }
else if ( retstr != 0 ) else if ( retstr != 0 )
{ {
//printf("retstr %s -> %.8f\n",retstr,dstr(amount)); //printf("retstr %s -> %.8f\n",retstr,dstr(amount));
strcpy(privkey,retstr); strcpy(privkey,retstr);
free(retstr); free(retstr);
retval = 0; return(0);
} }
return(retval);
} }
int32_t getnewaddress(char *coinaddr,char *refcoin,char *acname) int32_t getnewaddress(char *coinaddr,char *refcoin,char *acname)
@@ -700,6 +700,23 @@ int32_t z_getnewaddress(char *coinaddr,char *refcoin,char *acname,char *typestr)
return(retval); return(retval);
} }
int32_t z_getnewaddress(char *coinaddr,char *refcoin,char *acname,char *typestr)
{
cJSON *retjson; char *retstr; int64_t amount=0;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_getnewaddress",typestr,"","","")) != 0 )
{
fprintf(stderr,"z_getnewaddress.(%s) %s returned json!\n",refcoin,acname);
free_json(retjson);
return(-1);
}
else if ( retstr != 0 )
{
strcpy(coinaddr,retstr);
free(retstr);
return(0);
}
}
int64_t find_onetime_amount(char *coinstr,char *coinaddr) int64_t find_onetime_amount(char *coinstr,char *coinaddr)
{ {
cJSON *array,*item; int32_t i,n; char *addr; int64_t amount = 0; cJSON *array,*item; int32_t i,n; char *addr; int64_t amount = 0;
@@ -824,6 +841,39 @@ int32_t z_mergetoaddress(char *opidstr,char *coinstr,char *acname,char *destaddr
return(retval); return(retval);
} }
int32_t z_mergetoaddress(char *opidstr,char *coinstr,char *acname,char *destaddr)
{
cJSON *retjson; char *retstr,addr[128],*opstr; int32_t retval = -1;
sprintf(addr,"[\\\"ANY_SPROUT\\\"]");
//printf("z_sendmany from.(%s) -> %s\n",addr,destaddr);
if ( (retjson= get_komodocli(coinstr,&retstr,acname,"z_mergetoaddress",addr,destaddr,"","")) != 0 )
{
/*{
"remainingUTXOs": 0,
"remainingTransparentValue": 0.00000000,
"remainingNotes": 222,
"remainingShieldedValue": 5413.39093055,
"mergingUTXOs": 0,
"mergingTransparentValue": 0.00000000,
"mergingNotes": 10,
"mergingShieldedValue": 822.47447172,
"opid": "opid-f28f6261-4120-436c-aca5-859870a40a70"
}*/
if ( (opstr= jstr(retjson,"opid")) != 0 )
strcpy(opidstr,opstr);
retval = jint(retjson,"remainingNotes");
fprintf(stderr,"%s\n",jprint(retjson,0));
free_json(retjson);
}
else if ( retstr != 0 )
{
fprintf(stderr,"z_mergetoaddress.(%s) -> opid.(%s)\n",coinstr,retstr);
strcpy(opidstr,retstr);
free(retstr);
}
return(retval);
}
int32_t empty_mempool(char *coinstr,char *acname) int32_t empty_mempool(char *coinstr,char *acname)
{ {
cJSON *array; int32_t n; cJSON *array; int32_t n;

View File

@@ -15,6 +15,7 @@
#include "CCHeir.h" #include "CCHeir.h"
#include "heir_validate.h" #include "heir_validate.h"
#include <iomanip>
class CoinHelper; class CoinHelper;
class TokenHelper; class TokenHelper;
@@ -56,13 +57,14 @@ template <typename Helper> bool RunValidationPlans(uint8_t funcId, struct CCcont
// only for tokens: // only for tokens:
CMyPubkeyVoutValidator<TokenHelper> ownerCCaddrValidator(cp, fundingOpretScript, false); // check if this correct owner's cc user addr corresponding to opret CMyPubkeyVoutValidator<TokenHelper> ownerCCaddrValidator(cp, fundingOpretScript, false); // check if this correct owner's cc user addr corresponding to opret
COpRetValidator<Helper> opRetValidator(cp, fundingOpretScript); // compare opRets in this and last tx COpRetValidator<Helper> opRetValidator(cp, fundingOpretScript); // compare opRets in this and last tx
CMarkerValidator<Helper> markerValidator(cp); // initial tx marker spending protection
CNullValidator<Helper> nullValidator(cp); CNullValidator<Helper> nullValidator(cp);
switch (funcId) { switch (funcId) {
case 'F': // fund tokens case 'F': // fund tokens (only for tokens)
// vin validation plan: // vin validation plan:
vinPlan.pushValidators<CValidatorBase>((CInputIdentifierBase*)&normalInputIdentifier, &nullValidator); // txfee vin vinPlan.pushValidators<CValidatorBase>((CInputIdentifierBase*)&normalInputIdentifier, &nullValidator); // txfee vin
vinPlan.pushValidators<CValidatorBase>((CInputIdentifierBase*)&ccInputIdentifier, &ownerCCaddrValidator); // check cc owner addr vinPlan.pushValidators<CValidatorBase>((CInputIdentifierBase*)&ccInputIdentifier, &markerValidator, &ownerCCaddrValidator); // check cc owner addr
// vout validation plan: // vout validation plan:
voutPlan.pushValidators<CValidatorBase>(0, &cc1of2ValidatorThis); // check 1of2 addr funding voutPlan.pushValidators<CValidatorBase>(0, &cc1of2ValidatorThis); // check 1of2 addr funding
@@ -70,10 +72,10 @@ template <typename Helper> bool RunValidationPlans(uint8_t funcId, struct CCcont
// no checking for opret yet // no checking for opret yet
break; break;
case 'A': // add tokens case 'A': // add tokens (only for tokens)
// vin validation plan: // vin validation plan:
vinPlan.pushValidators<CValidatorBase>((CInputIdentifierBase*)&normalInputIdentifier, &nullValidator); // txfee vin vinPlan.pushValidators<CValidatorBase>((CInputIdentifierBase*)&normalInputIdentifier, &nullValidator); // txfee vin
vinPlan.pushValidators<CValidatorBase>((CInputIdentifierBase*)&ccInputIdentifier, &ownerCCaddrValidator); // check cc owner addr vinPlan.pushValidators<CValidatorBase>((CInputIdentifierBase*)&ccInputIdentifier, &markerValidator, &ownerCCaddrValidator); // check cc owner addr
// vout validation plan: // vout validation plan:
voutPlan.pushValidators<CValidatorBase>(0, &cc1of2ValidatorThis); // check 1of2 addr funding voutPlan.pushValidators<CValidatorBase>(0, &cc1of2ValidatorThis); // check 1of2 addr funding
@@ -81,10 +83,10 @@ template <typename Helper> bool RunValidationPlans(uint8_t funcId, struct CCcont
voutPlan.pushValidators<CValidatorBase>(numvouts - 1, &opRetValidator); // opreturn check, NOTE: only for C or A: voutPlan.pushValidators<CValidatorBase>(numvouts - 1, &opRetValidator); // opreturn check, NOTE: only for C or A:
break; break;
case 'C': case 'C': // spend coins or tokens
// vin validation plan: // vin validation plan:
vinPlan.pushValidators<CValidatorBase>((CInputIdentifierBase*)&normalInputIdentifier, &nullValidator); // txfee vin vinPlan.pushValidators<CValidatorBase>((CInputIdentifierBase*)&normalInputIdentifier, &nullValidator); // txfee vin
vinPlan.pushValidators<CValidatorBase>((CInputIdentifierBase*)&ccInputIdentifier, &cc1of2ValidatorThis); // cc1of2 funding addr vinPlan.pushValidators<CValidatorBase>((CInputIdentifierBase*)&ccInputIdentifier, &markerValidator, &cc1of2ValidatorThis); // cc1of2 funding addr
// vout validation plan: // vout validation plan:
voutPlan.pushValidators<CValidatorBase>(0, &heirSpendValidator); // check if heir is allowed to spend voutPlan.pushValidators<CValidatorBase>(0, &heirSpendValidator); // check if heir is allowed to spend
@@ -400,6 +402,23 @@ uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, uint256 &f
return _DecodeHeirEitherOpRet(scriptPubKey, tokenid, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingTxidInOpret, hasHeirSpendingBegun, noLogging); return _DecodeHeirEitherOpRet(scriptPubKey, tokenid, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingTxidInOpret, hasHeirSpendingBegun, noLogging);
} }
// check if pubkey is in vins
void CheckVinPubkey(std::vector<CTxIn> vins, CPubKey pubkey, bool &hasPubkey, bool &hasOtherPubkey) {
hasPubkey = false;
hasOtherPubkey = false;
for (auto vin : vins) {
CPubKey vinPubkey = check_signing_pubkey(vin.scriptSig);
if (vinPubkey.IsValid()) {
if (vinPubkey == pubkey)
hasPubkey = true;
if (vinPubkey != pubkey)
hasOtherPubkey = true;
}
}
}
/** /**
* find the latest funding tx: it may be the first F tx or one of A or C tx's * find the latest funding tx: it may be the first F tx or one of A or C tx's
* Note: this function is also called from validation code (use non-locking calls) * Note: this function is also called from validation code (use non-locking calls)
@@ -471,10 +490,20 @@ uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &toke
if (tmpFuncId != 0 && fundingtxid == fundingTxidInOpret && (tokenid == zeroid || tokenid == tokenidInOpret)) { // check tokenid also if (tmpFuncId != 0 && fundingtxid == fundingTxidInOpret && (tokenid == zeroid || tokenid == tokenidInOpret)) { // check tokenid also
if (blockHeight > maxBlockHeight) { if (blockHeight > maxBlockHeight) {
// check owner pubkey in vins
bool isOwner = false;
bool isNonOwner = false;
CheckVinPubkey(regtx.vin, ownerPubkey, isOwner, isNonOwner);
// we ignore 'donations' tx (with non-owner inputs) for calculating if heir is allowed to spend:
if (isOwner && !isNonOwner) {
hasHeirSpendingBegun = hasHeirSpendingBegunInOpret;
maxBlockHeight = blockHeight; maxBlockHeight = blockHeight;
latesttxid = txid; latesttxid = txid;
funcId = tmpFuncId; funcId = tmpFuncId;
hasHeirSpendingBegun = hasHeirSpendingBegunInOpret; }
//std::cerr << "FindLatestFundingTx() txid=" << latesttxid.GetHex() << " at blockHeight=" << maxBlockHeight //std::cerr << "FindLatestFundingTx() txid=" << latesttxid.GetHex() << " at blockHeight=" << maxBlockHeight
// << " opreturn type=" << (char)(funcId ? funcId : ' ') << " hasHeirSpendingBegun=" << (int)hasHeirSpendingBegun << " - set as current lasttxid" << '\n'; // << " opreturn type=" << (char)(funcId ? funcId : ' ') << " hasHeirSpendingBegun=" << (int)hasHeirSpendingBegun << " - set as current lasttxid" << '\n';
@@ -615,7 +644,7 @@ template <class Helper> int64_t LifetimeHeirContractFunds(struct CCcontract_info
* and also for setting spending plan for the funds' owner and heir * and also for setting spending plan for the funds' owner and heir
* @return fundingtxid handle for subsequent references to this heir funding plan * @return fundingtxid handle for subsequent references to this heir funding plan
*/ */
template <typename Helper> UniValue HeirFund(uint64_t txfee, int64_t amount, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid) template <typename Helper> UniValue _HeirFund(int64_t txfee, int64_t amount, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid)
{ {
UniValue result(UniValue::VOBJ); UniValue result(UniValue::VOBJ);
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
@@ -625,26 +654,32 @@ template <typename Helper> UniValue HeirFund(uint64_t txfee, int64_t amount, std
if (txfee == 0) if (txfee == 0)
txfee = 10000; txfee = 10000;
int64_t markerfee = 10000;
//std::cerr << "HeirFund() amount=" << amount << " txfee=" << txfee << " heirPubkey IsValid()=" << heirPubkey.IsValid() << " inactivityTime(sec)=" << inactivityTimeSec << " tokenid=" << tokenid.GetHex() << std::endl; //std::cerr << "HeirFund() amount=" << amount << " txfee=" << txfee << " heirPubkey IsValid()=" << heirPubkey.IsValid() << " inactivityTime(sec)=" << inactivityTimeSec << " tokenid=" << tokenid.GetHex() << std::endl;
if (!heirPubkey.IsValid()) { if (!heirPubkey.IsValid()) {
std::cerr << "HeirFund() heirPubkey is not valid!" << std::endl; std::cerr << "HeirFund() heirPubkey is not valid!" << std::endl;
return std::string(""); result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "invalid heir pubkey"));
} }
CPubKey myPubkey = pubkey2pk(Mypubkey()); CPubKey myPubkey = pubkey2pk(Mypubkey());
if (AddNormalinputs(mtx, myPubkey, txfee, 3) > 0) { // txfee for miners if (AddNormalinputs(mtx, myPubkey, markerfee, 3) > 0) {
int64_t inputs, change; int64_t inputs, change;
if ((inputs=Helper::addOwnerInputs(tokenid, mtx, myPubkey, amount, (int32_t)64)) > 0) { // 2 x txfee: 1st for marker vout, 2nd to miners if ((inputs=Helper::addOwnerInputs(tokenid, mtx, myPubkey, amount, (int32_t)64)) > 0) {
//mtx.vout.push_back(MakeTokensCC1of2vout(/*Helper::getMyEval()*/EVAL_HEIR, amount, myPubkey, heirPubkey)); // add cryptocondition to spend amount for either pk
mtx.vout.push_back(Helper::make1of2Vout(amount, myPubkey, heirPubkey)); mtx.vout.push_back(Helper::make1of2Vout(amount, myPubkey, heirPubkey));
// add a marker for finding all plans in HeirList() // add a marker for finding all plans in HeirList()
// TODO: change marker either to cc or normal txidaddr unspendable // TODO: change marker either to cc or normal txidaddr unspendable
CPubKey heirUnspendablePubKey = GetUnspendable(cp, 0); struct CCcontract_info *cpHeir, heirC;
mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(heirUnspendablePubKey)) << OP_CHECKSIG)); // TODO: do we need this marker? cpHeir = CCinit(&heirC, EVAL_HEIR);
CPubKey heirUnspendablePubKey = GetUnspendable(cpHeir, 0);
// mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(heirUnspendablePubKey)) << OP_CHECKSIG)); <-- bad marker cause it was spendable by anyone
mtx.vout.push_back(MakeCC1vout(EVAL_HEIR, markerfee, heirUnspendablePubKey)); // this marker spending is disabled in the validation code
// calc and add change vout: // calc and add change vout:
if (inputs > amount) if (inputs > amount)
@@ -656,6 +691,19 @@ template <typename Helper> UniValue HeirFund(uint64_t txfee, int64_t amount, std
mtx.vout.push_back(Helper::makeUserVout(change, myPubkey)); mtx.vout.push_back(Helper::makeUserVout(change, myPubkey));
} }
// check owner pubkey in vins
bool hasMypubkey = false;
bool hasNotMypubkey = false;
CheckVinPubkey(mtx.vin, myPubkey, hasMypubkey, hasNotMypubkey);
// for initial funding do not allow to sign by non-owner key:
if (hasNotMypubkey) {
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "using non-owner inputs not allowed"));
return result;
}
// add 1of2 vout validation pubkeys: // add 1of2 vout validation pubkeys:
std::vector<CPubKey> voutTokenPubkeys; std::vector<CPubKey> voutTokenPubkeys;
voutTokenPubkeys.push_back(myPubkey); voutTokenPubkeys.push_back(myPubkey);
@@ -689,12 +737,12 @@ template <typename Helper> UniValue HeirFund(uint64_t txfee, int64_t amount, std
} }
// if no these callers - it could not link // if no these callers - it could not link
UniValue HeirFundCoinCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid){ UniValue HeirFundCoinCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid){
return HeirFund<CoinHelper>(txfee, funds, heirName, heirPubkey, inactivityTimeSec, tokenid); return _HeirFund<CoinHelper>(txfee, satoshis, heirName, heirPubkey, inactivityTimeSec, tokenid);
} }
UniValue HeirFundTokenCaller(uint64_t txfee, int64_t funds, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid) { UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid) {
return HeirFund<TokenHelper>(txfee, funds, heirName, heirPubkey, inactivityTimeSec, tokenid); return _HeirFund<TokenHelper>(txfee, satoshis, heirName, heirPubkey, inactivityTimeSec, tokenid);
} }
/** /**
@@ -702,7 +750,7 @@ UniValue HeirFundTokenCaller(uint64_t txfee, int64_t funds, std::string heirName
* creates tx to add more funds to cryptocondition address for spending by either funds' owner or heir * creates tx to add more funds to cryptocondition address for spending by either funds' owner or heir
* @return result object with raw tx or error text * @return result object with raw tx or error text
*/ */
template <class Helper> UniValue _HeirAdd(uint256 fundingtxid, uint64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, uint8_t hasHeirSpendingBegun) template <class Helper> UniValue _HeirAdd(uint256 fundingtxid, int64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, uint8_t hasHeirSpendingBegun)
{ {
UniValue result(UniValue::VOBJ); UniValue result(UniValue::VOBJ);
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
@@ -715,6 +763,8 @@ template <class Helper> UniValue _HeirAdd(uint256 fundingtxid, uint64_t txfee, i
if (txfee == 0) if (txfee == 0)
txfee = 10000; txfee = 10000;
int64_t markerfee = 10000;
CPubKey myPubkey = pubkey2pk(Mypubkey()); CPubKey myPubkey = pubkey2pk(Mypubkey());
// check if it is the owner // check if it is the owner
@@ -724,7 +774,7 @@ template <class Helper> UniValue _HeirAdd(uint256 fundingtxid, uint64_t txfee, i
return result; return result;
} }
if (AddNormalinputs(mtx, myPubkey, txfee, 3) > 0) { // txfee for miners if (AddNormalinputs(mtx, myPubkey, markerfee, 3) > 0) { // some for marker
int64_t inputs, change; int64_t inputs, change;
@@ -740,6 +790,10 @@ template <class Helper> UniValue _HeirAdd(uint256 fundingtxid, uint64_t txfee, i
// add cryptocondition to spend this funded amount for either pk // add cryptocondition to spend this funded amount for either pk
mtx.vout.push_back(Helper::make1of2Vout(amount, ownerPubkey, heirPubkey)); mtx.vout.push_back(Helper::make1of2Vout(amount, ownerPubkey, heirPubkey));
char markeraddr[64];
CPubKey markerPubkey = CCtxidaddr(markeraddr, fundingtxid);
mtx.vout.push_back(CTxOut(markerfee, CScript() << ParseHex(HexStr(markerPubkey)) << OP_CHECKSIG)); // marker to prevent archiving of the funds add vouts
if (inputs > amount) if (inputs > amount)
change = (inputs - amount); // -txfee <-- txfee pays user change = (inputs - amount); // -txfee <-- txfee pays user
@@ -749,6 +803,28 @@ template <class Helper> UniValue _HeirAdd(uint256 fundingtxid, uint64_t txfee, i
mtx.vout.push_back(Helper::makeUserVout(change, myPubkey)); mtx.vout.push_back(Helper::makeUserVout(change, myPubkey));
} }
// check owner pubkey in vins
bool hasMypubkey = false;
bool hasNotMypubkey = false;
CheckVinPubkey(mtx.vin, myPubkey, hasMypubkey, hasNotMypubkey);
// for additional funding do not allow to sign by both owner and non-owner keys (is this a donation or not?):
if (hasMypubkey && hasNotMypubkey) {
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "using both owner and non-owner inputs is not allowed"));
return result;
}
// warn the user he's making a donation if this is all non-owner keys:
if (hasNotMypubkey) {
result.push_back(Pair("result", "warning"));
result.push_back(Pair("warning", "you are about to make a donation to heir fund"));
}
else {
result.push_back(Pair("result", "success"));
}
// add 1of2 vout validation pubkeys - needed only for tokens: // add 1of2 vout validation pubkeys - needed only for tokens:
std::vector<CPubKey> voutTokenPubkeys; std::vector<CPubKey> voutTokenPubkeys;
voutTokenPubkeys.push_back(ownerPubkey); voutTokenPubkeys.push_back(ownerPubkey);
@@ -759,11 +835,11 @@ template <class Helper> UniValue _HeirAdd(uint256 fundingtxid, uint64_t txfee, i
Helper::makeAddOpRet(tokenid, voutTokenPubkeys, fundingtxid, hasHeirSpendingBegun))); Helper::makeAddOpRet(tokenid, voutTokenPubkeys, fundingtxid, hasHeirSpendingBegun)));
if (!rawhextx.empty()) { if (!rawhextx.empty()) {
result.push_back(Pair("result", "success"));
result.push_back(Pair("hextx", rawhextx)); result.push_back(Pair("hextx", rawhextx));
} }
else { else {
std::cerr << "HeirAdd error in FinalizeCCtx" << std::endl; std::cerr << "HeirAdd error in FinalizeCCtx" << std::endl;
result.clear();
result.push_back(Pair("result", "error")); result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "sign error")); result.push_back(Pair("error", "sign error"));
} }
@@ -781,13 +857,11 @@ template <class Helper> UniValue _HeirAdd(uint256 fundingtxid, uint64_t txfee, i
result.push_back(Pair("error", "can't find normal inputs for tx fee")); result.push_back(Pair("error", "can't find normal inputs for tx fee"));
} }
return result; return result;
} }
UniValue HeirAddCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount) { UniValue HeirAddCaller(uint256 fundingtxid, int64_t txfee, std::string strAmount) {
CPubKey ownerPubkey, heirPubkey; CPubKey ownerPubkey, heirPubkey;
int64_t inactivityTimeSec; int64_t inactivityTimeSec;
@@ -798,11 +872,28 @@ UniValue HeirAddCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount) {
uint8_t hasHeirSpendingBegun = 0; uint8_t hasHeirSpendingBegun = 0;
if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun)) != zeroid) { if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun)) != zeroid) {
if (tokenid == zeroid) if (tokenid == zeroid) {
int64_t amount = (int64_t)(atof(strAmount.c_str()) * COIN);
if (amount <= 0) {
UniValue result(UniValue::VOBJ);
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "invalid amount"));
return result;
}
return _HeirAdd<CoinHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); return _HeirAdd<CoinHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun);
else }
else {
int64_t amount = atoll(strAmount.c_str());
if (amount <= 0) {
UniValue result(UniValue::VOBJ);
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "invalid amount"));
return result;
}
return _HeirAdd<TokenHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); return _HeirAdd<TokenHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun);
} }
}
else { else {
UniValue result(UniValue::VOBJ); UniValue result(UniValue::VOBJ);
@@ -819,7 +910,7 @@ UniValue HeirAddCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount) {
* creates tx to spend funds from cryptocondition address by either funds' owner or heir * creates tx to spend funds from cryptocondition address by either funds' owner or heir
* @return result object with raw tx or error text * @return result object with raw tx or error text
*/ */
template <typename Helper>UniValue _HeirClaim(uint256 fundingtxid, uint64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, uint8_t hasHeirSpendingBegun) template <typename Helper>UniValue _HeirClaim(uint256 fundingtxid, int64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, uint8_t hasHeirSpendingBegun)
{ {
UniValue result(UniValue::VOBJ); UniValue result(UniValue::VOBJ);
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight()); CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
@@ -940,7 +1031,7 @@ template <typename Helper>UniValue _HeirClaim(uint256 fundingtxid, uint64_t txfe
return result; return result;
} }
UniValue HeirClaimCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount) { UniValue HeirClaimCaller(uint256 fundingtxid, int64_t txfee, std::string strAmount) {
CPubKey ownerPubkey, heirPubkey; CPubKey ownerPubkey, heirPubkey;
int64_t inactivityTimeSec; int64_t inactivityTimeSec;
@@ -951,10 +1042,26 @@ UniValue HeirClaimCaller(uint256 fundingtxid, uint64_t txfee, int64_t amount) {
uint8_t hasHeirSpendingBegun = 0; uint8_t hasHeirSpendingBegun = 0;
if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun)) != zeroid) { if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun)) != zeroid) {
if( tokenid == zeroid ) if (tokenid == zeroid) {
int64_t amount = (int64_t)(atof(strAmount.c_str()) * COIN);
if (amount < 0) {
UniValue result(UniValue::VOBJ);
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "invalid amount"));
return result;
}
return _HeirClaim<CoinHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); return _HeirClaim<CoinHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun);
else }
else {
int64_t amount = atoll(strAmount.c_str());
if (amount <= 0) {
UniValue result(UniValue::VOBJ);
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "invalid amount"));
return result;
}
return _HeirClaim<TokenHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun); return _HeirClaim<TokenHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun);
}
} }
else { else {
@@ -1022,6 +1129,8 @@ UniValue HeirInfo(uint256 fundingtxid)
std::ostringstream stream; std::ostringstream stream;
std::string msg; std::string msg;
//sleep(10);
result.push_back(Pair("fundingtxid", fundingtxid.GetHex())); result.push_back(Pair("fundingtxid", fundingtxid.GetHex()));
result.push_back(Pair("name", heirName.c_str())); result.push_back(Pair("name", heirName.c_str()));
@@ -1052,7 +1161,7 @@ UniValue HeirInfo(uint256 fundingtxid)
if (tokenid == zeroid) { if (tokenid == zeroid) {
msg = "funding total in coins"; msg = "funding total in coins";
stream << (double)total / COIN; stream << std::fixed << std::setprecision(8) << (double)total / COIN;
} }
else { else {
msg = "funding total in tokens"; msg = "funding total in tokens";
@@ -1070,7 +1179,7 @@ UniValue HeirInfo(uint256 fundingtxid)
if (tokenid == zeroid) { if (tokenid == zeroid) {
msg = "funding available in coins"; msg = "funding available in coins";
stream << (double)inputs / COIN; stream << std::fixed << std::setprecision(8) << (double)inputs / COIN;
} }
else { else {
msg = "funding available in tokens"; msg = "funding available in tokens";
@@ -1090,13 +1199,13 @@ UniValue HeirInfo(uint256 fundingtxid)
} }
stream << inactivityTimeSec; stream << inactivityTimeSec;
result.push_back(Pair("inactivity time setting", stream.str().c_str())); result.push_back(Pair("inactivity time setting, sec", stream.str().c_str()));
stream.str(""); stream.str("");
stream.clear(); stream.clear();
if (!hasHeirSpendingBegun) { // we do not need find duration if the spending already has begun if (!hasHeirSpendingBegun) { // we do not need find duration if the spending already has begun
durationSec = CCduration(numblocks, latestFundingTxid); durationSec = CCduration(numblocks, latestFundingTxid);
std::cerr << "HeirInfo() duration=" << durationSec << " inactivityTime=" << inactivityTimeSec << " numblocks=" << numblocks << '\n'; std::cerr << "HeirInfo() duration (sec)=" << durationSec << " inactivityTime (sec)=" << inactivityTimeSec << " numblocks=" << numblocks << '\n';
} }
stream << std::boolalpha << (hasHeirSpendingBegun || durationSec > inactivityTimeSec); stream << std::boolalpha << (hasHeirSpendingBegun || durationSec > inactivityTimeSec);
@@ -1104,6 +1213,14 @@ UniValue HeirInfo(uint256 fundingtxid)
stream.str(""); stream.str("");
stream.clear(); stream.clear();
// adding owner current inactivity time:
if (!hasHeirSpendingBegun && durationSec <= inactivityTimeSec) {
stream << durationSec;
result.push_back(Pair("owner inactivity time, sec", stream.str().c_str()));
stream.str("");
stream.clear();
}
result.push_back(Pair("result", "success")); result.push_back(Pair("result", "success"));
} }
else { else {
@@ -1123,15 +1240,15 @@ UniValue HeirInfo(uint256 fundingtxid)
* @return list of heir plan handles (fundingtxid) * @return list of heir plan handles (fundingtxid)
*/ */
template <typename Helper>void _HeirList(struct CCcontract_info *cp, UniValue &result) void _HeirList(struct CCcontract_info *cp, UniValue &result)
{ {
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue>> unspentOutputs; std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue>> unspentOutputs;
char coinaddr[64]; char markeraddr[64];
CPubKey ccPubKeyEmpty;
GetCCaddress(cp, coinaddr, ccPubKeyEmpty);
SetCCunspents(unspentOutputs, cp->normaladdr);
//std::cerr << "HeirList() finding heir marker from Heir contract addr=" << cp->normaladdr << " unspentOutputs.size()=" << unspentOutputs.size() << '\n'; GetCCaddress(cp, markeraddr, GetUnspendable(cp, NULL));
SetCCunspents(unspentOutputs, markeraddr);
//std::cerr << "HeirList() finding heir marker from unspendable addr=" << markeraddr << " unspentOutputs.size()=" << unspentOutputs.size() << '\n';
// TODO: move marker to special cc addr to prevent checking all tokens // TODO: move marker to special cc addr to prevent checking all tokens
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue>>::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++) { for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue>>::const_iterator it = unspentOutputs.begin(); it != unspentOutputs.end(); it++) {
@@ -1177,10 +1294,10 @@ UniValue HeirList()
struct CCcontract_info *cpHeir, *cpTokens, heirC, tokenC; // NOTE we must use a separate 'C' structure for each CCinit! struct CCcontract_info *cpHeir, *cpTokens, heirC, tokenC; // NOTE we must use a separate 'C' structure for each CCinit!
cpHeir = CCinit(&heirC, EVAL_HEIR); cpHeir = CCinit(&heirC, EVAL_HEIR);
cpTokens = CCinit(&tokenC, EVAL_TOKENS); //cpTokens = CCinit(&tokenC, EVAL_TOKENS);
_HeirList<CoinHelper>(cpHeir, result); _HeirList(cpHeir, result);
_HeirList<TokenHelper>(cpTokens, result); //_HeirList<TokenHelper>(cpTokens, result); not used anymore
return result; return result;
} }

View File

@@ -125,8 +125,8 @@ class CValidatorBase
public: public:
CValidatorBase(CCcontract_info* cp) : m_cp(cp) {} CValidatorBase(CCcontract_info* cp) : m_cp(cp) {}
virtual bool isVinValidator() const = 0; virtual bool isVinValidator() const = 0;
virtual bool validateVin(CTxIn vin, CTxOut prevVout, std::string& message) const = 0; virtual bool validateVin(CTxIn vin, std::vector<CTxOut> prevVout, int32_t prevN, std::string& message) const = 0;
virtual bool validateVout(CTxOut vout, std::string& message) const = 0; virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const = 0;
protected: protected:
CCcontract_info * m_cp; CCcontract_info * m_cp;
@@ -258,10 +258,10 @@ private:
if (v->isVinValidator()) if (v->isVinValidator())
// validate this vin and previous vout: // validate this vin and previous vout:
result = v->validateVin(pTx->vin[iv], pPrevTx->vout[pTx->vin[iv].prevout.n], refMessage); result = v->validateVin(pTx->vin[iv], pPrevTx->vout, pTx->vin[iv].prevout.n, refMessage);
else else
// if it is vout validator pass the previous tx vout: // if it is vout validator pass the previous tx vout:
result = v->validateVout( pPrevTx->vout[pTx->vin[iv].prevout.n], refMessage); result = v->validateVout( pPrevTx->vout[pTx->vin[iv].prevout.n], pTx->vin[iv].prevout.n, refMessage);
if (!result) { if (!result) {
return result; return result;
} }
@@ -359,7 +359,7 @@ private:
if (!v->isVinValidator()) { if (!v->isVinValidator()) {
// if this is a 'in' validation plan then pass the previous tx vout: // if this is a 'in' validation plan then pass the previous tx vout:
bool result = v->validateVout(pTx->vout[iv], refMessage); bool result = v->validateVout(pTx->vout[iv], iv, refMessage);
if (!result) if (!result)
return result; return result;
} }
@@ -402,7 +402,7 @@ public:
m_fundingOpretScript(opRetScript), m_customMessage(customMessage), CValidatorBase(cp) {} m_fundingOpretScript(opRetScript), m_customMessage(customMessage), CValidatorBase(cp) {}
virtual bool isVinValidator() const { return false; } virtual bool isVinValidator() const { return false; }
virtual bool validateVout(CTxOut vout, std::string& message) const virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const
{ {
//std::cerr << "CCC1of2AddressValidator::validateVout() entered" << std::endl; //std::cerr << "CCC1of2AddressValidator::validateVout() entered" << std::endl;
CPubKey ownerPubkey, heirPubkey; CPubKey ownerPubkey, heirPubkey;
@@ -438,7 +438,7 @@ public:
std::cerr << "CCC1of2AddressValidator::validateVout() exits with false: " << message << std::endl; std::cerr << "CCC1of2AddressValidator::validateVout() exits with false: " << message << std::endl;
return false; return false;
} }
virtual bool validateVin(CTxIn vin, CTxOut prevVout, std::string& message) const { return false; } virtual bool validateVin(CTxIn vin, std::vector<CTxOut> prevVout, int32_t prevN, std::string& message) const { return false; }
private: private:
CScript m_fundingOpretScript; CScript m_fundingOpretScript;
@@ -456,7 +456,7 @@ public:
: m_fundingOpretScript(opRetScript), m_checkNormals(checkNormals), CValidatorBase(cp) { } : m_fundingOpretScript(opRetScript), m_checkNormals(checkNormals), CValidatorBase(cp) { }
virtual bool isVinValidator() const { return false; } virtual bool isVinValidator() const { return false; }
virtual bool validateVout(CTxOut vout, std::string& message) const virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const
{ {
//std::cerr << "CMyPubkeyVoutValidator::validateVout() entered" << std::endl; //std::cerr << "CMyPubkeyVoutValidator::validateVout() entered" << std::endl;
@@ -498,7 +498,7 @@ public:
message = std::string("invalid pubkey"); message = std::string("invalid pubkey");
return false; return false;
} }
virtual bool validateVin(CTxIn vin, CTxOut prevVout, std::string& message) const { return true; } virtual bool validateVin(CTxIn vin, std::vector<CTxOut> prevVout, int32_t prevN, std::string& message) const { return true; }
private: private:
CScript m_fundingOpretScript; CScript m_fundingOpretScript;
@@ -516,7 +516,7 @@ public:
: m_fundingOpretScript(opRetScript), m_latesttxid(latesttxid), m_isHeirSpendingBegan(isHeirSpendingBegan), CValidatorBase(cp) {} : m_fundingOpretScript(opRetScript), m_latesttxid(latesttxid), m_isHeirSpendingBegan(isHeirSpendingBegan), CValidatorBase(cp) {}
virtual bool isVinValidator() const { return false; } virtual bool isVinValidator() const { return false; }
virtual bool validateVout(CTxOut vout, std::string& message) const virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const
{ {
//std::cerr << "CHeirSpendValidator::validateVout() entered" << std::endl; //std::cerr << "CHeirSpendValidator::validateVout() entered" << std::endl;
@@ -554,7 +554,7 @@ public:
// this is not heir: // this is not heir:
return true; return true;
} }
virtual bool validateVin(CTxIn vin, CTxOut prevVout, std::string& message) const { return true; } virtual bool validateVin(CTxIn vin, std::vector<CTxOut> prevVout, int32_t prevN, std::string& message) const { return true; }
private: private:
CScript m_fundingOpretScript; CScript m_fundingOpretScript;
@@ -572,7 +572,7 @@ public:
: m_fundingOpretScript(opret), CValidatorBase(cp) {} : m_fundingOpretScript(opret), CValidatorBase(cp) {}
virtual bool isVinValidator() const { return false; } virtual bool isVinValidator() const { return false; }
virtual bool validateVout(CTxOut vout, std::string& message) const virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const
{ {
//std::cerr << "COpRetValidator::validateVout() entered" << std::endl; //std::cerr << "COpRetValidator::validateVout() entered" << std::endl;
@@ -607,12 +607,48 @@ public:
//std::cerr << "COpRetValidator::validateVout() exits with true" << std::endl; //std::cerr << "COpRetValidator::validateVout() exits with true" << std::endl;
return true; return true;
} }
virtual bool validateVin(CTxIn vin, CTxOut prevVout, std::string& message) const { return true; } virtual bool validateVin(CTxIn vin, std::vector<CTxOut> prevVout, int32_t prevN, std::string& message) const { return true; }
private: private:
CScript m_fundingOpretScript; CScript m_fundingOpretScript;
}; };
/**
* marker spending prevention validator,
* returns false if for tx with funcid=F vout.1 is being tried to spend
*/
template <class Helper> class CMarkerValidator : CValidatorBase
{
public:
CMarkerValidator(CCcontract_info* cp)
: CValidatorBase(cp) { }
virtual bool isVinValidator() const { return true; } // this is vin validator
virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const { return true; }
virtual bool validateVin(CTxIn vin, std::vector<CTxOut> prevVout, int32_t prevN, std::string& message) const {
uint256 fundingTxidInOpret = zeroid, dummyTxid, tokenid = zeroid, initialTokenid = zeroid;
uint8_t dummyIsHeirSpendingBegan;
//std::cerr << "CMarkerValidator::validateVin() prevVout.size()=" << prevVout.size() << " prevN=" << prevN << std::endl;
if (prevVout.size() > 0) {
// get funcId for prev tx:
uint8_t funcId = DecodeHeirEitherOpRet(prevVout[prevVout.size()-1].scriptPubKey, tokenid, fundingTxidInOpret, dummyIsHeirSpendingBegan, true);
//std::cerr << "CMarkerValidator::validateVin() funcId=" << (funcId?funcId:' ') << std::endl;
if (funcId == 'F' && prevN == 1) { // do not allow to spend 'F' marker's vout
message = std::string("spending marker not allowed");
return false;
}
}
//std::cerr << "CMarkerValidator::validateVin() exits with true" << std::endl;
return true;
}
};
/** /**
* empty validator always returns true * empty validator always returns true
*/ */
@@ -623,8 +659,8 @@ public:
: CValidatorBase(cp) { } : CValidatorBase(cp) { }
virtual bool isVinValidator() const { return false; } virtual bool isVinValidator() const { return false; }
virtual bool validateVout(CTxOut vout, std::string& message) const { return true; } virtual bool validateVout(CTxOut vout, int32_t vout_n, std::string& message) const { return true; }
virtual bool validateVin(CTxIn vin, CTxOut prevVout, std::string& message) const { return true; } virtual bool validateVin(CTxIn vin, std::vector<CTxOut> prevVout, int32_t prevN, std::string& message) const { return true; }
}; };

View File

@@ -94,7 +94,7 @@ uint8_t DecodeMaramaraCoinbaseOpRet(const CScript scriptPubKey,CPubKey &pk,int32
{ {
return(script[1]); return(script[1]);
} else fprintf(stderr,"DecodeMaramaraCoinbaseOpRet unmarshal error for %c\n",script[1]); } else fprintf(stderr,"DecodeMaramaraCoinbaseOpRet unmarshal error for %c\n",script[1]);
} else fprintf(stderr,"script[1] is %d != 'C' %d or 'P' %d or 'L' %d\n",script[1],'C','P','L'); } //else fprintf(stderr,"script[1] is %d != 'C' %d or 'P' %d or 'L' %d\n",script[1],'C','P','L');
} else fprintf(stderr,"vopret.size() is %d\n",(int32_t)vopret.size()); } else fprintf(stderr,"vopret.size() is %d\n",(int32_t)vopret.size());
return(0); return(0);
} }
@@ -255,6 +255,22 @@ int32_t MarmaraValidateCoinbase(int32_t height,CTransaction tx)
return(-1); return(-1);
} }
bool MarmaraPoScheck(char *destaddr,CScript opret,CTransaction staketx)
{
CPubKey Marmarapk,pk; int32_t height,unlockht; uint8_t funcid; char coinaddr[64]; struct CCcontract_info *cp,C;
//fprintf(stderr,"%s numvins.%d numvouts.%d %.8f opret[%d]\n",staketx.GetHash().ToString().c_str(),(int32_t)staketx.vin.size(),(int32_t)staketx.vout.size(),(double)staketx.vout[0].nValue/COIN,(int32_t)opret.size());
if ( staketx.vout.size() == 2 && opret == staketx.vout[1].scriptPubKey )
{
cp = CCinit(&C,EVAL_MARMARA);
funcid = DecodeMaramaraCoinbaseOpRet(opret,pk,height,unlockht);
Marmarapk = GetUnspendable(cp,0);
GetCCaddress1of2(cp,coinaddr,Marmarapk,pk);
//fprintf(stderr,"matched opret! funcid.%c ht.%d unlock.%d %s\n",funcid,height,unlockht,coinaddr);
return(strcmp(destaddr,coinaddr) == 0);
}
return(0);
}
bool MarmaraValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn) bool MarmaraValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
{ {
std::vector<uint8_t> vopret; CTransaction vinTx; uint256 hashBlock; int32_t numvins,numvouts,i,ht,unlockht,vht,vunlockht; uint8_t funcid,vfuncid,*script; CPubKey pk,vpk; std::vector<uint8_t> vopret; CTransaction vinTx; uint256 hashBlock; int32_t numvins,numvouts,i,ht,unlockht,vht,vunlockht; uint8_t funcid,vfuncid,*script; CPubKey pk,vpk;
@@ -318,6 +334,10 @@ bool MarmaraValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t
{ {
return(true); return(true);
} }
else if ( funcid == 'C' ) // coinbase
{
return(true);
}
// staking only for locked utxo // staking only for locked utxo
} }
return eval->Invalid("fall through error"); return eval->Invalid("fall through error");
@@ -476,7 +496,7 @@ UniValue MarmaraLock(uint64_t txfee,int64_t amount,int32_t height)
else else
{ {
result.push_back(Pair("result",(char *)"success")); result.push_back(Pair("result",(char *)"success"));
result.push_back(Pair("rawtx",rawtx)); result.push_back(Pair("hex",rawtx));
return(result); return(result);
} }
} else errorstr = (char *)"insufficient funds"; } else errorstr = (char *)"insufficient funds";
@@ -485,7 +505,34 @@ UniValue MarmaraLock(uint64_t txfee,int64_t amount,int32_t height)
return(result); return(result);
} }
// jl777: decide on what unlockht settlement change should have int32_t MarmaraSignature(uint8_t *utxosig,CMutableTransaction &mtx)
{
uint256 txid,hashBlock; uint8_t *ptr; int32_t i,siglen,vout,numvouts; CTransaction tx; std::string rawtx; CPubKey mypk; std::vector<CPubKey> pubkeys; struct CCcontract_info *cp,C; uint64_t txfee;
txfee = 10000;
vout = mtx.vin[0].prevout.n;
if ( GetTransaction(mtx.vin[0].prevout.hash,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 1 && vout < numvouts )
{
cp = CCinit(&C,EVAL_MARMARA);
mypk = pubkey2pk(Mypubkey());
pubkeys.push_back(mypk);
rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,tx.vout[numvouts - 1].scriptPubKey,pubkeys);
if ( rawtx.size() > 0 )
{
siglen = mtx.vin[0].scriptSig.size();
ptr = &mtx.vin[0].scriptSig[0];
for (i=0; i<siglen; i++)
{
utxosig[i] = ptr[i];
//fprintf(stderr,"%02x",ptr[i]);
}
//fprintf(stderr," got signed rawtx.%s siglen.%d\n",rawtx.c_str(),siglen);
return(siglen);
}
}
return(0);
}
// jl777: decide on what unlockht settlement change should have -> from utxo making change
UniValue MarmaraSettlement(uint64_t txfee,uint256 refbatontxid) UniValue MarmaraSettlement(uint64_t txfee,uint256 refbatontxid)
{ {
@@ -553,7 +600,7 @@ UniValue MarmaraSettlement(uint64_t txfee,uint256 refbatontxid)
mtx.vout.push_back(MakeCC1of2vout(EVAL_MARMARA,change,Marmarapk,pk)); mtx.vout.push_back(MakeCC1of2vout(EVAL_MARMARA,change,Marmarapk,pk));
rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,MarmaraLoopOpret('S',createtxid,mypk,0,refmatures,currency),pubkeys); rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,MarmaraLoopOpret('S',createtxid,mypk,0,refmatures,currency),pubkeys);
result.push_back(Pair("result",(char *)"success")); result.push_back(Pair("result",(char *)"success"));
result.push_back(Pair("rawtx",rawtx)); result.push_back(Pair("hex",rawtx));
return(result); return(result);
} else remaining -= inputsum; } else remaining -= inputsum;
if ( mtx.vin.size() >= CC_MAXVINS - MARMARA_VINS ) if ( mtx.vin.size() >= CC_MAXVINS - MARMARA_VINS )
@@ -569,7 +616,7 @@ UniValue MarmaraSettlement(uint64_t txfee,uint256 refbatontxid)
rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,MarmaraLoopOpret('D',createtxid,mypk,-remaining,refmatures,currency),pubkeys); rawtx = FinalizeCCTx(0,cp,mtx,mypk,txfee,MarmaraLoopOpret('D',createtxid,mypk,-remaining,refmatures,currency),pubkeys);
result.push_back(Pair("result",(char *)"error")); result.push_back(Pair("result",(char *)"error"));
result.push_back(Pair("error",(char *)"insufficient funds")); result.push_back(Pair("error",(char *)"insufficient funds"));
result.push_back(Pair("rawtx",rawtx)); result.push_back(Pair("hex",rawtx));
result.push_back(Pair("remaining",ValueFromAmount(remaining))); result.push_back(Pair("remaining",ValueFromAmount(remaining)));
} }
else else
@@ -684,7 +731,7 @@ UniValue MarmaraReceive(uint64_t txfee,CPubKey senderpk,int64_t amount,std::stri
else else
{ {
result.push_back(Pair("result",(char *)"success")); result.push_back(Pair("result",(char *)"success"));
result.push_back(Pair("rawtx",rawtx)); result.push_back(Pair("hex",rawtx));
result.push_back(Pair("funcid","R")); result.push_back(Pair("funcid","R"));
result.push_back(Pair("createtxid",createtxid.GetHex())); result.push_back(Pair("createtxid",createtxid.GetHex()));
if ( batontxid != zeroid ) if ( batontxid != zeroid )
@@ -740,7 +787,7 @@ UniValue MarmaraIssue(uint64_t txfee,uint8_t funcid,CPubKey receiverpk,int64_t a
else else
{ {
result.push_back(Pair("result",(char *)"success")); result.push_back(Pair("result",(char *)"success"));
result.push_back(Pair("rawtx",rawtx)); result.push_back(Pair("hex",rawtx));
char str[2]; str[0] = funcid, str[1] = 0; char str[2]; str[0] = funcid, str[1] = 0;
result.push_back(Pair("funcid",str)); result.push_back(Pair("funcid",str));
result.push_back(Pair("createtxid",createtxid.GetHex())); result.push_back(Pair("createtxid",createtxid.GetHex()));
@@ -978,7 +1025,7 @@ UniValue MarmaraPoolPayout(uint64_t txfee,int32_t firstheight,double perc,char *
else else
{ {
result.push_back(Pair("result",(char *)"success")); result.push_back(Pair("result",(char *)"success"));
result.push_back(Pair("rawtx",rawtx)); result.push_back(Pair("hex",rawtx));
if ( totalpayout > 0 && total > totalpayout-txfee ) if ( totalpayout > 0 && total > totalpayout-txfee )
{ {
result.push_back(Pair("firstheight",firstheight)); result.push_back(Pair("firstheight",firstheight));

View File

@@ -115,6 +115,7 @@ enum BlockStatus: uint32_t {
BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD, BLOCK_FAILED_MASK = BLOCK_FAILED_VALID | BLOCK_FAILED_CHILD,
BLOCK_ACTIVATES_UPGRADE = 128, //! block activates a network upgrade BLOCK_ACTIVATES_UPGRADE = 128, //! block activates a network upgrade
BLOCK_IN_TMPFILE = 256
}; };
//! Short-hand for the highest consensus validity we implement. //! Short-hand for the highest consensus validity we implement.
@@ -350,7 +351,7 @@ public:
nSolution = block.nSolution; nSolution = block.nSolution;
} }
int32_t SetHeight(int32_t height) void SetHeight(int32_t height)
{ {
this->chainPower.nHeight = height; this->chainPower.nHeight = height;
} }

View File

@@ -92,11 +92,6 @@ static CBlock CreateGenesisBlock(uint32_t nTime, const uint256& nNonce, const st
void *chainparams_commandline(void *ptr); void *chainparams_commandline(void *ptr);
#include "komodo_defs.h" #include "komodo_defs.h"
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
extern uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT;
extern uint32_t ASSETCHAIN_INIT, ASSETCHAINS_MAGIC;
extern int32_t VERUS_BLOCK_POSUNITS, ASSETCHAINS_LWMAPOS, ASSETCHAINS_SAPLING, ASSETCHAINS_OVERWINTER;
extern uint64_t ASSETCHAINS_SUPPLY, ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH, ASSETCHAINS_VERUSHASH;
const arith_uint256 maxUint = UintToArith256(uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")); const arith_uint256 maxUint = UintToArith256(uint256S("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
@@ -230,11 +225,32 @@ void CChainParams::SetCheckpointData(CChainParams::CCheckpointData checkpointDat
CChainParams::checkpointData = checkpointData; CChainParams::checkpointData = checkpointData;
} }
int32_t MAX_BLOCK_SIZE(int32_t height) // make sure to change MAX_PROTOCOL_MESSAGE_LENGTH also!!!! /*
To change the max block size, all that needs to be updated is the #define _MAX_BLOCK_SIZE in utils.h
However, doing that without any other changes will allow forking non-updated nodes by creating a larger block. So, make sure to height activate the new blocksize properly.
Assuming it is 8MB, then:
#define _OLD_MAX_BLOCK_SIZE (4096 * 1024)
#define _MAX_BLOCK_SIZE (2 * 4096 * 1024)
change the body of if:
{ {
if ( height < saplinght+1000000 ) // activates 8MB blocks 1 million blocks after saplinght
return(_OLD_MAX_BLOCK_SIZE);
else return(_MAX_BLOCK_SIZE);
}
*/
int32_t MAX_BLOCK_SIZE(int32_t height)
{
int32_t saplinght = mainParams.consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight;
//fprintf(stderr,"MAX_BLOCK_SIZE %d vs. %d\n",height,mainParams.consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight); //fprintf(stderr,"MAX_BLOCK_SIZE %d vs. %d\n",height,mainParams.consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight);
if ( height <= 0 || (mainParams.consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight > 0 && height >= mainParams.consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight) ) if ( height <= 0 || (saplinght > 0 && height >= saplinght) )
return(4096 * 1024); {
return(_MAX_BLOCK_SIZE);
}
else return(2000000); else return(2000000);
} }

View File

@@ -130,8 +130,8 @@ struct Params {
int64_t AveragingWindowTimespan() const { return nPowAveragingWindow * nPowTargetSpacing; } int64_t AveragingWindowTimespan() const { return nPowAveragingWindow * nPowTargetSpacing; }
int64_t MinActualTimespan() const { return (AveragingWindowTimespan() * (100 - nPowMaxAdjustUp )) / 100; } int64_t MinActualTimespan() const { return (AveragingWindowTimespan() * (100 - nPowMaxAdjustUp )) / 100; }
int64_t MaxActualTimespan() const { return (AveragingWindowTimespan() * (100 + nPowMaxAdjustDown)) / 100; } int64_t MaxActualTimespan() const { return (AveragingWindowTimespan() * (100 + nPowMaxAdjustDown)) / 100; }
int32_t SetSaplingHeight(int32_t height) { vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = height; } void SetSaplingHeight(int32_t height) { vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = height; }
int32_t SetOverwinterHeight(int32_t height) { vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = height; } void SetOverwinterHeight(int32_t height) { vUpgrades[Consensus::UPGRADE_OVERWINTER].nActivationHeight = height; }
uint256 nMinimumChainWork; uint256 nMinimumChainWork;
}; };
} // namespace Consensus } // namespace Consensus

View File

@@ -86,6 +86,7 @@ class CVerusHashV2
result = buf2; result = buf2;
curPos = 0; curPos = 0;
std::fill(buf1, buf1 + sizeof(buf1), 0); std::fill(buf1, buf1 + sizeof(buf1), 0);
return *this;
} }
int64_t *ExtraI64Ptr() { return (int64_t *)(curBuf + 32); } int64_t *ExtraI64Ptr() { return (int64_t *)(curBuf + 32); }

View File

@@ -707,6 +707,10 @@ int32_t komodo_voutupdate(int32_t *isratificationp,int32_t notaryid,uint8_t *scr
komodo_stateupdate(height,0,0,0,zero,0,0,0,0,0,0,0,0,0,0,sp->MoM,sp->MoMdepth); komodo_stateupdate(height,0,0,0,zero,0,0,0,0,0,0,0,0,0,0,sp->MoM,sp->MoMdepth);
if ( ASSETCHAINS_SYMBOL[0] != 0 ) if ( ASSETCHAINS_SYMBOL[0] != 0 )
printf("[%s] ht.%d NOTARIZED.%d %s.%s %sTXID.%s lens.(%d %d) MoM.%s %d\n",ASSETCHAINS_SYMBOL,height,*notarizedheightp,ASSETCHAINS_SYMBOL[0]==0?"KMD":ASSETCHAINS_SYMBOL,srchash.ToString().c_str(),ASSETCHAINS_SYMBOL[0]==0?"BTC":"KMD",desttxid.ToString().c_str(),opretlen,len,sp->MoM.ToString().c_str(),sp->MoMdepth); printf("[%s] ht.%d NOTARIZED.%d %s.%s %sTXID.%s lens.(%d %d) MoM.%s %d\n",ASSETCHAINS_SYMBOL,height,*notarizedheightp,ASSETCHAINS_SYMBOL[0]==0?"KMD":ASSETCHAINS_SYMBOL,srchash.ToString().c_str(),ASSETCHAINS_SYMBOL[0]==0?"BTC":"KMD",desttxid.ToString().c_str(),opretlen,len,sp->MoM.ToString().c_str(),sp->MoMdepth);
if (RemoveOrphanedBlocks(*notarizedheightp))
{
//fprintf(stderr, "Sucessfully removed all known orphaned blocks before height %d\n",*notarizedheightp);
}
if ( ASSETCHAINS_SYMBOL[0] == 0 ) if ( ASSETCHAINS_SYMBOL[0] == 0 )
{ {
if ( signedfp == 0 ) if ( signedfp == 0 )
@@ -947,6 +951,8 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block)
} }
} }
} }
if ( ASSETCHAINS_SYMBOL[0] != 0 || height < 100000 )
{
if ( ((signedmask & 1) != 0 && numvalid >= KOMODO_MINRATIFY) || bitweight(signedmask) > (numnotaries/3) ) if ( ((signedmask & 1) != 0 && numvalid >= KOMODO_MINRATIFY) || bitweight(signedmask) > (numnotaries/3) )
{ {
memset(&txhash,0,sizeof(txhash)); memset(&txhash,0,sizeof(txhash));
@@ -956,6 +962,7 @@ void komodo_connectblock(CBlockIndex *pindex,CBlock& block)
} }
} }
} }
}
if ( IS_KOMODO_NOTARY != 0 && ASSETCHAINS_SYMBOL[0] == 0 ) if ( IS_KOMODO_NOTARY != 0 && ASSETCHAINS_SYMBOL[0] == 0 )
printf("%s ht.%d\n",ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL,height); printf("%s ht.%d\n",ASSETCHAINS_SYMBOL[0] == 0 ? "KMD" : ASSETCHAINS_SYMBOL,height);
if ( pindex->GetHeight() == hwmheight ) if ( pindex->GetHeight() == hwmheight )

View File

@@ -557,9 +557,9 @@ uint64_t komodo_seed(int32_t height)
return(seed); return(seed);
} }
uint32_t komodo_txtime(uint64_t *valuep,uint256 hash, int32_t n, char *destaddr) uint32_t komodo_txtime(CScript &opret,uint64_t *valuep,uint256 hash, int32_t n, char *destaddr)
{ {
CTxDestination address; CTransaction tx; uint256 hashBlock; CTxDestination address; CTransaction tx; uint256 hashBlock; int32_t numvouts;
*valuep = 0; *valuep = 0;
if (!GetTransaction(hash, tx, if (!GetTransaction(hash, tx,
#ifndef KOMODO_ZCASH #ifndef KOMODO_ZCASH
@@ -570,10 +570,12 @@ uint32_t komodo_txtime(uint64_t *valuep,uint256 hash, int32_t n, char *destaddr)
//fprintf(stderr,"ERROR: %s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime); //fprintf(stderr,"ERROR: %s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
return(0); return(0);
} }
numvouts = tx.vout.size();
//fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime); //fprintf(stderr,"%s/v%d locktime.%u\n",hash.ToString().c_str(),n,(uint32_t)tx.nLockTime);
if ( n < tx.vout.size() ) if ( n < numvouts )
{ {
*valuep = tx.vout[n].nValue; *valuep = tx.vout[n].nValue;
opret = tx.vout[numvouts-1].scriptPubKey;
if (ExtractDestination(tx.vout[n].scriptPubKey, address)) if (ExtractDestination(tx.vout[n].scriptPubKey, address))
strcpy(destaddr,CBitcoinAddress(address).ToString().c_str()); strcpy(destaddr,CBitcoinAddress(address).ToString().c_str());
} }
@@ -614,12 +616,12 @@ uint32_t komodo_txtime2(uint64_t *valuep,uint256 hash,int32_t n,char *destaddr)
int32_t komodo_WhoStaked(CBlock *pblock, CTxDestination &addressout) int32_t komodo_WhoStaked(CBlock *pblock, CTxDestination &addressout)
{ {
int32_t n,vout; uint32_t txtime; uint64_t value; char voutaddr[64],destaddr[64]; CTxDestination voutaddress; uint256 txid; int32_t n,vout; uint32_t txtime; uint64_t value; char voutaddr[64],destaddr[64]; CTxDestination voutaddress; uint256 txid; CScript opret;
if ( (n= pblock->vtx.size()) > 1 && pblock->vtx[n-1].vin.size() == 1 && pblock->vtx[n-1].vout.size() == 1 ) if ( (n= pblock->vtx.size()) > 1 && pblock->vtx[n-1].vin.size() == 1 && pblock->vtx[n-1].vout.size() == 1 )
{ {
txid = pblock->vtx[n-1].vin[0].prevout.hash; txid = pblock->vtx[n-1].vin[0].prevout.hash;
vout = pblock->vtx[n-1].vin[0].prevout.n; vout = pblock->vtx[n-1].vin[0].prevout.n;
txtime = komodo_txtime(&value,txid,vout,destaddr); txtime = komodo_txtime(opret,&value,txid,vout,destaddr);
if ( ExtractDestination(pblock->vtx[n-1].vout[0].scriptPubKey,voutaddress) ) if ( ExtractDestination(pblock->vtx[n-1].vout[0].scriptPubKey,voutaddress) )
{ {
strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str()); strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
@@ -634,27 +636,41 @@ int32_t komodo_WhoStaked(CBlock *pblock, CTxDestination &addressout)
return(0); return(0);
} }
int32_t komodo_isPoS(CBlock *pblock) bool MarmaraPoScheck(char *destaddr,CScript opret,CTransaction staketx);
int32_t komodo_isPoS(CBlock *pblock,int32_t height)
{ {
int32_t n,vout; uint32_t txtime; uint64_t value; char voutaddr[64],destaddr[64]; CTxDestination voutaddress; uint256 txid; int32_t n,vout,numvouts; uint32_t txtime; uint64_t value; char voutaddr[64],destaddr[64]; CTxDestination voutaddress; uint256 txid; CScript opret;
if ( ASSETCHAINS_STAKED != 0 ) if ( ASSETCHAINS_STAKED != 0 )
{ {
if ( (n= pblock->vtx.size()) > 1 && pblock->vtx[n-1].vin.size() == 1 && pblock->vtx[n-1].vout.size() == 1 ) n = pblock->vtx.size();
//fprintf(stderr,"ht.%d check for PoS numtx.%d numvins.%d numvouts.%d\n",height,n,(int32_t)pblock->vtx[n-1].vin.size(),(int32_t)pblock->vtx[n-1].vout.size());
if ( n > 1 && pblock->vtx[n-1].vin.size() == 1 && pblock->vtx[n-1].vout.size() == 1+(ASSETCHAINS_MARMARA!=0) )
{ {
txid = pblock->vtx[n-1].vin[0].prevout.hash; txid = pblock->vtx[n-1].vin[0].prevout.hash;
vout = pblock->vtx[n-1].vin[0].prevout.n; vout = pblock->vtx[n-1].vin[0].prevout.n;
if ( ASSETCHAINS_MARMARA != 0 ) txtime = komodo_txtime(opret,&value,txid,vout,destaddr);
{
// need to verify it was signed by the non-Marmarapk of the 1of2
}
txtime = komodo_txtime(&value,txid,vout,destaddr);
if ( ExtractDestination(pblock->vtx[n-1].vout[0].scriptPubKey,voutaddress) ) if ( ExtractDestination(pblock->vtx[n-1].vout[0].scriptPubKey,voutaddress) )
{ {
strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str()); strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
if ( strcmp(destaddr,voutaddr) == 0 && pblock->vtx[n-1].vout[0].nValue == value ) //fprintf(stderr,"voutaddr.%s vs destaddr.%s\n",voutaddr,destaddr);
if ( pblock->vtx[n-1].vout[0].nValue == value && strcmp(destaddr,voutaddr) == 0 )
{ {
//fprintf(stderr,"is PoS block!\n"); if ( ASSETCHAINS_MARMARA == 0 )
return(1); return(1);
else
{
if ( pblock->vtx[n-1].vout[0].scriptPubKey.IsPayToCryptoCondition() != 0 && (numvouts= pblock->vtx[n-1].vout.size()) == 2 )
{
//fprintf(stderr,"validate proper %s %s signature and unlockht preservation\n",voutaddr,destaddr);
return(MarmaraPoScheck(destaddr,opret,pblock->vtx[n-1]));
}
else
{
fprintf(stderr,"reject ht.%d PoS block\n",height);
return(strcmp(ASSETCHAINS_SYMBOL,"MTST2") == 0); // allow until MTST3
}
}
} }
} }
} }
@@ -1194,7 +1210,7 @@ uint32_t komodo_segid32(char *coinaddr)
int8_t komodo_segid(int32_t nocache,int32_t height) int8_t komodo_segid(int32_t nocache,int32_t height)
{ {
CTxDestination voutaddress; CBlock block; CBlockIndex *pindex; uint64_t value; uint32_t txtime; char voutaddr[64],destaddr[64]; int32_t txn_count,vout; uint256 txid; int8_t segid = -1; CTxDestination voutaddress; CBlock block; CBlockIndex *pindex; uint64_t value; uint32_t txtime; char voutaddr[64],destaddr[64]; int32_t txn_count,vout; uint256 txid; CScript opret; int8_t segid = -1;
if ( height > 0 && (pindex= komodo_chainactive(height)) != 0 ) if ( height > 0 && (pindex= komodo_chainactive(height)) != 0 )
{ {
if ( nocache == 0 && pindex->segid >= -1 ) if ( nocache == 0 && pindex->segid >= -1 )
@@ -1206,7 +1222,7 @@ int8_t komodo_segid(int32_t nocache,int32_t height)
{ {
txid = block.vtx[txn_count-1].vin[0].prevout.hash; txid = block.vtx[txn_count-1].vin[0].prevout.hash;
vout = block.vtx[txn_count-1].vin[0].prevout.n; vout = block.vtx[txn_count-1].vin[0].prevout.n;
txtime = komodo_txtime(&value,txid,vout,destaddr); txtime = komodo_txtime(opret,&value,txid,vout,destaddr);
if ( ExtractDestination(block.vtx[txn_count-1].vout[0].scriptPubKey,voutaddress) ) if ( ExtractDestination(block.vtx[txn_count-1].vout[0].scriptPubKey,voutaddress) )
{ {
strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str()); strcpy(voutaddr,CBitcoinAddress(voutaddress).ToString().c_str());
@@ -1448,12 +1464,14 @@ int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_
pindex = it != mapBlockIndex.end() ? it->second : NULL; pindex = it != mapBlockIndex.end() ? it->second : NULL;
if ( pindex != 0 && pindex->segid >= -1 ) if ( pindex != 0 && pindex->segid >= -1 )
{ {
//fprintf(stderr,"isPoSblock segid.%d\n",pindex->segid);
if ( pindex->segid == -1 ) if ( pindex->segid == -1 )
return(0); return(0);
else return(1); else return(1);
} }
txn_count = pblock->vtx.size(); txn_count = pblock->vtx.size();
if ( txn_count > 1 && pblock->vtx[txn_count-1].vin.size() == 1 && pblock->vtx[txn_count-1].vout.size() == 1 ) //fprintf(stderr,"checkblock n.%d vins.%d vouts.%d %.8f %.8f\n",txn_count,(int32_t)pblock->vtx[txn_count-1].vin.size(),(int32_t)pblock->vtx[txn_count-1].vout.size(),(double)pblock->vtx[txn_count-1].vout[0].nValue/COIN,(double)pblock->vtx[txn_count-1].vout[1].nValue/COIN);
if ( txn_count > 1 && pblock->vtx[txn_count-1].vin.size() == 1 && pblock->vtx[txn_count-1].vout.size() == 1 + (ASSETCHAINS_MARMARA!=0) )
{ {
it = mapBlockIndex.find(pblock->hashPrevBlock); it = mapBlockIndex.find(pblock->hashPrevBlock);
if ( it != mapBlockIndex.end() && (previndex = it->second) != NULL ) if ( it != mapBlockIndex.end() && (previndex = it->second) != NULL )
@@ -1463,7 +1481,7 @@ int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_
vout = pblock->vtx[txn_count-1].vin[0].prevout.n; vout = pblock->vtx[txn_count-1].vin[0].prevout.n;
if ( prevtime != 0 ) if ( prevtime != 0 )
{ {
if ( komodo_isPoS(pblock) != 0 ) if ( komodo_isPoS(pblock,height) != 0 )
{ {
eligible = komodo_stake(1,bnTarget,height,txid,vout,pblock->nTime,prevtime+27,(char *)""); eligible = komodo_stake(1,bnTarget,height,txid,vout,pblock->nTime,prevtime+27,(char *)"");
} }
@@ -1499,7 +1517,7 @@ int32_t komodo_is_PoSblock(int32_t slowflag,int32_t height,CBlock *pblock,arith_
} }
if ( slowflag == 0 && isPoS == 0 ) // maybe previous block is not seen yet, do the best approx if ( slowflag == 0 && isPoS == 0 ) // maybe previous block is not seen yet, do the best approx
{ {
if ( komodo_isPoS(pblock) != 0 ) if ( komodo_isPoS(pblock,height) != 0 )
isPoS = 1; isPoS = 1;
} }
if ( slowflag != 0 && isPoS != 0 ) if ( slowflag != 0 && isPoS != 0 )
@@ -1812,6 +1830,7 @@ int32_t komodo_checkPOW(int32_t slowflag,CBlock *pblock,int32_t height)
return(-1); return(-1);
} }
} }
//fprintf(stderr,"ASSETCHAINS_STAKED.%d ht.%d\n",(int32_t)ASSETCHAINS_STAKED,height);
if ( ASSETCHAINS_STAKED != 0 && height >= 2 ) // must PoS or have at least 16x better PoW if ( ASSETCHAINS_STAKED != 0 && height >= 2 ) // must PoS or have at least 16x better PoW
{ {
if ( (is_PoSblock= komodo_is_PoSblock(slowflag,height,pblock,bnTarget,bhash)) == 0 ) if ( (is_PoSblock= komodo_is_PoSblock(slowflag,height,pblock,bnTarget,bhash)) == 0 )
@@ -2068,6 +2087,9 @@ uint32_t komodo_eligible(arith_uint256 bnTarget,arith_uint256 ratio,struct komod
return(0); return(0);
} }
int32_t MarmaraSignature(uint8_t *utxosig,CMutableTransaction &txNew);
uint8_t DecodeMaramaraCoinbaseOpRet(const CScript scriptPubKey,CPubKey &pk,int32_t &height,int32_t &unlockht);
int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig) int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blocktimep,uint32_t *txtimep,uint256 *utxotxidp,int32_t *utxovoutp,uint64_t *utxovaluep,uint8_t *utxosig)
{ {
static struct komodo_staking *array; static int32_t numkp,maxkp; static uint32_t lasttime; static struct komodo_staking *array; static int32_t numkp,maxkp; static uint32_t lasttime;
@@ -2098,7 +2120,9 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt
{ {
CBlockIndex* pblockindex = chainActive[tipindex->GetHeight()]; CBlockIndex* pblockindex = chainActive[tipindex->GetHeight()];
CBlock block; CTxDestination addressout; CBlock block; CTxDestination addressout;
if( ReadBlockFromDisk(block, pblockindex, 1) && komodo_WhoStaked(&block, addressout) != 0 && IsMine(*pwalletMain,addressout) != 0 ) if ( ASSETCHAINS_MARMARA != 0 )
resetstaker = true;
else if( ReadBlockFromDisk(block, pblockindex, 1) && komodo_WhoStaked(&block, addressout) != 0 && IsMine(*pwalletMain,addressout) != 0 )
{ {
resetstaker = true; resetstaker = true;
fprintf(stderr, "Reset ram staker after mining a block!\n"); fprintf(stderr, "Reset ram staker after mining a block!\n");
@@ -2116,7 +2140,7 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt
maxkp = numkp = 0; maxkp = numkp = 0;
lasttime = 0; lasttime = 0;
} }
if ( ASSETCHAINS_MARMARA == 0 || 1 ) if ( ASSETCHAINS_MARMARA == 0 )
{ {
BOOST_FOREACH(const COutput& out, vecOutputs) BOOST_FOREACH(const COutput& out, vecOutputs)
{ {
@@ -2149,8 +2173,29 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt
} }
else else
{ {
// calc 1of2 address struct CCcontract_info *cp,C; uint256 txid; int32_t vout,ht,unlockht; CAmount nValue; char coinaddr[64]; CPubKey mypk,Marmarapk,pk;
// iterate all unspents not spent in mempool and komodo_addutxo std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
cp = CCinit(&C,EVAL_MARMARA);
mypk = pubkey2pk(Mypubkey());
Marmarapk = GetUnspendable(cp,0);
GetCCaddress1of2(cp,coinaddr,Marmarapk,mypk);
SetCCunspents(unspentOutputs,coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
if ( (nValue= it->second.satoshis) < COIN )
continue;
if ( GetTransaction(txid,tx,hashBlock,true) != 0 && (pindex= komodo_getblockindex(hashBlock)) != 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
{
const CScript &scriptPubKey = tx.vout[vout].scriptPubKey;
if ( DecodeMaramaraCoinbaseOpRet(tx.vout[tx.vout.size()-1].scriptPubKey,pk,ht,unlockht) != 0 && pk == mypk )
{
array = komodo_addutxo(array,&numkp,&maxkp,(uint32_t)pindex->nTime,(uint64_t)nValue,txid,vout,coinaddr,hashbuf,(CScript)scriptPubKey);
}
// else fprintf(stderr,"SKIP addutxo %.8f numkp.%d vs max.%d\n",(double)nValue/COIN,numkp,maxkp);
}
}
} }
lasttime = (uint32_t)time(NULL); lasttime = (uint32_t)time(NULL);
//fprintf(stderr,"finished kp data of utxo for staking %u ht.%d numkp.%d maxkp.%d\n",(uint32_t)time(NULL),nHeight,numkp,maxkp); //fprintf(stderr,"finished kp data of utxo for staking %u ht.%d numkp.%d maxkp.%d\n",(uint32_t)time(NULL),nHeight,numkp,maxkp);
@@ -2230,24 +2275,26 @@ int32_t komodo_staked(CMutableTransaction &txNew,uint32_t nBits,uint32_t *blockt
txNew.vout[0].nValue = *utxovaluep - txfee; txNew.vout[0].nValue = *utxovaluep - txfee;
txNew.nLockTime = earliest; txNew.nLockTime = earliest;
CTransaction txNewConst(txNew); CTransaction txNewConst(txNew);
if ( ASSETCHAINS_MARMARA == 0 || 1 ) if ( ASSETCHAINS_MARMARA == 0 )
{ {
signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, *utxovaluep, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId); signSuccess = ProduceSignature(TransactionSignatureCreator(&keystore, &txNewConst, 0, *utxovaluep, SIGHASH_ALL), best_scriptPubKey, sigdata, consensusBranchId);
}
else
{
// add opreturn
// signSuccess = CCFinalizetx(...)
}
if (!signSuccess)
fprintf(stderr,"failed to create signature\n");
else
{
UpdateTransaction(txNew,0,sigdata); UpdateTransaction(txNew,0,sigdata);
ptr = (uint8_t *)&sigdata.scriptSig[0]; ptr = (uint8_t *)&sigdata.scriptSig[0];
siglen = sigdata.scriptSig.size(); siglen = sigdata.scriptSig.size();
for (i=0; i<siglen; i++) for (i=0; i<siglen; i++)
utxosig[i] = ptr[i];//, fprintf(stderr,"%02x",ptr[i]); utxosig[i] = ptr[i];//, fprintf(stderr,"%02x",ptr[i]);
}
else
{
siglen = MarmaraSignature(utxosig,txNew);
if ( siglen > 0 )
signSuccess = true;
else signSuccess = false;
}
if (!signSuccess)
fprintf(stderr,"failed to create signature\n");
else
{
//fprintf(stderr," siglen.%d\n",siglen); //fprintf(stderr," siglen.%d\n",siglen);
//fprintf(stderr,"best %u from %u, gap %d lag.%d\n",earliest,*blocktimep,(int32_t)(earliest - *blocktimep),(int32_t)(time(NULL) - *blocktimep)); //fprintf(stderr,"best %u from %u, gap %d lag.%d\n",earliest,*blocktimep,(int32_t)(earliest - *blocktimep),(int32_t)(time(NULL) - *blocktimep));
*blocktimep = earliest; *blocktimep = earliest;

View File

@@ -36,5 +36,43 @@
extern uint8_t ASSETCHAINS_TXPOW,ASSETCHAINS_PUBLIC; extern uint8_t ASSETCHAINS_TXPOW,ASSETCHAINS_PUBLIC;
int32_t MAX_BLOCK_SIZE(int32_t height); int32_t MAX_BLOCK_SIZE(int32_t height);
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
extern uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT;
extern uint32_t ASSETCHAIN_INIT, ASSETCHAINS_MAGIC;
extern int32_t VERUS_BLOCK_POSUNITS, ASSETCHAINS_LWMAPOS, ASSETCHAINS_SAPLING, ASSETCHAINS_OVERWINTER;
extern uint64_t ASSETCHAINS_SUPPLY;
extern uint64_t ASSETCHAINS_TIMELOCKGTE;
extern uint32_t ASSETCHAINS_ALGO, ASSETCHAINS_VERUSHASH,ASSETCHAINS_EQUIHASH,KOMODO_INITDONE;
extern int32_t KOMODO_MININGTHREADS,KOMODO_LONGESTCHAIN,ASSETCHAINS_SEED,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,KOMODO_ON_DEMAND,KOMODO_PASSPORT_INITDONE;
extern uint64_t ASSETCHAINS_COMMISSION, ASSETCHAINS_STAKED;
extern bool VERUS_MINTBLOCKS;
extern uint64_t ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_TIMELOCKGTE, ASSETCHAINS_NONCEMASK[];
extern const char *ASSETCHAINS_ALGORITHMS[];
extern int32_t VERUS_MIN_STAKEAGE;
extern uint32_t ASSETCHAINS_VERUSHASH, ASSETCHAINS_LASTERA, ASSETCHAINS_NONCESHIFT[], ASSETCHAINS_HASHESPERROUND[];
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 char ASSETCHAINS_SYMBOL[65];
extern int32_t VERUS_BLOCK_POSUNITS, VERUS_CONSECUTIVE_POS_THRESHOLD, VERUS_NOPOS_THRESHHOLD;
extern int32_t KOMODO_CONNECTING,KOMODO_CCACTIVATE,KOMODO_DEALERNODE;
extern uint32_t ASSETCHAINS_CC;
extern char ASSETCHAINS_SYMBOL[];
extern std::string CCerror,ASSETCHAINS_CCLIB;
extern uint8_t ASSETCHAINS_CCDISABLES[256];
extern int32_t USE_EXTERNAL_PUBKEY;
extern std::string NOTARY_PUBKEY;
extern int32_t KOMODO_EXCHANGEWALLET;
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
extern int32_t VERUS_MIN_STAKEAGE;
extern std::string DONATION_PUBKEY;
extern uint8_t ASSETCHAINS_PRIVATE;
extern int32_t USE_EXTERNAL_PUBKEY;
#endif #endif

View File

@@ -1654,7 +1654,7 @@ extern int64_t MAX_MONEY;
void komodo_args(char *argv0) void komodo_args(char *argv0)
{ {
extern const char *Notaries_elected1[][2]; extern const char *Notaries_elected1[][2];
std::string name,addn; 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,baseid,len,n,extralen = 0; uint64_t ccenables[256]; std::string name,addn; 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_KOMODO_NOTARY = GetBoolArg("-notary", false);
memset(ccenables,0,sizeof(ccenables)); memset(ccenables,0,sizeof(ccenables));
memset(disablebits,0,sizeof(disablebits)); memset(disablebits,0,sizeof(disablebits));
@@ -1704,7 +1704,6 @@ void komodo_args(char *argv0)
KOMODO_STOPAT = GetArg("-stopat",0); KOMODO_STOPAT = GetArg("-stopat",0);
MAX_REORG_LENGTH = GetArg("-maxreorg",MAX_REORG_LENGTH); MAX_REORG_LENGTH = GetArg("-maxreorg",MAX_REORG_LENGTH);
WITNESS_CACHE_SIZE = MAX_REORG_LENGTH+10; WITNESS_CACHE_SIZE = MAX_REORG_LENGTH+10;
ASSETCHAINS_CC = GetArg("-ac_cc",0); ASSETCHAINS_CC = GetArg("-ac_cc",0);
KOMODO_CCACTIVATE = GetArg("-ac_ccactivate",0); KOMODO_CCACTIVATE = GetArg("-ac_ccactivate",0);
ASSETCHAINS_PUBLIC = GetArg("-ac_public",0); ASSETCHAINS_PUBLIC = GetArg("-ac_public",0);

View File

@@ -76,6 +76,7 @@ using namespace std;
* Global state * Global state
*/ */
#define TMPFILE_START 100000000
CCriticalSection cs_main; CCriticalSection cs_main;
extern uint8_t NOTARY_PUBKEY33[33]; extern uint8_t NOTARY_PUBKEY33[33];
extern int32_t KOMODO_LOADINGBLOCKS,KOMODO_LONGESTCHAIN,KOMODO_INSYNC,KOMODO_CONNECTING,KOMODO_EXTRASATOSHI; extern int32_t KOMODO_LOADINGBLOCKS,KOMODO_LONGESTCHAIN,KOMODO_INSYNC,KOMODO_CONNECTING,KOMODO_EXTRASATOSHI;
@@ -182,8 +183,9 @@ namespace {
multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked; multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
CCriticalSection cs_LastBlockFile; CCriticalSection cs_LastBlockFile;
std::vector<CBlockFileInfo> vinfoBlockFile; std::vector<CBlockFileInfo> vinfoBlockFile,tmpBlockFiles;
int nLastBlockFile = 0; int nLastBlockFile = 0;
int nLastTmpFile = 0;
/** Global flag to indicate we should check to see if there are /** Global flag to indicate we should check to see if there are
* block/undo files that should be deleted. Set on startup * block/undo files that should be deleted. Set on startup
* or if we allocate more file space when we're in prune mode * or if we allocate more file space when we're in prune mode
@@ -1979,6 +1981,73 @@ bool GetAddressUnspent(uint160 addressHash, int type,
return true; return true;
} }
struct CompareBlocksByHeightMain
{
bool operator()(const CBlockIndex* a, const CBlockIndex* b) const
{
/* Make sure that unequal blocks with the same height do not compare
equal. Use the pointers themselves to make a distinction. */
if (a->GetHeight() != b->GetHeight())
return (a->GetHeight() > b->GetHeight());
return a < b;
}
};
bool RemoveOrphanedBlocks(int32_t notarized_height)
{
LOCK(cs_main);
std::vector<const CBlockIndex*> prunedblocks;
std::set<const CBlockIndex*, CompareBlocksByHeightMain> setTips;
int32_t m=0,n = 0;
// get notarised timestamp and use this as a backup incase the forked block has no height.
// we -600 to make sure the time is within future block constraints.
uint32_t notarized_timestamp = komodo_heightstamp(notarized_height)-600;
// Most of this code is a direct copy from GetChainTips RPC. Which gives a return of all
// blocks that are not in the main chain.
BOOST_FOREACH(const PAIRTYPE(const uint256, CBlockIndex*)& item, mapBlockIndex)
{
n++;
setTips.insert(item.second);
}
n = 0;
BOOST_FOREACH(const PAIRTYPE(const uint256, CBlockIndex*)& item, mapBlockIndex)
{
const CBlockIndex* pprev=0;
n++;
if ( item.second != 0 )
pprev = item.second->pprev;
if (pprev)
setTips.erase(pprev);
}
const CBlockIndex *forked;
BOOST_FOREACH(const CBlockIndex* block, setTips)
{
// We skip anything over notarised height to avoid breaking normal consensus rules.
if ( block->GetHeight() > notarized_height || block->nTime > notarized_timestamp )
continue;
// We can also check if the block is in the active chain as a backup test.
forked = chainActive.FindFork(block);
// Here we save each forked block to a vector for removal later.
if ( forked != 0 )
prunedblocks.push_back(block);
}
if (prunedblocks.size() > 0 && pblocktree->EraseBatchSync(prunedblocks))
{
// Blocks cleared from disk succesfully, using internal DB batch erase function. Which exists, but has never been used before.
// We need to try and clear the block index from mapBlockIndex now, otherwise node will need a restart.
BOOST_FOREACH(const CBlockIndex* block, prunedblocks)
{
m++;
mapBlockIndex.erase(block->GetBlockHash());
}
fprintf(stderr, "%s removed %d orphans from %d blocks before %d\n",ASSETCHAINS_SYMBOL,m,n, notarized_height);
return true;
}
return false;
}
/*uint64_t myGettxout(uint256 hash,int32_t n) /*uint64_t myGettxout(uint256 hash,int32_t n)
{ {
CCoins coins; CCoins coins;
@@ -2126,7 +2195,7 @@ bool GetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock
// CBlock and CBlockIndex // CBlock and CBlockIndex
// //
bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart) bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart)
{ {
// Open history file to append // Open history file to append
CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION); CAutoFile fileout(OpenBlockFile(pos), SER_DISK, CLIENT_VERSION);
@@ -3157,9 +3226,12 @@ static int64_t nTimeConnect = 0;
static int64_t nTimeIndex = 0; static int64_t nTimeIndex = 0;
static int64_t nTimeCallbacks = 0; static int64_t nTimeCallbacks = 0;
static int64_t nTimeTotal = 0; static int64_t nTimeTotal = 0;
bool FindBlockPos(int32_t tmpflag,CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false);
bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos);
bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck,bool fCheckPOW) bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pindex, CCoinsViewCache& view, bool fJustCheck,bool fCheckPOW)
{ {
CDiskBlockPos blockPos;
const CChainParams& chainparams = Params(); const CChainParams& chainparams = Params();
if ( KOMODO_STOPAT != 0 && pindex->GetHeight() > KOMODO_STOPAT ) if ( KOMODO_STOPAT != 0 && pindex->GetHeight() > KOMODO_STOPAT )
return(false); return(false);
@@ -3189,6 +3261,21 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin
return false; return false;
fprintf(stderr,"grandfathered exception, until jan 15th 2019\n"); fprintf(stderr,"grandfathered exception, until jan 15th 2019\n");
} }
if ( (pindex->nStatus & BLOCK_IN_TMPFILE) != 0 )
{
unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
if (!FindBlockPos(0,state, blockPos, nBlockSize+8, pindex->GetHeight(), block.GetBlockTime(),false))
return error("ConnectBlock(): FindBlockPos failed");
if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart()))
return error("ConnectBlock(): FindBlockPos failed");
pindex->nStatus &= (~BLOCK_IN_TMPFILE);
pindex->nFile = blockPos.nFile;
pindex->nDataPos = blockPos.nPos;
if (!ReceivedBlockTransactions(block, state, pindex, blockPos))
return error("AcceptBlock(): ReceivedBlockTransactions failed");
setDirtyFileInfo.insert(blockPos.nFile);
fprintf(stderr,"added ht.%d copy of tmpfile to %d.%d\n",pindex->GetHeight(),blockPos.nFile,blockPos.nPos);
}
// verify that the view's current state corresponds to the previous block // verify that the view's current state corresponds to the previous block
uint256 hashPrevBlock = pindex->pprev == NULL ? uint256() : pindex->pprev->GetBlockHash(); uint256 hashPrevBlock = pindex->pprev == NULL ? uint256() : pindex->pprev->GetBlockHash();
if ( hashPrevBlock != view.GetBestBlock() ) if ( hashPrevBlock != view.GetBestBlock() )
@@ -3806,7 +3893,7 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) {
CValidationState stateDummy; CValidationState stateDummy;
// don't keep staking or invalid transactions // don't keep staking or invalid transactions
if (tx.IsCoinBase() || ((i == (block.vtx.size() - 1)) && (ASSETCHAINS_STAKED && komodo_isPoS((CBlock *)&block) != 0)) || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL)) if (tx.IsCoinBase() || ((i == (block.vtx.size() - 1)) && (ASSETCHAINS_STAKED && komodo_isPoS((CBlock *)&block,pindexDelete->GetHeight()) != 0)) || !AcceptToMemoryPool(mempool, stateDummy, tx, false, NULL))
{ {
mempool.remove(tx, removed, true); mempool.remove(tx, removed, true);
} }
@@ -3837,7 +3924,7 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) {
{ {
CTransaction &tx = block.vtx[i]; CTransaction &tx = block.vtx[i];
//if ((i == (block.vtx.size() - 1)) && ((ASSETCHAINS_LWMAPOS && block.IsVerusPOSBlock()) || (ASSETCHAINS_STAKED != 0 && (komodo_isPoS((CBlock *)&block) != 0)))) //if ((i == (block.vtx.size() - 1)) && ((ASSETCHAINS_LWMAPOS && block.IsVerusPOSBlock()) || (ASSETCHAINS_STAKED != 0 && (komodo_isPoS((CBlock *)&block) != 0))))
if ((i == (block.vtx.size() - 1)) && (ASSETCHAINS_STAKED != 0 && (komodo_isPoS((CBlock *)&block) != 0))) if ((i == (block.vtx.size() - 1)) && (ASSETCHAINS_STAKED != 0 && (komodo_isPoS((CBlock *)&block,pindexDelete->GetHeight()) != 0)))
{ {
EraseFromWallets(tx.GetHash()); EraseFromWallets(tx.GetHash());
} }
@@ -3853,7 +3940,8 @@ bool static DisconnectTip(CValidationState &state, bool fBare = false) {
int32_t komodo_activate_sapling(CBlockIndex *pindex) int32_t komodo_activate_sapling(CBlockIndex *pindex)
{ {
uint32_t blocktime,prevtime; CBlockIndex *prev; int32_t i,transition=0,height,prevht,activation = 0; uint32_t blocktime,prevtime; CBlockIndex *prev; int32_t i,transition=0,height,prevht;
int32_t activation = 0;
if ( pindex == 0 ) if ( pindex == 0 )
{ {
fprintf(stderr,"komodo_activate_sapling null pindex\n"); fprintf(stderr,"komodo_activate_sapling null pindex\n");
@@ -3911,6 +3999,7 @@ int32_t komodo_activate_sapling(CBlockIndex *pindex)
fprintf(stderr,"%s sapling activation at %d\n",ASSETCHAINS_SYMBOL,activation); fprintf(stderr,"%s sapling activation at %d\n",ASSETCHAINS_SYMBOL,activation);
ASSETCHAINS_SAPLING = activation; ASSETCHAINS_SAPLING = activation;
} }
return activation;
} }
static int64_t nTimeReadFromDisk = 0; static int64_t nTimeReadFromDisk = 0;
@@ -4483,43 +4572,57 @@ bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBl
return true; return true;
} }
bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false) bool FindBlockPos(int32_t tmpflag,CValidationState &state, CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown)
{ {
std::vector<CBlockFileInfo> *ptr; int *lastfilep;
LOCK(cs_LastBlockFile); LOCK(cs_LastBlockFile);
unsigned int nFile = fKnown ? pos.nFile : nLastBlockFile; unsigned int nFile;
if ( tmpflag != 0 )
{
ptr = &tmpBlockFiles;
nFile = nLastTmpFile;
lastfilep = &nLastTmpFile;
}
else
{
ptr = &vinfoBlockFile;
lastfilep = &nLastBlockFile;
nFile = fKnown ? pos.nFile : nLastBlockFile;
if (vinfoBlockFile.size() <= nFile) { if (vinfoBlockFile.size() <= nFile) {
vinfoBlockFile.resize(nFile + 1); vinfoBlockFile.resize(nFile + 1);
} }
}
if (!fKnown) { if (!fKnown) {
while (vinfoBlockFile[nFile].nSize + nAddSize >= MAX_BLOCKFILE_SIZE) { while ((*ptr)[nFile].nSize + nAddSize >= MAX_BLOCKFILE_SIZE) {
nFile++; nFile++;
if (vinfoBlockFile.size() <= nFile) { if ((*ptr).size() <= nFile) {
vinfoBlockFile.resize(nFile + 1); (*ptr).resize(nFile + 1);
} }
} }
pos.nFile = nFile; pos.nFile = nFile + tmpflag*TMPFILE_START;
pos.nPos = vinfoBlockFile[nFile].nSize; pos.nPos = (*ptr)[nFile].nSize;
if ( 0 && tmpflag != 0 )
fprintf(stderr,"pos.nFile %d nPos %u\n",pos.nFile,pos.nPos);
} }
if (nFile != nLastBlockFile) { if (nFile != *lastfilep) {
if (!fKnown) { if (!fKnown) {
LogPrintf("Leaving block file %i: %s\n", nFile, vinfoBlockFile[nFile].ToString()); LogPrintf("Leaving block file %i: %s\n", nFile, (*ptr)[nFile].ToString());
} }
FlushBlockFile(!fKnown); FlushBlockFile(!fKnown);
nLastBlockFile = nFile; *lastfilep = nFile;
} }
vinfoBlockFile[nFile].AddBlock(nHeight, nTime); (*ptr)[nFile].AddBlock(nHeight, nTime);
if (fKnown) if (fKnown)
vinfoBlockFile[nFile].nSize = std::max(pos.nPos + nAddSize, vinfoBlockFile[nFile].nSize); (*ptr)[nFile].nSize = std::max(pos.nPos + nAddSize, (*ptr)[nFile].nSize);
else else
vinfoBlockFile[nFile].nSize += nAddSize; (*ptr)[nFile].nSize += nAddSize;
if (!fKnown) { if (!fKnown) {
unsigned int nOldChunks = (pos.nPos + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE; unsigned int nOldChunks = (pos.nPos + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE;
unsigned int nNewChunks = (vinfoBlockFile[nFile].nSize + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE; unsigned int nNewChunks = ((*ptr)[nFile].nSize + BLOCKFILE_CHUNK_SIZE - 1) / BLOCKFILE_CHUNK_SIZE;
if (nNewChunks > nOldChunks) { if (nNewChunks > nOldChunks) {
if (fPruneMode) if (fPruneMode)
fCheckForPruning = true; fCheckForPruning = true;
@@ -4536,19 +4639,26 @@ bool FindBlockPos(CValidationState &state, CDiskBlockPos &pos, unsigned int nAdd
} }
} }
setDirtyFileInfo.insert(nFile); setDirtyFileInfo.insert(nFile + tmpflag*TMPFILE_START);
return true; return true;
} }
bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize) bool FindUndoPos(CValidationState &state, int nFile, CDiskBlockPos &pos, unsigned int nAddSize)
{ {
pos.nFile = nFile; std::vector<CBlockFileInfo> *ptr; int *lastfilep;
LOCK(cs_LastBlockFile); LOCK(cs_LastBlockFile);
pos.nFile = nFile;
if ( nFile >= TMPFILE_START )
{
fprintf(stderr,"skip tmp undo\n");
return(false);
nFile %= TMPFILE_START;
ptr = &tmpBlockFiles;
} else ptr = &vinfoBlockFile;
unsigned int nNewSize; unsigned int nNewSize;
pos.nPos = vinfoBlockFile[nFile].nUndoSize; pos.nPos = (*ptr)[nFile].nUndoSize;
nNewSize = vinfoBlockFile[nFile].nUndoSize += nAddSize; nNewSize = (*ptr)[nFile].nUndoSize += nAddSize;
setDirtyFileInfo.insert(nFile); setDirtyFileInfo.insert(nFile);
unsigned int nOldChunks = (pos.nPos + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE; unsigned int nOldChunks = (pos.nPos + UNDOFILE_CHUNK_SIZE - 1) / UNDOFILE_CHUNK_SIZE;
@@ -4592,7 +4702,7 @@ bool CheckBlockHeader(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,
*futureblockp = 0; *futureblockp = 0;
if (blockhdr.GetBlockTime() > GetAdjustedTime() + 60) if (blockhdr.GetBlockTime() > GetAdjustedTime() + 60)
{ {
CBlockIndex *tipindex; /*CBlockIndex *tipindex;
//fprintf(stderr,"ht.%d future block %u vs time.%u + 60\n",height,(uint32_t)blockhdr.GetBlockTime(),(uint32_t)GetAdjustedTime()); //fprintf(stderr,"ht.%d future block %u vs time.%u + 60\n",height,(uint32_t)blockhdr.GetBlockTime(),(uint32_t)GetAdjustedTime());
if ( (tipindex= chainActive.Tip()) != 0 && tipindex->GetBlockHash() == blockhdr.hashPrevBlock && blockhdr.GetBlockTime() < GetAdjustedTime() + 60 + 5 ) if ( (tipindex= chainActive.Tip()) != 0 && tipindex->GetBlockHash() == blockhdr.hashPrevBlock && blockhdr.GetBlockTime() < GetAdjustedTime() + 60 + 5 )
{ {
@@ -4601,9 +4711,9 @@ bool CheckBlockHeader(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,
sleep(1); sleep(1);
//fprintf(stderr,"now its valid\n"); //fprintf(stderr,"now its valid\n");
} }
else else*/
{ {
if (blockhdr.GetBlockTime() < GetAdjustedTime() + 600) if (blockhdr.GetBlockTime() < GetAdjustedTime() + 300)
*futureblockp = 1; *futureblockp = 1;
//LogPrintf("CheckBlockHeader block from future %d error",blockhdr.GetBlockTime() - GetAdjustedTime()); //LogPrintf("CheckBlockHeader block from future %d error",blockhdr.GetBlockTime() - GetAdjustedTime());
return false; //state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"),REJECT_INVALID, "time-too-new"); return false; //state.Invalid(error("CheckBlockHeader(): block timestamp too far in the future"),REJECT_INVALID, "time-too-new");
@@ -4734,7 +4844,7 @@ bool CheckBlock(int32_t *futureblockp,int32_t height,CBlockIndex *pindex,const C
CValidationState state; CValidationState state;
CTransaction Tx; CTransaction Tx;
const CTransaction &tx = (CTransaction)block.vtx[i]; const CTransaction &tx = (CTransaction)block.vtx[i];
if (tx.IsCoinBase() || !tx.vjoinsplit.empty() || !tx.vShieldedSpend.empty() || ((i == (block.vtx.size() - 1)) && (ASSETCHAINS_STAKED && komodo_isPoS((CBlock *)&block) != 0))) if (tx.IsCoinBase() || !tx.vjoinsplit.empty() || !tx.vShieldedSpend.empty() || ((i == (block.vtx.size() - 1)) && (ASSETCHAINS_STAKED && komodo_isPoS((CBlock *)&block,height) != 0)))
continue; continue;
Tx = tx; Tx = tx;
if ( myAddtomempool(Tx, &state, true) == false ) // happens with out of order tx in block on resync if ( myAddtomempool(Tx, &state, true) == false ) // happens with out of order tx in block on resync
@@ -5098,19 +5208,22 @@ bool AcceptBlock(int32_t *futureblockp,CBlock& block, CValidationState& state, C
} }
int nHeight = pindex->GetHeight(); int nHeight = pindex->GetHeight();
int32_t usetmp = 0;
// Write block to history file // Write block to history file
try { try {
unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
CDiskBlockPos blockPos; CDiskBlockPos blockPos;
if (dbp != NULL) if (dbp != NULL)
blockPos = *dbp; blockPos = *dbp;
if (!FindBlockPos(state, blockPos, nBlockSize+8, nHeight, block.GetBlockTime(), dbp != NULL)) if (!FindBlockPos(usetmp,state, blockPos, nBlockSize+8, nHeight, block.GetBlockTime(), dbp != NULL))
return error("AcceptBlock(): FindBlockPos failed"); return error("AcceptBlock(): FindBlockPos failed");
if (dbp == NULL) if (dbp == NULL)
if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart()))
AbortNode(state, "Failed to write block"); AbortNode(state, "Failed to write block");
if (!ReceivedBlockTransactions(block, state, pindex, blockPos)) if (!ReceivedBlockTransactions(block, state, pindex, blockPos))
return error("AcceptBlock(): ReceivedBlockTransactions failed"); return error("AcceptBlock(): ReceivedBlockTransactions failed");
if ( usetmp != 0 ) // not during initialdownload or if futureflag==0 and contextchecks ok
pindex->nStatus |= BLOCK_IN_TMPFILE;
} catch (const std::runtime_error& e) { } catch (const std::runtime_error& e) {
return AbortNode(state, std::string("System error: ") + e.what()); return AbortNode(state, std::string("System error: ") + e.what());
} }
@@ -5428,7 +5541,7 @@ bool CheckDiskSpace(uint64_t nAdditionalBytes)
FILE* OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fReadOnly) FILE* OpenDiskFile(const CDiskBlockPos &pos, const char *prefix, bool fReadOnly)
{ {
static int32_t didinit[64]; static int32_t didinit[256];
if (pos.IsNull()) if (pos.IsNull())
return NULL; return NULL;
boost::filesystem::path path = GetBlockPosFilename(pos, prefix); boost::filesystem::path path = GetBlockPosFilename(pos, prefix);
@@ -5572,6 +5685,7 @@ bool static LoadBlockIndexDB()
// Load block file info // Load block file info
pblocktree->ReadLastBlockFile(nLastBlockFile); pblocktree->ReadLastBlockFile(nLastBlockFile);
vinfoBlockFile.resize(nLastBlockFile + 1); vinfoBlockFile.resize(nLastBlockFile + 1);
tmpBlockFiles.resize(nLastTmpFile + 1);
LogPrintf("%s: last block file = %i\n", __func__, nLastBlockFile); LogPrintf("%s: last block file = %i\n", __func__, nLastBlockFile);
for (int nFile = 0; nFile <= nLastBlockFile; nFile++) { for (int nFile = 0; nFile <= nLastBlockFile; nFile++) {
pblocktree->ReadBlockFileInfo(nFile, vinfoBlockFile[nFile]); pblocktree->ReadBlockFileInfo(nFile, vinfoBlockFile[nFile]);
@@ -5595,7 +5709,6 @@ bool static LoadBlockIndexDB()
if (pindex->nStatus & BLOCK_HAVE_DATA) { if (pindex->nStatus & BLOCK_HAVE_DATA) {
setBlkDataFiles.insert(pindex->nFile); setBlkDataFiles.insert(pindex->nFile);
} }
//komodo_pindex_init(pindex,(int32_t)pindex->GetHeight());
} }
//fprintf(stderr,"load blockindexDB %u\n",(uint32_t)time(NULL)); //fprintf(stderr,"load blockindexDB %u\n",(uint32_t)time(NULL));
for (std::set<int>::iterator it = setBlkDataFiles.begin(); it != setBlkDataFiles.end(); it++) for (std::set<int>::iterator it = setBlkDataFiles.begin(); it != setBlkDataFiles.end(); it++)
@@ -5936,6 +6049,7 @@ void UnloadBlockIndex()
nSyncStarted = 0; nSyncStarted = 0;
mapBlocksUnlinked.clear(); mapBlocksUnlinked.clear();
vinfoBlockFile.clear(); vinfoBlockFile.clear();
tmpBlockFiles.clear();
nLastBlockFile = 0; nLastBlockFile = 0;
nBlockSequenceId = 1; nBlockSequenceId = 1;
mapBlockSource.clear(); mapBlockSource.clear();
@@ -5971,6 +6085,7 @@ bool LoadBlockIndex()
bool InitBlockIndex() { bool InitBlockIndex() {
const CChainParams& chainparams = Params(); const CChainParams& chainparams = Params();
LOCK(cs_main); LOCK(cs_main);
tmpBlockFiles.clear();
// Initialize global variables that cannot be constructed at startup. // Initialize global variables that cannot be constructed at startup.
recentRejects.reset(new CRollingBloomFilter(120000, 0.000001)); recentRejects.reset(new CRollingBloomFilter(120000, 0.000001));
@@ -6003,7 +6118,7 @@ bool InitBlockIndex() {
unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION); unsigned int nBlockSize = ::GetSerializeSize(block, SER_DISK, CLIENT_VERSION);
CDiskBlockPos blockPos; CDiskBlockPos blockPos;
CValidationState state; CValidationState state;
if (!FindBlockPos(state, blockPos, nBlockSize+8, 0, block.GetBlockTime())) if (!FindBlockPos(0,state, blockPos, nBlockSize+8, 0, block.GetBlockTime()))
return error("LoadBlockIndex(): FindBlockPos failed"); return error("LoadBlockIndex(): FindBlockPos failed");
if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart())) if (!WriteBlockToDisk(block, blockPos, chainparams.MessageStart()))
return error("LoadBlockIndex(): writing genesis block to disk failed"); return error("LoadBlockIndex(): writing genesis block to disk failed");

View File

@@ -78,7 +78,7 @@ static const bool DEFAULT_ALERTS = true;
/** Minimum alert priority for enabling safe mode. */ /** Minimum alert priority for enabling safe mode. */
static const int ALERT_PRIORITY_SAFE_MODE = 4000; static const int ALERT_PRIORITY_SAFE_MODE = 4000;
/** Maximum reorg length we will accept before we shut down and alert the user. */ /** Maximum reorg length we will accept before we shut down and alert the user. */
static unsigned int MAX_REORG_LENGTH = (_COINBASE_MATURITY - 1); static unsigned int MAX_REORG_LENGTH = _COINBASE_MATURITY - 1;
/** Maximum number of signature check operations in an IsStandard() P2SH script */ /** Maximum number of signature check operations in an IsStandard() P2SH script */
static const unsigned int MAX_P2SH_SIGOPS = 15; static const unsigned int MAX_P2SH_SIGOPS = 15;
/** The maximum number of sigops we're willing to relay/mine in a single tx */ /** The maximum number of sigops we're willing to relay/mine in a single tx */
@@ -803,10 +803,10 @@ bool GetAddressUnspent(uint160 addressHash, int type,
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs); std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > &unspentOutputs);
/** Functions for disk access for blocks */ /** Functions for disk access for blocks */
bool WriteBlockToDisk(CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart); bool WriteBlockToDisk(const CBlock& block, CDiskBlockPos& pos, const CMessageHeader::MessageStartChars& messageStart);
bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos,bool checkPOW); bool ReadBlockFromDisk(CBlock& block, const CDiskBlockPos& pos,bool checkPOW);
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex,bool checkPOW); bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex,bool checkPOW);
bool RemoveOrphanedBlocks(int32_t notarized_height);
/** Functions for validating blocks and updating the block tree */ /** Functions for validating blocks and updating the block tree */

View File

@@ -39,8 +39,7 @@
#endif #endif
#include <unistd.h> #include <unistd.h>
extern uint64_t ASSETCHAINS_TIMELOCKGTE; #include "komodo_defs.h"
extern uint32_t ASSETCHAINS_ALGO, ASSETCHAINS_VERUSHASH;
int64_t komodo_block_unlocktime(uint32_t nHeight); int64_t komodo_block_unlocktime(uint32_t nHeight);
void AtomicTimer::start() void AtomicTimer::start()

View File

@@ -132,17 +132,8 @@ void UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams,
#include "komodo_defs.h" #include "komodo_defs.h"
extern CCriticalSection cs_metrics; extern CCriticalSection cs_metrics;
extern int32_t KOMODO_MININGTHREADS,KOMODO_LONGESTCHAIN,ASSETCHAINS_SEED,IS_KOMODO_NOTARY,USE_EXTERNAL_PUBKEY,KOMODO_CHOSEN_ONE,ASSETCHAIN_INIT,KOMODO_INITDONE,KOMODO_ON_DEMAND,KOMODO_INITDONE,KOMODO_PASSPORT_INITDONE;
extern uint64_t ASSETCHAINS_COMMISSION, ASSETCHAINS_STAKED;
extern bool VERUS_MINTBLOCKS;
extern uint64_t ASSETCHAINS_REWARD[ASSETCHAINS_MAX_ERAS], ASSETCHAINS_TIMELOCKGTE, ASSETCHAINS_NONCEMASK[];
extern const char *ASSETCHAINS_ALGORITHMS[];
extern int32_t VERUS_MIN_STAKEAGE, ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH, ASSETCHAINS_VERUSHASH, ASSETCHAINS_LASTERA, ASSETCHAINS_LWMAPOS, ASSETCHAINS_NONCESHIFT[], ASSETCHAINS_HASHESPERROUND[];
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
extern std::string NOTARY_PUBKEY,ASSETCHAINS_OVERRIDE_PUBKEY,ASSETCHAINS_SCRIPTPUB;
void vcalc_sha256(char deprecated[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uint8_t *src,int32_t len); void vcalc_sha256(char deprecated[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uint8_t *src,int32_t len);
extern uint8_t NOTARY_PUBKEY33[33],ASSETCHAINS_OVERRIDE_PUBKEY33[33],ASSETCHAINS_MARMARA;
uint32_t Mining_start,Mining_height; uint32_t Mining_start,Mining_height;
int32_t My_notaryid = -1; int32_t My_notaryid = -1;
int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33,uint32_t timestamp); int32_t komodo_chosennotary(int32_t *notaryidp,int32_t height,uint8_t *pubkey33,uint32_t timestamp);
@@ -487,7 +478,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
{ {
LEAVE_CRITICAL_SECTION(cs_main); LEAVE_CRITICAL_SECTION(cs_main);
LEAVE_CRITICAL_SECTION(mempool.cs); LEAVE_CRITICAL_SECTION(mempool.cs);
uint64_t txfees,utxovalue; uint32_t txtime; uint256 utxotxid; int32_t i,siglen,numsigs,utxovout; uint8_t utxosig[128],*ptr; uint64_t txfees,utxovalue; uint32_t txtime; uint256 utxotxid; int32_t i,siglen,numsigs,utxovout; uint8_t utxosig[512],*ptr;
CMutableTransaction txStaked = CreateNewContextualCMutableTransaction(Params().GetConsensus(), stakeHeight); CMutableTransaction txStaked = CreateNewContextualCMutableTransaction(Params().GetConsensus(), stakeHeight);
if (ASSETCHAINS_LWMAPOS != 0) if (ASSETCHAINS_LWMAPOS != 0)
@@ -521,7 +512,7 @@ CBlockTemplate* CreateNewBlock(CPubKey _pk,const CScript& _scriptPubKeyIn, int32
pblocktemplate->vTxSigOps.push_back(GetLegacySigOpCount(txStaked)); pblocktemplate->vTxSigOps.push_back(GetLegacySigOpCount(txStaked));
nFees += txfees; nFees += txfees;
pblock->nTime = blocktime; pblock->nTime = blocktime;
//printf("staking PoS ht.%d t%u lag.%u\n",(int32_t)chainActive.LastTip()->GetHeight()+1,blocktime,(uint32_t)(GetAdjustedTime() - (blocktime-13))); printf("staking PoS ht.%d t%u lag.%u\n",(int32_t)chainActive.LastTip()->GetHeight()+1,blocktime,(uint32_t)(GetAdjustedTime() - (blocktime-13)));
} else return(0); //fprintf(stderr,"no utxos eligible for staking\n"); } else return(0); //fprintf(stderr,"no utxos eligible for staking\n");
} }
// Create coinbase tx // Create coinbase tx
@@ -1405,6 +1396,8 @@ void static BitcoinMiner_noeq()
miningTimer.stop(); miningTimer.stop();
} }
int32_t gotinvalid;
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
void static BitcoinMiner(CWallet *pwallet) void static BitcoinMiner(CWallet *pwallet)
#else #else
@@ -1613,16 +1606,12 @@ void static BitcoinMiner()
fprintf(stderr," PoW for staked coin PoS %d%% vs target %d%% ht.%d\n",percPoS,(int32_t)ASSETCHAINS_STAKED,Mining_height); fprintf(stderr," PoW for staked coin PoS %d%% vs target %d%% ht.%d\n",percPoS,(int32_t)ASSETCHAINS_STAKED,Mining_height);
} }
} }
gotinvalid = 0;
while (true) while (true)
{ {
/*if ( KOMODO_INSYNC == 0 ) //fprintf(stderr,"gotinvalid.%d\n",gotinvalid);
{ if ( gotinvalid != 0 )
KOMODO_LONGESTCHAIN = komodo_longestchain(); break;
fprintf(stderr,"Mining when blockchain might not be in sync longest.%d vs %d\n",KOMODO_LONGESTCHAIN,Mining_height);
if ( KOMODO_LONGESTCHAIN != 0 && Mining_height >= KOMODO_LONGESTCHAIN )
KOMODO_INSYNC = Mining_height;
sleep(3);
}*/
komodo_longestchain(); komodo_longestchain();
// Hash state // Hash state
KOMODO_CHOSEN_ONE = 0; KOMODO_CHOSEN_ONE = 0;
@@ -1716,6 +1705,7 @@ void static BitcoinMiner()
for (z=31; z>=0; z--) for (z=31; z>=0; z--)
fprintf(stderr,"%02x",((uint8_t *)&h)[z]); fprintf(stderr,"%02x",((uint8_t *)&h)[z]);
fprintf(stderr," Invalid block mined, try again\n"); fprintf(stderr," Invalid block mined, try again\n");
gotinvalid = 1;
return(false); return(false);
} }
KOMODO_CHOSEN_ONE = 1; KOMODO_CHOSEN_ONE = 1;

View File

@@ -33,6 +33,7 @@
#include "sync.h" #include "sync.h"
#include "uint256.h" #include "uint256.h"
#include "utilstrencodings.h" #include "utilstrencodings.h"
#include "util.h"
#include <deque> #include <deque>
#include <stdint.h> #include <stdint.h>
@@ -63,7 +64,7 @@ static const unsigned int MAX_INV_SZ = 50000;
/** The maximum number of new addresses to accumulate before announcing. */ /** The maximum number of new addresses to accumulate before announcing. */
static const unsigned int MAX_ADDR_TO_SEND = 1000; static const unsigned int MAX_ADDR_TO_SEND = 1000;
/** Maximum length of incoming protocol messages (no message over 2 MiB is currently acceptable). */ /** Maximum length of incoming protocol messages (no message over 2 MiB is currently acceptable). */
static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = 4 * 1024 * 1024; // depends on MAX_BLOCK_SIZE static const unsigned int MAX_PROTOCOL_MESSAGE_LENGTH = (_MAX_BLOCK_SIZE + 24); // 24 is msgheader size
/** Maximum length of strSubVer in `version` message */ /** Maximum length of strSubVer in `version` message */
static const unsigned int MAX_SUBVERSION_LENGTH = 256; static const unsigned int MAX_SUBVERSION_LENGTH = 256;
/** -listen default */ /** -listen default */

View File

@@ -37,9 +37,8 @@
#endif // ENABLE_RUST #endif // ENABLE_RUST
uint32_t komodo_chainactive_timestamp(); uint32_t komodo_chainactive_timestamp();
extern uint32_t ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH, ASSETCHAINS_STAKED; #include "komodo_defs.h"
extern char ASSETCHAINS_SYMBOL[65];
extern int32_t ASSETCHAINS_LWMAPOS,VERUS_BLOCK_POSUNITS, VERUS_CONSECUTIVE_POS_THRESHOLD, VERUS_NOPOS_THRESHHOLD;
unsigned int lwmaGetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params); unsigned int lwmaGetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params);
unsigned int lwmaCalculateNextWorkRequired(const CBlockIndex* pindexLast, const Consensus::Params& params); unsigned int lwmaCalculateNextWorkRequired(const CBlockIndex* pindexLast, const Consensus::Params& params);

View File

@@ -24,8 +24,8 @@
#include "tinyformat.h" #include "tinyformat.h"
#include "utilstrencodings.h" #include "utilstrencodings.h"
#include "crypto/common.h" #include "crypto/common.h"
#include "komodo_defs.h"
extern uint32_t ASSETCHAINS_ALGO, ASSETCHAINS_VERUSHASH;
// default hash algorithm for block // default hash algorithm for block
uint256 (CBlockHeader::*CBlockHeader::hashFunction)() const = &CBlockHeader::GetSHA256DHash; uint256 (CBlockHeader::*CBlockHeader::hashFunction)() const = &CBlockHeader::GetSHA256DHash;

View File

@@ -48,10 +48,8 @@
using namespace std; using namespace std;
extern int32_t ASSETCHAINS_ALGO, ASSETCHAINS_EQUIHASH, ASSETCHAINS_LWMAPOS; #include "komodo_defs.h"
extern uint64_t ASSETCHAINS_STAKED;
extern int32_t KOMODO_MININGTHREADS;
extern bool VERUS_MINTBLOCKS;
arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc); arith_uint256 komodo_PoWtarget(int32_t *percPoSp,arith_uint256 target,int32_t height,int32_t goalperc);
/** /**

View File

@@ -77,7 +77,8 @@ int32_t notarizedtxid_height(char *dest,char *txidstr,int32_t *kmdnotarized_heig
extern uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT; extern uint16_t ASSETCHAINS_P2PPORT,ASSETCHAINS_RPCPORT;
extern uint32_t ASSETCHAINS_CC; extern uint32_t ASSETCHAINS_CC;
extern uint32_t ASSETCHAINS_MAGIC; extern uint32_t ASSETCHAINS_MAGIC;
extern uint64_t ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED,ASSETCHAINS_SUPPLY,ASSETCHAINS_LASTERA; extern uint64_t ASSETCHAINS_COMMISSION,ASSETCHAINS_STAKED,ASSETCHAINS_SUPPLY;
extern uint32_t ASSETCHAINS_LASTERA;
extern int32_t ASSETCHAINS_LWMAPOS,ASSETCHAINS_SAPLING; extern int32_t ASSETCHAINS_LWMAPOS,ASSETCHAINS_SAPLING;
extern uint64_t ASSETCHAINS_ENDSUBSIDY[],ASSETCHAINS_REWARD[],ASSETCHAINS_HALVING[],ASSETCHAINS_DECAY[]; extern uint64_t ASSETCHAINS_ENDSUBSIDY[],ASSETCHAINS_REWARD[],ASSETCHAINS_HALVING[],ASSETCHAINS_DECAY[];
extern std::string NOTARY_PUBKEY; extern uint8_t NOTARY_PUBKEY33[]; extern std::string NOTARY_PUBKEY; extern uint8_t NOTARY_PUBKEY33[];
@@ -224,7 +225,7 @@ UniValue getinfo(const UniValue& params, bool fHelp)
} }
} }
if (ASSETCHAINS_LASTERA > 0) if (ASSETCHAINS_LASTERA > 0)
obj.push_back(Pair("eras", ASSETCHAINS_LASTERA + 1)); obj.push_back(Pair("eras", (int64_t)(ASSETCHAINS_LASTERA + 1)));
obj.push_back(Pair("reward", acReward)); obj.push_back(Pair("reward", acReward));
obj.push_back(Pair("halving", acHalving)); obj.push_back(Pair("halving", acHalving));
obj.push_back(Pair("decay", acDecay)); obj.push_back(Pair("decay", acDecay));

View File

@@ -463,6 +463,10 @@ static const CRPCCommand vRPCCommands[] =
// Payments // Payments
{ "payments", "paymentsaddress", &paymentsaddress, true }, { "payments", "paymentsaddress", &paymentsaddress, true },
{ "CClib", "cclibaddress", &cclibaddress, true },
{ "CClib", "cclibinfo", &cclibinfo, true },
{ "CClib", "cclib", &cclib, true },
// Gateways // Gateways
{ "gateways", "gatewaysaddress", &gatewaysaddress, true }, { "gateways", "gatewaysaddress", &gatewaysaddress, true },
{ "gateways", "gatewayslist", &gatewayslist, true }, { "gateways", "gatewayslist", &gatewayslist, true },
@@ -533,6 +537,9 @@ static const CRPCCommand vRPCCommands[] =
{ "util", "reconsiderblock", &reconsiderblock, true }, { "util", "reconsiderblock", &reconsiderblock, true },
/* Not shown in help */ /* Not shown in help */
{ "hidden", "setmocktime", &setmocktime, true }, { "hidden", "setmocktime", &setmocktime, true },
{ "hidden", "test_ac", &test_ac, true },
{ "hidden", "test_heirmarker", &test_heirmarker, true },
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
/* Wallet */ /* Wallet */
{ "wallet", "resendwallettransactions", &resendwallettransactions, true}, { "wallet", "resendwallettransactions", &resendwallettransactions, true},

View File

@@ -287,6 +287,9 @@ extern UniValue marmara_creditloop(const UniValue& params, bool fHelp);
extern UniValue marmara_settlement(const UniValue& params, bool fHelp); extern UniValue marmara_settlement(const UniValue& params, bool fHelp);
extern UniValue marmara_lock(const UniValue& params, bool fHelp); extern UniValue marmara_lock(const UniValue& params, bool fHelp);
extern UniValue paymentsaddress(const UniValue& params, bool fHelp); extern UniValue paymentsaddress(const UniValue& params, bool fHelp);
extern UniValue cclibaddress(const UniValue& params, bool fHelp);
extern UniValue cclibinfo(const UniValue& params, bool fHelp);
extern UniValue cclib(const UniValue& params, bool fHelp);
extern UniValue gatewaysaddress(const UniValue& params, bool fHelp); extern UniValue gatewaysaddress(const UniValue& params, bool fHelp);
extern UniValue gatewayslist(const UniValue& params, bool fHelp); extern UniValue gatewayslist(const UniValue& params, bool fHelp);
extern UniValue gatewaysinfo(const UniValue& params, bool fHelp); extern UniValue gatewaysinfo(const UniValue& params, bool fHelp);
@@ -468,4 +471,8 @@ extern UniValue paxprices(const UniValue& params, bool fHelp);
extern UniValue paxdeposit(const UniValue& params, bool fHelp); extern UniValue paxdeposit(const UniValue& params, bool fHelp);
extern UniValue paxwithdraw(const UniValue& params, bool fHelp); extern UniValue paxwithdraw(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);
#endif // BITCOIN_RPCSERVER_H #endif // BITCOIN_RPCSERVER_H

View File

@@ -647,3 +647,4 @@ bool DummySignatureCreator::CreateSig(
vchSig[6 + 33 + 32] = SIGHASH_ALL; vchSig[6 + 33 + 32] = SIGHASH_ALL;
return true; return true;
} }

View File

@@ -103,7 +103,7 @@ void ThreadSendAlert()
// 4000 or higher will put the RPC into safe mode // 4000 or higher will put the RPC into safe mode
alert.nPriority = 4000; alert.nPriority = 4000;
alert.strComment = ""; alert.strComment = "";
alert.strStatusBar = "Your client version has degraded networking behavior. Please update to the most recent version of Verus (0.3.2 or later)."; alert.strStatusBar = "Your client version has degraded networking behavior. Please update to the most recent version of Komodo (0.3.3 or later).";
alert.strRPCError = alert.strStatusBar; alert.strRPCError = alert.strStatusBar;
// Set specific client version/versions here. If setSubVer is empty, no filtering on subver is done: // Set specific client version/versions here. If setSubVer is empty, no filtering on subver is done:

View File

@@ -686,7 +686,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts()
pindexNew->nTx = diskindex.nTx; pindexNew->nTx = diskindex.nTx;
pindexNew->nSproutValue = diskindex.nSproutValue; pindexNew->nSproutValue = diskindex.nSproutValue;
pindexNew->nSaplingValue = diskindex.nSaplingValue; pindexNew->nSaplingValue = diskindex.nSaplingValue;
//fprintf(stderr,"loadguts ht.%d\n",pindexNew->GetHeight());
// Consistency checks // Consistency checks
auto header = pindexNew->GetBlockHeader(); auto header = pindexNew->GetBlockHeader();
if (header.GetHash() != pindexNew->GetBlockHash()) if (header.GetHash() != pindexNew->GetBlockHash())

View File

@@ -3,6 +3,21 @@
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
* the top-level directory of this distribution for the individual copyright *
* holder information and the developer policies on copyright and licensing. *
* *
* Unless otherwise agreed in a custom licensing agreement, no part of the *
* SuperNET software, including this file may be copied, modified, propagated *
* or distributed except according to the terms contained in the LICENSE file *
* *
* Removal or modification of this copyright notice is prohibited. *
* *
******************************************************************************/
/** /**
* Server/client environment: argument handling, config file parsing, * Server/client environment: argument handling, config file parsing,
* logging, thread wrappers * logging, thread wrappers
@@ -29,6 +44,8 @@
#include <boost/signals2/signal.hpp> #include <boost/signals2/signal.hpp>
#include <boost/thread/exceptions.hpp> #include <boost/thread/exceptions.hpp>
#define _MAX_BLOCK_SIZE (4096 * 1024) // changing just _MAX_BLOCK_SIZE will hardfork to that size
static const bool DEFAULT_LOGTIMEMICROS = false; static const bool DEFAULT_LOGTIMEMICROS = false;
static const bool DEFAULT_LOGIPS = false; static const bool DEFAULT_LOGIPS = false;
static const bool DEFAULT_LOGTIMESTAMPS = true; static const bool DEFAULT_LOGTIMESTAMPS = true;

View File

@@ -57,6 +57,7 @@
#include <numeric> #include <numeric>
#include "komodo_defs.h"
using namespace std; using namespace std;
@@ -67,8 +68,6 @@ const std::string ADDR_TYPE_SPROUT = "sprout";
const std::string ADDR_TYPE_SAPLING = "sapling"; const std::string ADDR_TYPE_SAPLING = "sapling";
extern UniValue TxJoinSplitToJSON(const CTransaction& tx); extern UniValue TxJoinSplitToJSON(const CTransaction& tx);
extern uint8_t ASSETCHAINS_PRIVATE;
extern int32_t USE_EXTERNAL_PUBKEY;
uint32_t komodo_segid32(char *coinaddr); uint32_t komodo_segid32(char *coinaddr);
int32_t komodo_dpowconfs(int32_t height,int32_t numconfs); int32_t komodo_dpowconfs(int32_t height,int32_t numconfs);
int32_t komodo_isnotaryvout(char *coinaddr); // from ac_private chains only int32_t komodo_isnotaryvout(char *coinaddr); // from ac_private chains only
@@ -4887,10 +4886,11 @@ UniValue z_mergetoaddress(const UniValue& params, bool fHelp)
if (useAnySprout || useAnySapling || zaddrs.size() > 0) { if (useAnySprout || useAnySapling || zaddrs.size() > 0) {
// Get available notes // Get available notes
std::vector<CSproutNotePlaintextEntry> sproutEntries,skipsprout; std::vector<CSproutNotePlaintextEntry> sproutEntries;
//std::vector<SaplingNoteEntry> saplingEntries;
//pwalletMain->GetFilteredNotes(sproutEntries, saplingEntries, zaddrs);
std::vector<SaplingNoteEntry> saplingEntries,skipsapling; std::vector<SaplingNoteEntry> saplingEntries,skipsapling;
pwalletMain->GetFilteredNotes(sproutEntries, useAnySprout == 0 ? saplingEntries : skipsapling, zaddrs); pwalletMain->GetFilteredNotes(sproutEntries, useAnySprout == 0 ? saplingEntries : skipsapling, zaddrs);
// If Sapling is not active, do not allow sending from a sapling addresses. // If Sapling is not active, do not allow sending from a sapling addresses.
if (!saplingActive && saplingEntries.size() > 0) { if (!saplingActive && saplingEntries.size() > 0) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated"); throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, Sapling has not activated");
@@ -5172,7 +5172,6 @@ int32_t verus_staked(CBlock *pBlock, CMutableTransaction &txNew, uint32_t &nBits
int32_t ensure_CCrequirements() int32_t ensure_CCrequirements()
{ {
extern uint8_t NOTARY_PUBKEY33[];
CCerror = ""; CCerror = "";
if ( NOTARY_PUBKEY33[0] == 0 ) if ( NOTARY_PUBKEY33[0] == 0 )
return(-1); return(-1);
@@ -5262,8 +5261,6 @@ UniValue setpubkey(const UniValue& params, bool fHelp)
char Raddress[18]; char Raddress[18];
uint8_t pubkey33[33]; uint8_t pubkey33[33];
extern uint8_t NOTARY_PUBKEY33[];
extern std::string NOTARY_PUBKEY;
if ( NOTARY_PUBKEY33[0] == 0 ) { if ( NOTARY_PUBKEY33[0] == 0 ) {
if (strlen(params[0].get_str().c_str()) == 66) { if (strlen(params[0].get_str().c_str()) == 66) {
decode_hex(pubkey33,33,(char *)params[0].get_str().c_str()); decode_hex(pubkey33,33,(char *)params[0].get_str().c_str());
@@ -5327,6 +5324,43 @@ UniValue channelsaddress(const UniValue& params, bool fHelp)
return(result); return(result);
} }
UniValue cclibaddress(const UniValue& params, bool fHelp)
{
struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
cp = CCinit(&C,EVAL_FIRSTUSER);
if ( fHelp || params.size() > 1 )
throw runtime_error("cclibaddress [pubkey]\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
if ( params.size() == 1 )
pubkey = ParseHex(params[0].get_str().c_str());
return(CCaddress(cp,(char *)"CClib",pubkey));
}
UniValue cclibinfo(const UniValue& params, bool fHelp)
{
struct CCcontract_info *cp,C;
cp = CCinit(&C,EVAL_FIRSTUSER);
if ( fHelp || params.size() > 0 )
throw runtime_error("cclibinfo\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
return(CClib_info(cp));
}
UniValue cclib(const UniValue& params, bool fHelp)
{
struct CCcontract_info *cp,C; char *method; cJSON *jsonparams;
cp = CCinit(&C,EVAL_FIRSTUSER);
if ( fHelp || params.size() > 2 )
throw runtime_error("cclib method [JSON params]\n");
if ( ensure_CCrequirements() < 0 )
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
method = (char *)params[0].get_str().c_str();
jsonparams = cJSON_Parse(params[1].get_str().c_str());
return(CClib(cp,method,jsonparams));
}
UniValue oraclesaddress(const UniValue& params, bool fHelp) UniValue oraclesaddress(const UniValue& params, bool fHelp)
{ {
struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey; struct CCcontract_info *cp,C; std::vector<unsigned char> pubkey;
@@ -7329,7 +7363,7 @@ UniValue heirfund(const UniValue& params, bool fHelp)
{ {
UniValue result(UniValue::VOBJ); UniValue result(UniValue::VOBJ);
uint256 tokenid = zeroid; uint256 tokenid = zeroid;
uint64_t txfee; int64_t txfee;
int64_t amount; int64_t amount;
int64_t inactivitytime; int64_t inactivitytime;
std::string hex; std::string hex;
@@ -7340,21 +7374,34 @@ UniValue heirfund(const UniValue& params, bool fHelp)
return NullUniValue; return NullUniValue;
if (fHelp || params.size() != 5 && params.size() != 6) if (fHelp || params.size() != 5 && params.size() != 6)
throw runtime_error("heirfundtokens fee funds heirname heirpubkey inactivitytime [tokenid]\n"); throw runtime_error("heirfund txfee funds heirname heirpubkey inactivitytime [tokenid]\n");
if (ensure_CCrequirements() < 0) if (ensure_CCrequirements() < 0)
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); 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; const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet); LOCK2(cs_main, pwalletMain->cs_wallet);
txfee = atoll((char*)params[0].get_str().c_str()); txfee = atoll(params[0].get_str().c_str());
amount = atoll((char*)params[1].get_str().c_str()); if (txfee < 0)
throw runtime_error("incorrect txfee param\n");
if(params.size() == 6) // tokens in satoshis:
amount = atoll(params[1].get_str().c_str());
else // coins:
amount = atof(params[1].get_str().c_str()) * COIN;
if( amount <= 0 )
throw runtime_error("incorrect amount\n");
name = params[2].get_str(); name = params[2].get_str();
pubkey = ParseHex(params[3].get_str().c_str()); pubkey = ParseHex(params[3].get_str().c_str());
if( !pubkey2pk(pubkey).IsValid() ) if( !pubkey2pk(pubkey).IsValid() )
throw runtime_error("incorrect pubkey\n"); throw runtime_error("incorrect pubkey\n");
inactivitytime = atof((char*)params[4].get_str().c_str()); inactivitytime = atoll(params[4].get_str().c_str());
if (inactivitytime <= 0)
throw runtime_error("incorrect inactivity time param\n");
if (params.size() == 6) { if (params.size() == 6) {
tokenid = Parseuint256((char*)params[5].get_str().c_str()); tokenid = Parseuint256((char*)params[5].get_str().c_str());
if(tokenid == zeroid) if(tokenid == zeroid)
@@ -7373,7 +7420,7 @@ UniValue heiradd(const UniValue& params, bool fHelp)
{ {
UniValue result; UniValue result;
uint256 fundingtxid; uint256 fundingtxid;
uint64_t txfee; int64_t txfee;
int64_t amount; int64_t amount;
int64_t inactivitytime; int64_t inactivitytime;
std::string hex; std::string hex;
@@ -7384,18 +7431,20 @@ UniValue heiradd(const UniValue& params, bool fHelp)
return NullUniValue; return NullUniValue;
if (fHelp || params.size() != 3) if (fHelp || params.size() != 3)
throw runtime_error("heiraddtokens fee funds fundingtxid\n"); throw runtime_error("heiradd txfee funds fundingtxid\n");
if (ensure_CCrequirements() < 0) if (ensure_CCrequirements() < 0)
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); 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; const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet); LOCK2(cs_main, pwalletMain->cs_wallet);
txfee = atoll((char*)params[0].get_str().c_str()); txfee = atoll(params[0].get_str().c_str());
amount = atoll((char*)params[1].get_str().c_str()); if (txfee < 0)
throw runtime_error("incorrect txfee param\n");
fundingtxid = Parseuint256((char*)params[2].get_str().c_str()); fundingtxid = Parseuint256((char*)params[2].get_str().c_str());
result = HeirAddCaller(fundingtxid, txfee, amount); result = HeirAddCaller(fundingtxid, txfee, params[1].get_str());
return result; return result;
} }
@@ -7404,7 +7453,6 @@ UniValue heirclaim(const UniValue& params, bool fHelp)
UniValue result; // result(UniValue::VOBJ); UniValue result; // result(UniValue::VOBJ);
uint256 fundingtxid; uint256 fundingtxid;
int64_t txfee; int64_t txfee;
int64_t amount;
int64_t inactivitytime; int64_t inactivitytime;
std::string hex; std::string hex;
std::vector<unsigned char> pubkey; std::vector<unsigned char> pubkey;
@@ -7415,18 +7463,20 @@ UniValue heirclaim(const UniValue& params, bool fHelp)
return NullUniValue; return NullUniValue;
if (fHelp || params.size() != 3) if (fHelp || params.size() != 3)
throw runtime_error("heirclaimtokens fee funds fundingtxid\n"); throw runtime_error("heirclaim txfee funds fundingtxid\n");
if (ensure_CCrequirements() < 0) if (ensure_CCrequirements() < 0)
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n"); 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; const CKeyStore& keystore = *pwalletMain;
LOCK2(cs_main, pwalletMain->cs_wallet); LOCK2(cs_main, pwalletMain->cs_wallet);
txfee = atoll((char*)params[0].get_str().c_str()); txfee = atoll(params[0].get_str().c_str());
amount = atoll((char*)params[1].get_str().c_str()); if (txfee < 0)
throw runtime_error("incorrect txfee param\n");
fundingtxid = Parseuint256((char*)params[2].get_str().c_str()); fundingtxid = Parseuint256((char*)params[2].get_str().c_str());
result = HeirClaimCaller(fundingtxid, txfee, amount); result = HeirClaimCaller(fundingtxid, txfee, params[1].get_str());
return result; return result;
} }
@@ -7548,3 +7598,79 @@ void RegisterWalletRPCCommands(CRPCTable &tableRPC)
for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++)
tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]);
} }
UniValue test_ac(const UniValue& params, bool fHelp)
{
// make fake token tx:
struct CCcontract_info *cp, C;
if (fHelp || (params.size() != 4))
throw runtime_error("incorrect params\n");
if (ensure_CCrequirements() < 0)
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
std::vector<unsigned char> pubkey1;
std::vector<unsigned char> pubkey2;
pubkey1 = ParseHex(params[0].get_str().c_str());
pubkey2 = ParseHex(params[1].get_str().c_str());
CPubKey pk1 = pubkey2pk(pubkey1);
CPubKey pk2 = pubkey2pk(pubkey2);
if(!pk1.IsValid() || !pk2.IsValid())
throw runtime_error("invalid pubkey\n");
int64_t txfee = 10000;
int64_t amount = atoll(params[2].get_str().c_str()) * COIN;
uint256 fundingtxid = Parseuint256((char *)params[3].get_str().c_str());
CPubKey myPubkey = pubkey2pk(Mypubkey());
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
int64_t normalInputs = AddNormalinputs(mtx, myPubkey, txfee + amount, 60);
if( normalInputs < txfee + amount)
throw runtime_error("not enough normals\n");
mtx.vout.push_back(MakeCC1of2vout(EVAL_HEIR, amount, pk1, pk2));
CScript opret;
fundingtxid = revuint256(fundingtxid);
opret << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_HEIR << (uint8_t)'A' << fundingtxid << (uint8_t)0);
cp = CCinit(&C, EVAL_HEIR);
return(FinalizeCCTx(0, cp, mtx, myPubkey, txfee, opret));
}
UniValue test_heirmarker(const UniValue& params, bool fHelp)
{
// make fake token tx:
struct CCcontract_info *cp, C;
if (fHelp || (params.size() != 1))
throw runtime_error("incorrect params\n");
if (ensure_CCrequirements() < 0)
throw runtime_error("to use CC contracts, you need to launch daemon with valid -pubkey= for an address in your wallet\n");
uint256 fundingtxid = Parseuint256((char *)params[0].get_str().c_str());
CPubKey myPubkey = pubkey2pk(Mypubkey());
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
int64_t normalInputs = AddNormalinputs(mtx, myPubkey, 10000, 60);
if (normalInputs < 10000)
throw runtime_error("not enough normals\n");
mtx.vin.push_back(CTxIn(fundingtxid, 1));
mtx.vout.push_back(MakeCC1vout(EVAL_HEIR, 10000, myPubkey));
CScript opret;
fundingtxid = revuint256(fundingtxid);
opret << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_HEIR << (uint8_t)'C' << fundingtxid << (uint8_t)0);
cp = CCinit(&C, EVAL_HEIR);
return(FinalizeCCTx(0, cp, mtx, myPubkey, 10000, opret));
}

View File

@@ -59,13 +59,7 @@ bool fSendFreeTransactions = false;
bool fPayAtLeastCustomFee = true; bool fPayAtLeastCustomFee = true;
#include "komodo_defs.h" #include "komodo_defs.h"
extern int32_t USE_EXTERNAL_PUBKEY;
extern std::string NOTARY_PUBKEY;
extern int32_t KOMODO_EXCHANGEWALLET;
extern char ASSETCHAINS_SYMBOL[KOMODO_ASSETCHAIN_MAXLEN];
extern int32_t VERUS_MIN_STAKEAGE;
CBlockIndex *komodo_chainactive(int32_t height); CBlockIndex *komodo_chainactive(int32_t height);
extern std::string DONATION_PUBKEY;
/** /**
* Fees smaller than this (in satoshi) are considered zero fee (for transaction creation) * Fees smaller than this (in satoshi) are considered zero fee (for transaction creation)

View File

@@ -77,7 +77,6 @@ static const unsigned int MAX_FREE_TRANSACTION_CREATE_SIZE = 1000;
// unless there is some exceptional network disruption. // unless there is some exceptional network disruption.
extern unsigned int WITNESS_CACHE_SIZE; extern unsigned int WITNESS_CACHE_SIZE;
//! Size of HD seed in bytes //! Size of HD seed in bytes
static const size_t HD_WALLET_SEED_LENGTH = 32; static const size_t HD_WALLET_SEED_LENGTH = 32;