def createGenesisCoinbase(signblockpubkey): genesis_coinbase = CTransaction() coinbaseinput = CTxIn(outpoint=COutPoint(0, 0), nSequence=0xffffffff) coinbaseinput.scriptSig=CScript([hex_str_to_bytes(signblockpubkey)]) genesis_coinbase.vin.append(coinbaseinput) coinbaseoutput = CTxOut() coinbaseoutput.nValue = 50 * COIN coinbaseoutput.scriptPubKey = CScript([OP_DUP, OP_HASH160, hex_str_to_bytes(signblockpubkey),OP_EQUALVERIFY, OP_CHECKSIG]) genesis_coinbase.vout.append(coinbaseoutput) genesis_coinbase.calc_sha256() return genesis_coinbase
def run_test(self): # Add p2p connection to node0 node0 = self.nodes[0] # convenience reference to the node node0.add_p2p_connection(P2PDataStore()) n0_addr = node0.getnewaddress() n0_pubk = hex_str_to_bytes(node0.getaddressinfo(n0_addr)["pubkey"]) node1 = self.nodes[1] n1_addr = node1.getnewaddress() # Generate the first block and let node0 get 50 BTC from the coinbase transaction as the initial funding best_block = node0.getblock(node0.getbestblockhash()) tip = int(node0.getbestblockhash(), 16) height = best_block["height"] + 1 block_time = best_block["time"] + 1 self.log.info("Create a new block using the coinbase of the node0.") block1 = create_block(tip, create_coinbase(height, n0_pubk), block_time) block1.solve() node0.p2p.send_blocks_and_test([block1], node0, success=True, timeout=60) self.log.info("Mature the block, make the mined BTC usable.") node0.generatetoaddress(100, node0.get_deterministic_priv_key().address) # generate 100 more blocks. assert(node0.getbalance() == 50) # node0 get the reward as a miner # craft a new transaction, which double spend the coinbase tx of node0 in block1 tx2_raw = node0.createrawtransaction( inputs = [{"txid": block1.vtx[0].hash, "vout": 0}, {"txid": block1.vtx[0].hash, "vout": 0}], outputs = {n1_addr: 100} ) tx2_sig = node0.signrawtransactionwithwallet(tx2_raw) assert_equal(tx2_sig["complete"], True) tx2_hex = tx2_sig["hex"] tct2 = CTransaction() tct2.deserialize(BytesIO(hex_str_to_bytes(tx2_hex))) best_block = node0.getblock(node0.getbestblockhash()) tip = int(node0.getbestblockhash(), 16) height = best_block["height"] + 1 block_time = best_block["time"] + 1 block2 = create_block(tip, create_coinbase(height), block_time) block2.vtx.extend([tct2]) block2.hashMerkleRoot = block2.calc_merkle_root() block2.solve() node0.p2p.send_blocks_and_test([block2], node0, success=True, timeout=60) # check the balances assert(node0.getbalance() == 0) assert(node1.getbalance() == 100) self.log.info("Successfully double spend the 50 BTCs.")
def mine_msg_txn_incorrectly(self, tip_height, tip_hash): nonce = 0 op_return_data = self.create_op_return_data(tip_height, tip_hash, nonce) tx = CTransaction() tx.vin.append(CTxIn(COutPoint(0, 0xfffffffe), b"", 0xffffffff)) tx.vout.append(CTxOut(0, CScript([OP_RETURN, op_return_data]))) tx.nLockTime = self.tx_time tx.mine() tx.rehash() self.tx_time += 1 lower_bound = get_target(tx) upper_bound = uint256_from_str( hex_str_to_bytes( "00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" )[::-1]) while tx.sha256s ^ 0x8000000000000000000000000000000000000000000000000000000000000000 <= lower_bound or \ tx.sha256s ^ 0x8000000000000000000000000000000000000000000000000000000000000000 > upper_bound: nonce += 1 op_return_data[-4:] = struct.pack("<I", nonce) tx.vout[0] = CTxOut(0, CScript([OP_RETURN, op_return_data])) tx.mine() tx.rehash() return tx
def createIncorectGenesisBlock(genesis_coinbase, signblockprivkey, signblockpubkey): genesis = CBlock() genesis.nTime = int(time.time() + 600) genesis.hashPrevBlock = 0 genesis.vtx.append(genesis_coinbase) genesis.hashMerkleRoot = genesis.calc_merkle_root() genesis.hashImMerkleRoot = genesis.calc_immutable_merkle_root() genesis.xfieldType = 1 genesis.xfield = hex_str_to_bytes(signblockpubkey) genesis.solve(signblockprivkey) return genesis
def get_target(txn): block_subsidy = 5000000000 txn_cost = get_txn_cost(txn) ratio = block_subsidy // txn_cost block_target = uint256_from_str( hex_str_to_bytes( "0000000000ffff00000000000000000000000000000000000000000000000000") [::-1]) target = block_target * ratio * TARGET_MULTIPLIER return target
def run_test(self): self.stop_node(0) shutil.rmtree(self.nodes[0].datadir) initialize_datadir(self.options.tmpdir, 0) self.log.info("Test with no genesis file") self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: unable to read genesis file', match=ErrorMatch.PARTIAL_REGEX) self.log.info("Phase 1: Tests using genesis block") self.log.info("Test correct genesis file") self.writeGenesisBlockToFile(self.nodes[0].datadir) self.start_node(0) self.stop_node(0) self.log.info("Restart with correct genesis file") self.start_node(0) self.stop_node(0) self.log.info("Test incorrect genesis block - No Coinbase") genesis_coinbase = createGenesisCoinbase(self.signblockpubkey) genesis_coinbase.vin[0].prevout.hash = 111111 genesis = createIncorectGenesisBlock(genesis_coinbase, self.signblockprivkey, self.signblockpubkey) writeIncorrectGenesisBlockToFile(self.nodes[0].datadir, genesis) self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid genesis block', match=ErrorMatch.PARTIAL_REGEX) self.log.info("Test incorrect genesis block - Incorrect height") genesis_coinbase_height = createGenesisCoinbase(self.signblockpubkey) genesis_coinbase_height.vin[0].prevout.n = 10 genesis = createIncorectGenesisBlock(genesis_coinbase_height, self.signblockprivkey, self.signblockpubkey) writeIncorrectGenesisBlockToFile(self.nodes[0].datadir, genesis) self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid height in genesis block', match=ErrorMatch.PARTIAL_REGEX) self.log.info("Test incorrect genesis block - Multiple transactions") genesis_coinbase = createGenesisCoinbase(self.signblockpubkey) genesis = createIncorectGenesisBlock(genesis_coinbase, self.signblockprivkey, self.signblockpubkey) genesis.vtx.append(CTransaction()) genesis.hashMerkleRoot = genesis.calc_merkle_root() genesis.hashImMerkleRoot = genesis.calc_immutable_merkle_root() genesis.solve(self.signblockprivkey) writeIncorrectGenesisBlockToFile(self.nodes[0].datadir, genesis) self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid genesis block', match=ErrorMatch.PARTIAL_REGEX) self.log.info("Test incorrect genesis block - No proof") genesis = createIncorectGenesisBlock(genesis_coinbase, self.signblockprivkey, self.signblockpubkey) genesis.proof.clear() writeIncorrectGenesisBlockToFile(self.nodes[0].datadir, genesis) self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid genesis block', match=ErrorMatch.PARTIAL_REGEX) self.log.info("Test incorrect genesis block - Insufficient Proof") genesis = createIncorectGenesisBlock(genesis_coinbase, self.signblockprivkey, self.signblockpubkey) genesis.proof = genesis.proof[:-1] writeIncorrectGenesisBlockToFile(self.nodes[0].datadir, genesis) self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid genesis block', match=ErrorMatch.PARTIAL_REGEX) self.log.info("Test incorrect genesis block - Incorrect xfieldType") genesis_coinbase = createGenesisCoinbase(self.signblockpubkey) genesis = CBlock() genesis.nTime = int(time.time() + 600) genesis.hashPrevBlock = 0 genesis.vtx.append(genesis_coinbase) genesis.hashMerkleRoot = genesis.calc_merkle_root() genesis.hashImMerkleRoot = genesis.calc_immutable_merkle_root() genesis.xfieldType = 0 genesis.xfield = hex_str_to_bytes(self.signblockpubkey) genesis.solve(self.signblockprivkey) writeIncorrectGenesisBlockToFile(self.nodes[0].datadir, genesis) self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid xfieldType in genesis block', match=ErrorMatch.PARTIAL_REGEX) self.log.info("Test incorrect genesis block - Incorrect xfield") genesis_coinbase = createGenesisCoinbase(self.signblockpubkey) genesis = CBlock() genesis.nTime = int(time.time() + 600) genesis.hashPrevBlock = 0 genesis.vtx.append(genesis_coinbase) genesis.hashMerkleRoot = genesis.calc_merkle_root() genesis.hashImMerkleRoot = genesis.calc_immutable_merkle_root() genesis.xfieldType = 1 genesis.xfield = hex_str_to_bytes(self.signblockpubkey[:32]) genesis.solve(self.signblockprivkey) writeIncorrectGenesisBlockToFile(self.nodes[0].datadir, genesis) self.nodes[0].assert_start_raises_init_error([], 'Aggregate Public Key for Signed Block is invalid', match=ErrorMatch.PARTIAL_REGEX) self.log.info("Test incorrect genesis block - No hashMerkleRoot") genesis_coinbase = createGenesisCoinbase(self.signblockpubkey) genesis = CBlock() genesis.nTime = int(time.time() + 600) genesis.hashPrevBlock = 0 genesis.vtx.append(genesis_coinbase) genesis.xfieldType = 1 genesis.xfield = hex_str_to_bytes(self.signblockpubkey) # not populating hashMerkleRoot and hashImMerkleRoot genesis.solve(self.signblockprivkey) writeIncorrectGenesisBlockToFile(self.nodes[0].datadir, genesis) self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid MerkleRoot in genesis block', match=ErrorMatch.PARTIAL_REGEX) self.log.info("Test incorrect genesis block - No hashImMerkleRoot") genesis_coinbase = createGenesisCoinbase(self.signblockpubkey) genesis = CBlock() genesis.nTime = int(time.time() + 600) genesis.hashPrevBlock = 0 genesis.vtx.append(genesis_coinbase) genesis.hashMerkleRoot = genesis.calc_merkle_root() genesis.xfieldType = 1 genesis.xfield = hex_str_to_bytes(self.signblockpubkey) # not populating hashImMerkleRoot genesis.solve(self.signblockprivkey) writeIncorrectGenesisBlockToFile(self.nodes[0].datadir, genesis) self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid MerkleRoot in genesis block', match=ErrorMatch.PARTIAL_REGEX) self.log.info("Phase 2: Tests using genesis.dat file") self.log.info("Test new genesis file") self.genesisBlock = None self.writeGenesisBlockToFile(self.nodes[0].datadir, nTime=int(time.time())) #different genesis file self.nodes[0].assert_start_raises_init_error([], 'Error: Incorrect or no genesis block found.', match=ErrorMatch.PARTIAL_REGEX) datadir = self.nodes[0].datadir genesisFile = os.path.join(datadir, "genesis.dat") self.log.info("Test incorrect genesis file - append 2 bytes") self.writeGenesisBlockToFile(self.nodes[0].datadir) with open(genesisFile, 'a', encoding='utf8') as f: f.write("abcd") self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid genesis file', match=ErrorMatch.PARTIAL_REGEX) os.remove(genesisFile) self.log.info("Test incorrect genesis file - append many bytes") self.writeGenesisBlockToFile(self.nodes[0].datadir) with open(genesisFile, 'a', encoding='utf8') as f: s = "".join([str(i) for i in range(0,16) for j in range(0, 100)]) f.write(s) self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid genesis file', match=ErrorMatch.PARTIAL_REGEX) os.remove(genesisFile) self.log.info("Test incorrect genesis file - replace 2 bytes") self.writeGenesisBlockToFile(self.nodes[0].datadir) with open(genesisFile, 'r+', encoding='utf8') as f: content = f.readline() clen = len(content) content = content[:500] + "0000" + content[504:] assert(len(content) == clen) f.write(content) self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid genesis file', match=ErrorMatch.PARTIAL_REGEX) os.remove(genesisFile) self.log.info("Test incorrect genesis file - insert 2 bytes") content = "" self.writeGenesisBlockToFile(self.nodes[0].datadir) with open(genesisFile, 'r+', encoding='utf8') as f: content = f.readline() clen = len(content) content = content[:550] + "1111" + content[550:] assert(len(content) == clen + 4) f.write(content) self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid genesis file', match=ErrorMatch.PARTIAL_REGEX) os.remove(genesisFile) self.log.info("Test incorrect genesis file - remove 2 bytes") content = "" self.writeGenesisBlockToFile(self.nodes[0].datadir) with open(genesisFile, 'r+', encoding='utf8') as f: content = f.readline() clen = len(content) content = content[:100] + content[104:] assert(len(content) == clen - 4) f.write(content) self.nodes[0].assert_start_raises_init_error([], 'ReadGenesisBlock: invalid genesis file', match=ErrorMatch.PARTIAL_REGEX) os.remove(genesisFile) self.log.info("Test incorrect genesis file - truncate file") self.writeGenesisBlockToFile(self.nodes[0].datadir) with open(genesisFile, 'r+', encoding='utf8') as f: f.truncate(500) self.nodes[0].assert_start_raises_init_error([], 'CDataStream::read().*end of data', match=ErrorMatch.PARTIAL_REGEX) self.log.info("Phase 3: Edit genesis file after sarting the blockchain") self.stop_node(0) shutil.rmtree(self.nodes[0].datadir) initialize_datadir(self.options.tmpdir, 0) self.log.info("Starting node") self.writeGenesisBlockToFile(self.nodes[0].datadir) self.start_node(0) self.nodes[0].add_p2p_connection(P2PInterface()) self.log.info("Generating 10 blocks") blocks = self.nodes[0].generate(10, self.signblockprivkey_wif) self.sync_all([self.nodes[0:1]]) assert_equal(self.nodes[0].getbestblockhash(), blocks[-1]) self.stop_node(0) shutil.copytree(self.nodes[0].datadir, os.path.join(self.options.tmpdir, "backup")) self.log.info("Creating corrupt genesis file") with open(genesisFile, 'r+', encoding='utf8') as f: content = f.readline() clen = len(content) content = content[:500] + "0000" + content[504:] assert(len(content) == clen) f.write(content) self.nodes[0].assert_start_raises_init_error([]) self.log.info("Starting node again") self.genesisBlock = None self.writeGenesisBlockToFile(self.nodes[0].datadir) self.nodes[0].assert_start_raises_init_error([], 'Error: Incorrect or no genesis block found.', match=ErrorMatch.PARTIAL_REGEX) self.log.info("Recovering original blockchain") shutil.rmtree(self.nodes[0].datadir) shutil.copytree(os.path.join(self.options.tmpdir, "backup"), self.nodes[0].datadir) self.start_node(0) self.nodes[0].add_p2p_connection(P2PInterface()) self.sync_all([self.nodes[0:1]]) assert_equal(self.nodes[0].getbestblockhash(), blocks[-1]) self.log.info("Blockchain intact!")
def set_test_params(self): self.setup_clean_chain = True self.num_nodes = 1 self.extra_args = [["-whitelist=127.0.0.1"]] self.signKey = Schnorr() self.signKey.set_secretbytes(hex_str_to_bytes(self.signblockprivkey))