1from .address import * 2from .script import * 3from .mininode import * 4from .util import * 5from .qtumconfig import * 6from .blocktools import * 7from .key import * 8from .segwit_addr import * 9import io 10import base64 11import math 12import pprint 13 14pp = pprint.PrettyPrinter() 15 16def generatesynchronized(node, numblocks, address=None, sync_with_nodes=[]): 17 if not address: 18 address = node.getnewaddress() 19 20 blockhashes = [] 21 for i in range(0, max(numblocks//16, 0)): 22 blockhashes += node.generatetoaddress(16, address) 23 sync_blocks(sync_with_nodes, wait=0.001) 24 25 if numblocks % 16: 26 blockhashes += node.generatetoaddress(numblocks % 16, address) 27 sync_blocks(sync_with_nodes, wait=0.001) 28 return blockhashes 29 30def generateinitial(node, numblocks, address=None, sync_with_nodes=[]): 31 mocktime = node.getblock(node.getbestblockhash())['mocktime'] 32 for n in [node] + sync_with_nodes: 33 n.setmocktime(mocktime) 34 35 blockhashes = node.generatetoaddress(numblocks, address) 36 37 for n in [node] + sync_with_nodes: 38 n.setmocktime(0) 39 40 return blockhashes 41 42def make_transaction(node, vin, vout): 43 tx = CTransaction() 44 tx.vin = vin 45 tx.vout = vout 46 tx.rehash() 47 48 unsigned_raw_tx = bytes_to_hex_str(tx.serialize_without_witness()) 49 signed_raw_tx = node.signrawtransactionwithwallet(unsigned_raw_tx)['hex'] 50 return signed_raw_tx 51 52def make_vin(node, value): 53 addr = node.getnewaddress() 54 txid_hex = node.sendtoaddress(addr, value/COIN) 55 txid = int(txid_hex, 16) 56 node.generate(1) 57 raw_tx = node.decoderawtransaction(node.gettransaction(txid_hex)['hex']) 58 59 for vout_index, txout in enumerate(raw_tx['vout']): 60 if txout['scriptPubKey']['addresses'] == [addr]: 61 break 62 else: 63 assert False 64 65 return CTxIn(COutPoint(txid, vout_index), nSequence=0) 66 67def make_op_create_output(node, value, version, gas_limit, gas_price, data): 68 scriptPubKey = CScript() 69 scriptPubKey += version 70 scriptPubKey += gas_limit 71 scriptPubKey += gas_price 72 scriptPubKey += data 73 scriptPubKey += OP_CREATE 74 return CTxOut(value, scriptPubKey) 75 76def make_op_call_output(value, version, gas_limit, gas_price, data, contract): 77 scriptPubKey = CScript() 78 scriptPubKey += version 79 scriptPubKey += gas_limit 80 scriptPubKey += gas_price 81 scriptPubKey += data 82 scriptPubKey += contract 83 scriptPubKey += OP_CALL 84 return CTxOut(value, scriptPubKey) 85 86def convert_btc_address_to_qtum(addr, main=False): 87 version, hsh, checksum = base58_to_byte(addr, 25) 88 if version == 111: 89 return keyhash_to_p2pkh(binascii.unhexlify(hsh), main) 90 91 if version == 196: 92 return scripthash_to_p2sh(binascii.unhexlify(hsh), main) 93 assert(False) 94 95def convert_btc_bech32_address_to_qtum(addr, main=False): 96 hdr, data = bech32_decode(addr) 97 return bech32_encode('qcrt', data) 98 99 100def p2pkh_to_hex_hash(address): 101 return str(base58_to_byte(address, 25)[1])[2:-1] 102 103def hex_hash_to_p2pkh(hex_hash): 104 return keyhash_to_p2pkh(hex_str_to_bytes(hex_hash)) 105 106def assert_vin(tx, expected_vin): 107 assert_equal(len(tx['vin']), len(expected_vin)) 108 matches = [] 109 for expected in expected_vin: 110 for i in range(len(tx['vin'])): 111 if i not in matches and expected[0] == tx['vin'][i]['scriptSig']['asm']: 112 matches.append(i) 113 break 114 assert_equal(len(matches), len(expected_vin)) 115 116def assert_vout(tx, expected_vout): 117 assert_equal(len(tx['vout']), len(expected_vout)) 118 matches = [] 119 for expected in expected_vout: 120 for i in range(len(tx['vout'])): 121 if i not in matches and expected[0] == tx['vout'][i]['value'] and expected[1] == tx['vout'][i]['scriptPubKey']['type']: 122 matches.append(i) 123 break 124 assert_equal(len(matches), len(expected_vout)) 125 126def rpc_sign_transaction(node, tx): 127 ret = node.signrawtransactionwithwallet(bytes_to_hex_str(tx.serialize())) 128 if not ret['complete']: 129 print(ret) 130 assert(ret['complete']) 131 tx_signed_raw_hex = ret['hex'] 132 f = io.BytesIO(hex_str_to_bytes(tx_signed_raw_hex)) 133 tx_signed = CTransaction() 134 tx_signed.deserialize(f) 135 return tx_signed 136 137def make_vin_from_unspent(node, unspents=None, value=2000000000000, address=None): 138 if not unspents: 139 unspents = node.listunspent() 140 for i in range(len(unspents)): 141 unspent = unspents[i] 142 if unspent['amount'] == value/COIN and (not address or address == unspent['address']): 143 unspents.pop(i) 144 return CTxIn(COutPoint(int(unspent['txid'], 16), unspent['vout']), nSequence=0) 145 return None 146 147def read_evm_array(node, address, abi, ignore_nulls=True): 148 arr = [] 149 index = 0 150 ret = node.callcontract(address, abi + hex(index)[2:].zfill(64)) 151 while ret['executionResult']['excepted'] == 'None': 152 if int(ret['executionResult']['output'], 16) != 0 or not ignore_nulls: 153 arr.append(ret['executionResult']['output']) 154 index += 1 155 ret = node.callcontract(address, abi + hex(index)[2:].zfill(64)) 156 return arr 157 158class DGPState: 159 def __init__(self, node, contract_address): 160 self.last_state_assert_block_height = 0 161 self.node = node 162 self.contract_address = contract_address 163 self.param_count = 0 164 self.gov_keys = [] 165 self.admin_keys = [] 166 self.params_for_block = [] 167 self.param_address_at_indices = [] 168 self.required_votes = [0, 0, 0] 169 self.current_on_vote_statuses = [ 170 [False, False, False], 171 [False, False, False], 172 [False, False] 173 ] 174 self.current_on_vote_address_proposals = [ 175 ["0", "0", "0"], 176 ["0", "0"] 177 ] 178 self.abiAddAddressProposal = "bf5f1e83" #addAddressProposal(address,uint256) 179 self.abiRemoveAddressProposal = "4cc0e2bc" # removeAddressProposal(address,uint256) 180 self.abiChangeValueProposal = "19971cbd" # changeValueProposal(uint256,uint256) 181 self.abiAlreadyVoted = "e9944a81" # alreadyVoted(address,address[]) 182 self.abiGetAddressesList = "850d9758" # getAddressesList(uint256) 183 self.abiGetArrayNonNullLength = "9b216626" # getArrayNonNullLenght(address[]) 184 self.abiGetCurrentOnVoteAddressProposal = "0c83ebac" # getCurrentOnVoteAddressProposal(uint256,uint256) 185 self.abiGetCurrentOnVoteStatus = "5f302e8b" # getCurrentOnVoteStatus(uint256,uint256) 186 self.abiGetCurrentOnVoteValueProposal = "4364725c" # getCurrentOnVoteValueProposal(uint256) 187 self.abiGetCurrentOnVoteVotes = "f9f51401" # getCurrentOnVoteVotes(uint256,uint256) 188 self.abiGetParamAddressAtIndex = "15341747" # getParamAddressAtIndex(uint256) 189 self.abiGetParamCount = "27e35746" # getParamCount() 190 self.abiGetParamHeightAtIndex = "8a5a9d07" # getParamHeightAtIndex(uint256) 191 self.abiGetParamsForBlock = "f769ac48" # getParamsForBlock(uint256) 192 self.abiGetRequiredVotes = "1ec28e0f" # getRequiredVotes(uint256) 193 self.abiIsAdminKey = "6b102c49" # isAdminKey(address) 194 self.abiIsGovKey = "7b993bf3" # isGovKey(address) 195 self.abiSetInitialAdmin = "6fb81cbb" # setInitialAdmin() 196 self.abiTallyAdminVotes = "bec171e5" # tallyAdminVotes(address[]) 197 self.abiTallyGovVotes = "4afb4f11" # tallyGovVotes(address[]) 198 self.abiGovKeys = "30a79873" # govKeys(uint256) 199 self.abiAdminKeys = "aff125f6" # adminKeys(uint256) 200 201 def send_set_initial_admin(self, sender): 202 self.node.sendtoaddress(sender, 1) 203 self.node.sendtocontract(self.contract_address, self.abiSetInitialAdmin, 0, 2000000, QTUM_MIN_GAS_PRICE_STR, sender) 204 205 def send_add_address_proposal(self, proposal_address, type1, sender): 206 self.node.sendtoaddress(sender, 1) 207 txid = self.node.sendtocontract(self.contract_address, self.abiAddAddressProposal + proposal_address.zfill(64) + hex(type1)[2:].zfill(64), 0, 20000000, QTUM_MIN_GAS_PRICE_STR, sender)['txid'] 208 return txid 209 210 def send_remove_address_proposal(self, proposal_address, type1, sender): 211 self.node.sendtoaddress(sender, 1) 212 txid = self.node.sendtocontract(self.contract_address, self.abiRemoveAddressProposal + proposal_address.zfill(64) + hex(type1)[2:].zfill(64), 0, 20000000, QTUM_MIN_GAS_PRICE_STR, sender)['txid'] 213 return txid 214 215 def send_change_value_proposal(self, uint_proposal, type1, sender): 216 self.node.sendtoaddress(sender, 1) 217 txid = self.node.sendtocontract(self.contract_address, self.abiChangeValueProposal + hex(uint_proposal)[2:].zfill(64) + hex(type1)[2:].zfill(64), 0, 20000000, QTUM_MIN_GAS_PRICE_STR, sender)['txid'] 218 return txid 219 220 221 def assert_state(self): 222 # This assertion is only to catch potential errors in the test code (if we forget to add a generate after an evm call) 223 assert(self.last_state_assert_block_height < self.node.getblockcount()) 224 self.last_state_assert_block_height = self.node.getblockcount() 225 226 self._assert_param_count(self.param_count) 227 self._assert_gov_keys_equal(self.gov_keys) 228 self._assert_admin_keys_equal(self.admin_keys) 229 for block_height, param_for_block in self.params_for_block: 230 self._assert_params_for_block(block_height, param_for_block) 231 # Make sure that there are no subsequent params for blocks 232 if self.params_for_block: 233 ret = self.node.callcontract(self.contract_address, self.abiGetParamsForBlock + hex(0x2fff)[2:].zfill(64)) 234 assert_equal(int(ret['executionResult']['output'], 16), int(param_for_block, 16)) 235 else: 236 ret = self.node.callcontract(self.contract_address, self.abiGetParamsForBlock + hex(0x2fff)[2:].zfill(64)) 237 assert_equal(int(ret['executionResult']['output'], 16), 0) 238 239 240 for index, param_address_at_index in enumerate(self.param_address_at_indices): 241 self._assert_param_address_at_index(index, param_address_at_index) 242 # Make sure that there are no subsequent params at the next index 243 if self.param_address_at_indices: 244 ret = self.node.callcontract(self.contract_address, self.abiGetParamAddressAtIndex + hex(index+1)[2:].zfill(64)) 245 assert(ret['executionResult']['excepted'] != 'None') 246 else: 247 ret = self.node.callcontract(self.contract_address, self.abiGetParamAddressAtIndex + hex(0x0)[2:].zfill(64)) 248 assert(ret['executionResult']['excepted'] != 'None') 249 250 251 for type1, required_votes in enumerate(self.required_votes): 252 self._assert_required_votes(type1, required_votes) 253 for type1, arr1 in enumerate(self.current_on_vote_statuses): 254 for type2, current_on_vote_status in enumerate(arr1): 255 self._assert_current_on_vote_status(type1, type2, current_on_vote_status) 256 for type1, arr1 in enumerate(self.current_on_vote_address_proposals): 257 for type2, current_on_vote_address_proposal in enumerate(arr1): 258 self._assert_current_on_vote_address_proposal(type1, type2, current_on_vote_address_proposal) 259 260 """ 261 function getRequiredVotes(uint _type) constant returns (uint val){ 262 // type 0: adminVotesForParams 263 // type 1: govVotesForParams 264 // type 2: adminVotesForManagement 265 if(_type>2) throw; // invalid type 266 if(_type==0)return activeVotesRequired.adminVotesForParams; 267 if(_type==1)return activeVotesRequired.govVotesForParams; 268 if(_type==2)return activeVotesRequired.adminVotesForManagement; 269 } 270 """ 271 def _assert_required_votes(self, type1, expected_required_votes): 272 ret = self.node.callcontract(self.contract_address, self.abiGetRequiredVotes + str(type1).zfill(64)) 273 assert_equal(int(ret['executionResult']['output'], 16), expected_required_votes) 274 275 """ 276 function getCurrentOnVoteStatus(uint _type, uint _type2) constant returns (bool val){ 277 // type 0: addAddress 278 // type 1: changeValue 279 // type 2: removeAddress 280 281 // type2 0: adminKey 282 // type2 1: govKey 283 // type2 2: paramsAddress 284 285 if(_type>2 || _type2>2) throw; // invalid type 286 if(_type==0)return currentProposals.keys[_type2].onVote; 287 if(_type==1)return currentProposals.uints[_type2].onVote; 288 if(_type==2)return currentProposals.removeKeys[_type2].onVote; 289 } 290 """ 291 def _assert_current_on_vote_status(self, type1, type2, expected_current_on_vote_status): 292 ret = self.node.callcontract(self.contract_address, self.abiGetCurrentOnVoteStatus + str(type1).zfill(64) + str(type2).zfill(64)) 293 assert_equal(int(ret['executionResult']['output'], 16), expected_current_on_vote_status) 294 295 """ 296 function getCurrentOnVoteAddressProposal(uint _type, uint _type2) constant returns (address val){ 297 // type 0: addAddress 298 // type 1: removeAddress 299 300 // type2 0: adminKey 301 // type2 1: govKey 302 // type2 2: paramsAddress 303 304 if(_type>1 || _type2>2) throw; // invalid type 305 if(_type==0)return currentProposals.keys[_type2].proposal; 306 if(_type==1)return currentProposals.removeKeys[_type2].proposal; 307 } 308 """ 309 def _assert_current_on_vote_address_proposal(self, type1, type2, expected_address): 310 ret = self.node.callcontract(self.contract_address, self.abiGetCurrentOnVoteAddressProposal + hex(type1)[2:].zfill(64) + hex(type2)[2:].zfill(64)) 311 assert_equal(int(ret['executionResult']['output'], 16), int(expected_address, 16)) 312 313 """ 314 function getCurrentOnVoteValueProposal(uint _type) constant returns (uint val){ 315 // type 0: adminVotesForParams 316 // type 1: govVotesForParams 317 // type 2: adminVotesForManagement 318 319 if(_type>2) throw; // invalid type 320 return currentProposals.uints[_type].proposal; 321 } 322 """ 323 def _assert_current_on_vote_value_proposal(self, type1, expected_proposal): 324 ret = self.node.callcontract(self.contract_address, self.abiGetCurrentOnVoteValueProposal + hex(type1)[2:].zfill(64)) 325 assert_equal(int(ret['executionResult']['output'], 16), expected_proposal) 326 327 """ 328 function getParamsForBlock(uint _reqBlockHeight) constant returns (address paramsAddress){ 329 uint i; 330 for(i=paramsHistory.length-1;i>0;i--){ 331 if(paramsHistory[i].blockHeight<=_reqBlockHeight)return paramsHistory[i].paramsAddress; 332 } 333 if(paramsHistory[0].blockHeight<=_reqBlockHeight)return paramsHistory[0].paramsAddress; 334 return 0; 335 } 336 """ 337 def _assert_params_for_block(self, required_block_height, expected_param_address): 338 ret = self.node.callcontract(self.contract_address, self.abiGetParamsForBlock + hex(required_block_height)[2:].zfill(64)) 339 assert_equal(int(ret['executionResult']['output'], 16), int(expected_param_address, 16)) 340 341 """ 342 function getParamAddressAtIndex(uint _paramIndex) constant returns (address paramsAddress){ 343 return paramsHistory[_paramIndex].paramsAddress; 344 } 345 """ 346 def _assert_param_address_at_index(self, param_index, expected_param_address): 347 ret = self.node.callcontract(self.contract_address, self.abiGetParamAddressAtIndex + hex(param_index)[2:].zfill(64)) 348 assert_equal(int(ret['executionResult']['output'], 16), int(expected_param_address, 16)) 349 350 351 """ 352 function getParamHeightAtIndex(uint _paramIndex) constant returns (uint paramsHeight){ 353 return paramsHistory[_paramIndex].blockHeight; 354 } 355 """ 356 def _assert_param_block_height_at_index(self, param_index, expected_block_height): 357 ret = self.node.callcontract(self.contract_address, self.abiGetParamHeightAtIndex + hex(param_index)[2:].zfill(64)) 358 assert_equal(int(ret['executionResult']['output'], 16), expected_block_height) 359 360 """ 361 function getParamCount() constant returns (uint paramsCount){ 362 return paramsHistory.length; 363 } 364 """ 365 def _assert_param_count(self, expected_param_count): 366 ret = self.node.callcontract(self.contract_address, self.abiGetParamCount) 367 assert_equal(int(ret['executionResult']['output'], 16), expected_param_count) 368 369 def _assert_gov_keys_equal(self, expected_gov_keys): 370 real_gov_keys = read_evm_array(self.node, self.contract_address, self.abiGovKeys) 371 assert_equal(len(real_gov_keys), len(expected_gov_keys)) 372 for real, expected in zip(real_gov_keys, expected_gov_keys): 373 assert_equal(int(real, 16), int(expected, 16)) 374 375 def _assert_admin_keys_equal(self, expected_admin_keys): 376 real_admin_keys = read_evm_array(self.node, self.contract_address, self.abiAdminKeys) 377 assert_equal(len(real_admin_keys), len(expected_admin_keys)) 378 for real, expected in zip(real_admin_keys, expected_admin_keys): 379 assert_equal(int(real, 16), int(expected, 16)) 380 381 382def collect_prevouts(node, amount=None, address=None, min_confirmations=COINBASE_MATURITY, min_amount=0): 383 blocks = [] 384 for block_no in range(1, node.getblockcount()+1): 385 blocks.append(node.getblock(node.getblockhash(block_no))) 386 387 388 staking_prevouts = [] 389 for unspent in node.listunspent(): 390 for block in blocks: 391 if unspent['txid'] in block['tx']: 392 tx_block_time = block['time'] 393 break 394 else: 395 assert(False) 396 if unspent['confirmations'] > min_confirmations and (not amount or amount == unspent['amount']) and (not address or address == unspent['address']) and unspent['amount'] >= min_amount: 397 staking_prevouts.append((COutPoint(int(unspent['txid'], 16), unspent['vout']), int(unspent['amount']*COIN), tx_block_time)) 398 return staking_prevouts 399 400 401def create_unsigned_pos_block(node, staking_prevouts, nTime=None): 402 tip = node.getblock(node.getbestblockhash()) 403 if not nTime: 404 current_time = int(time.time()) + TIMESTAMP_MASK+1 405 nTime = current_time & (0xffffffff - TIMESTAMP_MASK) 406 407 parent_block_stake_modifier = int(tip['modifier'], 16) 408 coinbase = create_coinbase(tip['height']+1) 409 coinbase.vout[0].nValue = 0 410 coinbase.vout[0].scriptPubKey = b"" 411 coinbase.rehash() 412 block = create_block(int(tip['hash'], 16), coinbase, nTime) 413 block.hashStateRoot = int(tip['hashStateRoot'], 16) 414 block.hashUTXORoot = int(tip['hashUTXORoot'], 16) 415 416 if not block.solve_stake(parent_block_stake_modifier, staking_prevouts): 417 return None 418 419 txout = node.gettxout(hex(block.prevoutStake.hash)[2:].zfill(64), block.prevoutStake.n) 420 # input value + block reward 421 out_value = int((float(str(txout['value'])) + INITIAL_BLOCK_REWARD_POS) * COIN) // 2 422 423 # create a new private key used for block signing. 424 block_sig_key = ECKey() 425 block_sig_key.set(hash256(struct.pack('<I', 0)), False) 426 pubkey = block_sig_key.get_pubkey().get_bytes() 427 scriptPubKey = CScript([pubkey, OP_CHECKSIG]) 428 stake_tx_unsigned = CTransaction() 429 430 stake_tx_unsigned.vin.append(CTxIn(block.prevoutStake)) 431 stake_tx_unsigned.vout.append(CTxOut()) 432 433 # Split the output value into two separate txs 434 stake_tx_unsigned.vout.append(CTxOut(int(out_value), scriptPubKey)) 435 stake_tx_unsigned.vout.append(CTxOut(int(out_value), scriptPubKey)) 436 437 stake_tx_signed_raw_hex = node.signrawtransactionwithwallet(bytes_to_hex_str(stake_tx_unsigned.serialize()))['hex'] 438 f = io.BytesIO(hex_str_to_bytes(stake_tx_signed_raw_hex)) 439 stake_tx_signed = CTransaction() 440 stake_tx_signed.deserialize(f) 441 block.vtx.append(stake_tx_signed) 442 block.hashMerkleRoot = block.calc_merkle_root() 443 return (block, block_sig_key) 444 445 446def create_unsigned_mpos_block(node, staking_prevouts, nTime=None, block_fees=0): 447 mpos_block, block_sig_key = create_unsigned_pos_block(node, staking_prevouts, nTime) 448 tip = node.getblock(node.getbestblockhash()) 449 450 # The block reward is constant for regtest 451 stake_per_participant = int(INITIAL_BLOCK_REWARD_POS*COIN+block_fees) // MPOS_PARTICIPANTS 452 453 for i in range(MPOS_PARTICIPANTS-1): 454 partipant_block = node.getblock(node.getblockhash(tip['height']-500-i)) 455 participant_tx = node.decoderawtransaction(node.gettransaction(partipant_block['tx'][1])['hex']) 456 participant_pubkey = hex_str_to_bytes(participant_tx['vout'][1]['scriptPubKey']['asm'].split(' ')[0]) 457 mpos_block.vtx[1].vout.append(CTxOut(stake_per_participant, CScript([OP_DUP, OP_HASH160, hash160(participant_pubkey), OP_EQUALVERIFY, OP_CHECKSIG]))) 458 459 # the input value 460 txout = node.gettxout(hex(mpos_block.prevoutStake.hash)[2:], mpos_block.prevoutStake.n) 461 462 # Reward per output 463 main_staker_reward = (int(float(str(txout['value']))*COIN) + stake_per_participant) 464 465 mpos_block.vtx[1].vout[1].nValue = main_staker_reward // 2 466 mpos_block.vtx[1].vout[2].nValue = main_staker_reward // 2 467 468 stake_tx_signed_raw_hex = node.signrawtransactionwithwallet(bytes_to_hex_str(mpos_block.vtx[1].serialize()))['hex'] 469 f = io.BytesIO(hex_str_to_bytes(stake_tx_signed_raw_hex)) 470 stake_tx_signed = CTransaction() 471 stake_tx_signed.deserialize(f) 472 mpos_block.vtx[1] = stake_tx_signed 473 mpos_block.hashMerkleRoot = mpos_block.calc_merkle_root() 474 return mpos_block, block_sig_key 475 476# Generates 4490 - blockheight PoW blocks + 510 PoS blocks, 477# i.e. block height afterwards will be 5000 and we will have valid MPoS participants. 478def activate_mpos(node, use_cache=True): 479 if not node.getblockcount(): 480 node.setmocktime(int(time.time()) - 1000000) 481 node.generatetoaddress(4990-COINBASE_MATURITY-node.getblockcount(), "qSrM9K6FMhZ29Vkp8Rdk8Jp66bbfpjFETq") 482 staking_prevouts = collect_prevouts(node, address="qSrM9K6FMhZ29Vkp8Rdk8Jp66bbfpjFETq") 483 484 for i in range(COINBASE_MATURITY+10): 485 time.sleep(0.05) 486 nTime = (node.getblock(node.getbestblockhash())['time']+45) & 0xfffffff0 487 node.setmocktime(nTime) 488 block, block_sig_key = create_unsigned_pos_block(node, staking_prevouts, nTime=nTime) 489 block.sign_block(block_sig_key) 490 block.rehash() 491 block_count = node.getblockcount() 492 assert_equal(node.submitblock(bytes_to_hex_str(block.serialize())), None) 493 assert_equal(node.getblockcount(), block_count+1) 494 495 # Remove the staking prevout so we don't accidently reuse it 496 for j in range(len(staking_prevouts)): 497 prevout = staking_prevouts[j] 498 if prevout[0].serialize() == block.prevoutStake.serialize(): 499 staking_prevouts.pop(j) 500 break 501 502 if len(staking_prevouts) < 20: 503 staking_prevouts = collect_prevouts(node, address="qSrM9K6FMhZ29Vkp8Rdk8Jp66bbfpjFETq") 504 505 506def wif_to_ECKey(wif): 507 _, privkey, _ = base58_to_byte(wif, 38) 508 bytes_privkey = hex_str_to_bytes(str(privkey)[2:-1]) 509 key = ECKey() 510 # Assume always compressed, ignore last byte which specifies compression 511 key.set(bytes_privkey[:-1], True) 512 return key 513 514def create_POD(delegator, delegator_address, staker_address): 515 hex_hash = p2pkh_to_hex_hash(staker_address) 516 b64_signature = delegator.signmessage(delegator_address, hex_hash) 517 bytes_signature = base64.b64decode(b64_signature) 518 return bytes_signature 519 520def assert_delegation_reverted_with_message(delegator, abi, sender, message, gas=2250000): 521 txid = delegator.sendtocontract(DELEGATION_CONTRACT_ADDRESS, abi, 0, gas, 0.00000040, sender)['txid'] 522 delegator.generate(1) 523 receipt = delegator.gettransactionreceipt(txid)[0] 524 assert_equal(receipt['excepted'], 'Revert') 525 assert_equal(receipt['exceptedMessage'], message) 526 #print("[+] passed " + message) 527 528def assert_delegation_events_emitted(delegator, abi, sender, events=[], delegations={}, gas=2250000, expected_gas_consumed=0): 529 txid = delegator.sendtocontract(DELEGATION_CONTRACT_ADDRESS, abi, 0, gas, 0.00000040, sender)['txid'] 530 delegator.generate(1) 531 receipt = delegator.gettransactionreceipt(txid)[0] 532 533 # Verify the fields of the log are as expected 534 for ret, expected in zip(receipt['log'], events): 535 for ret_indexed, expected_indexed in zip(ret['topics'], expected['topics']): 536 assert_equal(ret_indexed, expected_indexed) 537 assert_equal(ret['data'], expected['data']) 538 539 # Check the state of the delegation attribute 540 for delegate, delegate_data in delegations.items(): 541 out = delegator.callcontract(DELEGATION_CONTRACT_ADDRESS, "bffe3486" + delegate.zfill(64))['executionResult']['output'] 542 assert_equal(out[:64], delegate_data['staker'].zfill(64)) 543 assert_equal(out[64:128], delegate_data['fee'].zfill(64)) 544 assert_equal(out[128:192], delegate_data['blockHeight'].zfill(64)) 545 assert_equal(out[192:], "80".zfill(64) + hex(65 if delegate_data['pod'] else 0)[2:].zfill(64) + delegate_data['pod']) 546 547 # Make sure we consume the minimum gas expected 548 assert(receipt['gasUsed'] > expected_gas_consumed) 549 550def get_delegate_abi(staker_address, fee, pod): 551 padded_hex_pod = bytes_to_hex_str(pod) + "00"*31 552 fee_hex = hex(fee)[2:] 553 staker_address_hex = p2pkh_to_hex_hash(staker_address) 554 abi = "4c0e968c" 555 abi += staker_address_hex.zfill(64) 556 abi += fee_hex.zfill(64) 557 abi += "60".zfill(64) 558 abi += hex(65)[2:].zfill(64) 559 abi += padded_hex_pod 560 return abi 561 562def delegate_to_staker(delegator, delegator_address, staker_address, fee, pod): 563 padded_hex_pod = bytes_to_hex_str(pod) + "00"*31 564 fee_hex = hex(fee)[2:] 565 expected_block_height = hex(delegator.getblockcount()+1)[2:] 566 staker_address_hex = p2pkh_to_hex_hash(staker_address) 567 delegator_address_hex = p2pkh_to_hex_hash(delegator_address) 568 abi = get_delegate_abi(staker_address, fee, pod) 569 assert_delegation_events_emitted(delegator, abi, delegator_address, events=[{ 570 "topics": [ 571 'a23803f3b2b56e71f2921c22b23c32ef596a439dbe03f7250e6b58a30eb910b5', # keccak256 of AddDelegation(...) 572 staker_address_hex.zfill(64), # staker 573 delegator_address_hex.zfill(64) # delegate 574 ], 575 # fee + block.number + offsetofpod + sizeofpod + pod 576 "data": fee_hex.zfill(64) + expected_block_height.zfill(64) + "60".zfill(64) + hex(65)[2:].zfill(64) + padded_hex_pod 577 }], delegations={ 578 delegator_address_hex: { 579 "fee": fee_hex, 580 "staker": staker_address_hex, 581 "blockHeight": expected_block_height, 582 "pod": padded_hex_pod 583 } 584 }, expected_gas_consumed=2000000) 585 586 587def create_delegated_pos_block(staker, staker_eckey, staker_prevout, delegator_address_hex, pod, staking_fee_percentage, delegator_prevouts, nFees=0, nTime=None, use_pos_reward=False): 588 tmp = create_unsigned_pos_block(staker, delegator_prevouts, nTime=nTime) 589 if not tmp: 590 return None 591 592 block_subsidy = INITIAL_BLOCK_REWARD_POS if use_pos_reward else INITIAL_BLOCK_REWARD 593 594 block, k = tmp 595 # change the vin from the staker input to the delegator input 596 staker_nas_txout = staker.gettxout(hex(staker_prevout.hash)[2:].zfill(64), staker_prevout.n) 597 staker_nas_input_value = int(float(str(staker_nas_txout['value']))*COIN) 598 599 block.vtx[1].vin[0] = CTxIn(staker_prevout) 600 block.vtx[1].vout[1].scriptPubKey = CScript([staker_eckey.get_pubkey().get_bytes(), OP_CHECKSIG]) 601 block.vtx[1].vout[1].nValue = int(((block_subsidy*COIN+nFees) * staking_fee_percentage) // 100) 602 block.vtx[1].vout[2].scriptPubKey = CScript([OP_DUP, OP_HASH160, hex_str_to_bytes(delegator_address_hex), OP_EQUALVERIFY, OP_CHECKSIG]) 603 block.vtx[1].vout[2].nValue = int(block_subsidy*COIN+nFees) - block.vtx[1].vout[1].nValue # subtract the staker's reward to get the delegator's reward (the delegator will ceil) 604 block.vtx[1].vout[1].nValue += staker_nas_input_value # add the input value for the staker 605 block.vtx[1] = rpc_sign_transaction(staker, block.vtx[1]) 606 block.vtx[1].rehash() 607 block.hashMerkleRoot = block.calc_merkle_root() 608 block.rehash() 609 block.sign_block(staker_eckey, pod=pod) 610 block.vchBlockSig = block.vchBlockSig + pod 611 block.rehash() 612 return block 613 614 615