Skip to content

Latest commit

History

57 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Bitcoin-Simulation

Introduction

Bitcoin is a decentralized digital cryptocurrency that is built upon the central idea of coming to a consensus on what verified peer-to-peer transactions happened (to avoid double-spending); this consensus is between all nodes participating within a network without reinforcement by an entity with extra power than others.

Specifically, peer-to-peer transactions are verified by other nodes on network through cryptographical utilities with the share of a public distributed ledger called a blockchain. Introduction of this currency in the network has arisen once during the creation of genesis block. It now continues to be introduced as a reward for mining an appropriate block in the blockchain.

Simulation Architecture

Key-Pair at Node

We use the Elliptic Curve Digital Signature Algorithm (ECDSA) as the algorithm to generate private and public key. We use hash160 of the public key for verifying the signature script and base58 encoding for the better visualization of addresses to ease the peer-to-peer transaction.

classNode:
def__init__(self):
self.keys=utils.generate_ec_key_pairs()
self.pub_key_hash=utils.hash160(self.keys['public'])
self.address=utils.Base58.base58encode(hash160)

Proof of Work

Central to the issue of consensus is the problem of how do all nodes on the network agree on what transactions have been made. Proof of work is a cryptographic puzzle that when one node solves first, others can verify on their own and agree to it.

Explicitly, the Bitcoin mining process incorporates a proof of work system based on Adam Back's Hashcash. It ensures two properties:

  • A node that has performed work must have made some effort (it need to be proved.)
  • That proof should be efficiently verifiable by other nodes.

Design Implementation:

  • A target hash has been set: that starts with a particular number of 0's. For e.g. "000000xxxx...x" starts with 6 zeros.
  • We double-hash (SHA-256) the serialized block header with a value called nonce until a hash is generated which is less than target hash,
  • If so then we have successfully mined a block.
  • But while doing this how do we know if some other node has mined the block first while we are still mining?
  • We have decided that our node will perform 1000 nonce values and then check its messages if it had received a newly mined correct block from the network.
  • If yes, we stop our mining, add that block in our block-chain, and start again on a new set of transactions in waiting pool (add those who are not yet included in mined block)
  • If no, then we continue our mining.

Here's a snippet of code:

classProof:
def__init__(self, block):
self.quit=Falseself.block=block# Here's our target hash in hexself.target_hash="0"*block.bits+"1"+"0"*(64-block.bits)
defrun(self, start):
# do for 1000 nonce values and then check messagesfornonceinrange(start+1, sys.maxsize): # 2^63-1ifself.quit:
returnNone_hash=self.get_hash(nonce)
if_hash<self.target_hash:
returnWork(nonce, _hash)
if(nonce%1000==0):
returnnoncedefget_hash(self, nonce):
# double hash serialized block header with nonce returndouble_sha256(self.block.get_serialized_block_header(nonce))

Coinbase Transaction

Coinbase is the first transaction in any block that is created as an incentive for successfully mining a block. Since its input transaction reference is to none, it has been decided that vout would be -1 and sig script would be any random hex string and txnid is 64 bytes - all-zero string. And its output contains the amount as a reward of 50 bitcoins (in our simulation), and script pub key contains the pub-key hash160 of the node that mined that block.

##########---------- TXN ----------##########
[@] TXNID : cd552474b06342559a3ee0f2b12aca6d8e82af4f360a9cf1b22343f244480b09#####----- Input_txn -----#####
[@] TXNID : 0000000000000000000000000000000000000000000000000000000000000000
[@] Vout : -1
[@] SigScript : d1db4326fa3a7c3fc8f312ff7c649728e4fdcd18b29e56bb47d85bd2fb4395f14747e095f2fd0b2ef56359420d7766da98c3cf17f50b848403ff7aa7df1bcae6ae94e33927517778961c398e412ad6d7e1e550f2e19cd0c7785e72cb266625b87b442553e203e848c29528e011b0ca268a0023f354f1282412931c7f0087ce4a#####----- Output TXN -----#####
[@] Amount : 50
[@] ScriptPubKey : 9e58390d0660fb71a85edc814f201e701211b632

We implement code in this fashion:

@staticmethoddefcreate_coinbase_txn(keys):
script_sig=create_script_sig(keys, "I am inevitable")
inp=InputTXN('0'*64, -1, script_sig)
script_pub_key=create_script_pub_key(keys['public'])
out=OutputTXN(config.reward, script_pub_key)
txn=TXN([inp], [out])
returntxn

Genesis Block

  • A genesis block is the first block of a blockchain. The genesis block is almost always hardcoded into the software of the applications that utilize its blockchain (as in the Bitcoin software). It is a particular case such that it does not refer to a previous block, and it produces the first unspendable subsidy.
  • Our genesis block is also hard-coded in the blockchain. When a node starts, we give him a blockchain that already comes with the genesis block. This block has one coinbase transaction that rewards node-0 50 coins.
  • We chose its hash as 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f because this is the hash of the first block of bitcoin (and it starts with at-least three zeros which is our bits limit).
  • Prev-block-hash can be anything, and since it doesn't refer to anything, we chose it to be zero.
  • It consists of one coinbase transaction, as defined above.

It looks like this (where the keys have usual meanings):

##########---------- Block ----------##########
[@] Nonce : 0
[@] Hash : 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
[@] PrevBlockHash : 0000000000000000000000000000000000000000000000000000000000000000
[@] Bits : 3
[@] MerkleRoot : 6ae340ab52b654e0a2d92a3474ae8c2e74b8cfb7cc6d066a7e3f9ce4fc3c05a7##########---------- TXN ----------##########
[@] TXNID : cd552474b06342559a3ee0f2b12aca6d8e82af4f360a9cf1b22343f244480b09#####----- Input_txn -----#####
[@] TXNID : 0000000000000000000000000000000000000000000000000000000000000000
[@] Vout : -1
[@] SigScript : d1db4326fa3a7c3fc8f312ff7c649728e4fdcd18b29e56bb47d85bd2fb4395f14747e095f2fd0b2ef56359420d7766da98c3cf17f50b848403ff7aa7df1bcae6ae94e33927517778961c398e412ad6d7e1e550f2e19cd0c7785e72cb266625b87b442553e203e848c29528e011b0ca268a0023f354f1282412931c7f0087ce4a#####----- Output TXN -----#####
[@] Amount : 50
[@] ScriptPubKey : 9e58390d0660fb71a85edc814f201e701211b632

DesignChoices and Implementation Details

Node's Working and Process Handling

Any node in the bitcoin network has the capability to do the following tasks:

  • Create a peer-to-peer transaction
  • Check for the received block if someone mined it first and verify it
  • Check for any received transaction from the network and add it in its transaction pool
  • Mine for the new block (this is optional, but we assume every node is participating in mining.)

Since in our simulation one thread is a node, our node has messages() as a queue. This thread does mining work for 1000 nonce values at a time and then stops briefly to check its messages and do the following task if required: 1. check received a transaction, check received block, or make a transaction. If no block is encountered, it continues to mine from the last nonce value, otherwise stops and starts mining for the next block.

defcheck_messages(self):
whilelen(self.messages):
withself.lock:
msg_type, msg=self.messages.popleft()
ifmsg_type=="txn":
_txn=msg.create_copy()
self.receive_txn(_txn)
elifmsg_type=="block":
block=msg.create_copy()
self.recieve_block(block)
elifmsg_type=="new_txn":
reciever_address, amount=msg[0], msg[1]
ret=self.create_txn(reciever_address, amount)

Block Verification

  • Calculate the block hash from the block header and nonce to check if the hash is calculated correctly.

  • Check the integrity of the hash of Merkle root tree

  • Check if all input transactions exist as UTXO (unspent transaction outputs)

  • For each input transaction:

  • Verify the scripting signatures and pubkeyscript

  • Verify that difference of output and input is < 0

  • For coinbase transaction:

  • Verify its vout and that its amount is no more than incentive from creating block and block fees in case any transaction it has a positive difference in input-amount and output-amount

  • If everything above is true, the block is successfully verified

Here's the snippet of the code.

defverify_block(self, block):
serial=block.get_serialized_block_header(block.nonce)
# verifying hash of blockhash_hex=double_sha256(serial)
ifnot (hash_hex==block.hashandblock.merkle_root==block.get_merkle_root_hash()):
returnFalse# block.txns[0] is coinbase [ASSUMPTION]coinbase_future_reward=0.0fortxninblock.txns[1:]:
input_amount=0.0forinp_txnintxn.inp_txns:
ifnotself.UTXOdb.search_by_txnid(inp_txn.txnid, inp_txn.vout):
returnFalseoutput_txn=self.UTXOdb.get_txn_by_txnid(inp_txn.txnid).out_txns[inp_txn.vout]
ifnotScriptInterpreter.verify_pay_to_pubkey_hash(
inp_txn.signature_script,
output_txn.script_pub_key,
inp_txn.txnid
):
returnFalseinput_amount+=output_txn.amountoutput_amount=0.0forout_txnintxn.out_txns:
output_amount+=out_txn.amountifoutput_amount>input_amount:
returnFalsecoinbase_future_reward+= (input_amount-output_amount)
# verify coinbasecoinbase=block.txns[0]
ifnot ((len(coinbase.inp_txns) ==1) and (int(coinbase.inp_txns[0].txnid, 16) ==0)
and (int(coinbase.inp_txns[0].vout) ==-1)
and (len(coinbase.out_txns) ==1)):
returnFalseifcoinbase.out_txns[0].amount>coinbase_future_reward+config.reward:
returnFalsereturnTrue

Managing Unspent Transaction Outputs (UTXOs)

  • Every node maintains the unspent transaction outputs (UTXOs) on their own. To verify if a given transaction is correctly created.

  • We have designed an n-depth-Trie data structure for it.

  • This is a tree data structure whose any node can have 0-f (hex) values till a certain depth, and then at the nth index, the transaction and its possible vouts are stored in a list. This facilitates the fast searching, adding and removal of transaction references.

  • For e.g. if we have a txn with id: ab23bcf65 and it has possible vout of 0, 1, 2; say we have a 2-depth Trie DS. We save it like this:

  • a $-&gt;$ b $-&gt;$ ["ab23bcf65": {vout:[0, 1, 2]}]

  • if I add another txn: a923bcf65 with vout as 0, 1; it will be added as: a $-&gt;$ [ b $-&gt;$ ["ab23bcf65": {vout:[0, 1, 2]}], 9 $-&gt;$ ["a923bcf65": {vout:[0, 1]}]]

  • Benefits:

  • Fewer data in memory at a time

  • A quick search for UTXOs, addition and removal

Chain Stabilization and Reorganization}

We maintain the main branch of blockchain as new blocks are getting added. This is checked by self.longest\_active\_head in chain\_stabilize.py.

Say a new block B arrives:

  • If B's previous hash is the self.longest\_active\_head of the main branch, we add the block. Removing B's input_transaction references from UTXO database and adding new output references to it.

  • If not we check where the B's previous hash is and add it there (without any change to UTXO database)

  • If after adding B the side chain becomes the longest chain in blockchain

  • Then we backtrack all the transaction of the main branch till the intersectional node and then continue on the side branch (by making a necessary change to UTXOs)

  • This would effectively make the side branch as the main branch

  • At last, we check if the side branch and main branch differs by a gap of orphan\_threshold.

  • If yes, then we remove the side branch and check if the transactions they had contained are already added in the main blockchain

  • If no, then we circulate them again on the network.

Below are the snippets of code for this implementation.

  • Backtracking on previous main branch till the cross-section block and then moving in the new main branch
    defreorganize_blocks(self, reorg_dict):
    # removing blocks in back-track of prev main chainforblockinreorg_dict['blocks_to_remove']:
    fortxninblock.txns:
    self.UTXOdb.remove_by_txn(txn)
    fortxninblock.txns[1:]:
    forinp_txnintxn.inp_txns:
    self.UTXOdb.add_by_txnid(inp_txn.txnid, inp_txn.vout)
    # adding blocks in front-track of new main chainforblockinreorg_dict['blocks_to_add']:
    fortxninblock.txns[1:]:
    forinp_txnintxn.inp_txns:
    self.UTXOdb.remove_by_txnid(inp_txn.txnid, inp_txn.vout)
    fortxninblock.txns:
    self.UTXOdb.add_by_txn(txn)
  • Distribution of unadded transactions of orphan nodes on the network
    deforphan_txns_redistribute(self):
    o_blocks=self.stabilize.check_for_orphan_nodes()
    ifo_blocks:
    forblockino_blocks:
    fortxninblock.txns:
    forinp_txnintxn.inp_txns:
    ifnotself.UTXOdb.search_by_txnid(inp_txn.txnid, inp_txn.vout):
    breakelse:
    # redistribute on networkself.network.distribute_txn(txn, self.node)

Verification of Pay to Pub Key Hash (P2PKH)}

In the Bitcoin implementation, the script\_pub\_key is written in an interpretive language called Script. It works on a series of upcode and a stack machine.

Usually, the scriptPubKey and scriptSig are something like this:

scriptPubKey: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
scriptSig: <digital-signature> <pubKey>

We assumed our scriptPubKey to be only <pubKeyHash> and the rest remains the same.

Here's how we implement it to verify.

classScriptInterpreter:
@staticmethoddefverify_pay_to_pubkey_hash(script_signature, pub_key_script, message):
signature=script_signature[:128]
pub_key=script_signature[128:]
pub_hash160=utils.hash160(pub_key)
ifnot (pub_hash160.strip() ==pub_key_script.strip()):
returnFalsevk=VerifyingKey.from_string(bytearray.fromhex(pub_key),
curve=ecdsa.SECP256k1)
returnvk.verify(bytearray.fromhex(signature), str.encode(message))

Relevance of Network

Network in a peer-2-peer decentralized currency should not be something that knows all nodes. But for the 'simplicity in simulation,' we assume Network to be in a star topology. Which can with simple ease extended to a ring topology as it usually is. Our Network consists of these static methods. That any node can lock and use.

classNetwork:
nodes= [] # star topology (can be extended to ring)address_map= {} # pub_key_hash -> index in nodes@staticmethoddefadd_node(n):
pass@staticmethoddefcreate_nodes(num_nodes):
pass@staticmethoddefget_blockchain():
pass@staticmethoddefdistribute_txn(txn, src_node):
pass@staticmethoddefdistribute_block(block, src_node):
pass

Graphs

Arity of Merkle Tree vs Time Taken by transaction

\includesvg[]{first.svg}

\noindent We can see from the graph above that the merkle root has very little effect on the time taken to perform the transactions. This is mainly because most of the time is spent in message propagation and mining, not calculating the merkle root of the block.

Time Taken by transaction vs Number of Nodes

\includesvg[]{last.svg}

We can see from the above graph that the time taken to complete the transactions has little effect of the number of nodes too. The time taken increases with the number of nodes because number of message to be passed increases. On the other hand, time taken should decrease with increasing number of nodes because the number of miners increases. We see a little increment in the time taken with increasing number of nodes.

How To Run

Run the following command to execute a demo blockchain network:

python3 main.py

Sample Code output

Nodes after Genesis Block addition


##########---------- Node ----------##########
[@] Private Key : 7070ffdae5897a54d2124914587caad3b6e1648f2e5eacd0ae2d8eeb25bf0a0b
[@] Public Key : 32f0cebd6f98e066648c0e1d92c5a5de64705292aa03ba81f6aa6184f9cc83bf222dfae4
8d5ce5b56cba07c538efba84f82be699824f1678596b0009f1ed8c5a
[@] Pub Key Hash : dc8b202ad8ecadffafc7d1aa5aa4b696bdaa437c
[@] Blockchain
9 -> 9 -> {'99261eb646696af903700b6126056eac289ed2e7cd7648572de8219544837548': {'vout': [0], 'txn': <transaction.TXN object at 0x7fa59e37b100>}}
None
##########---------- Node ----------##########
[@] Private Key : 20b2965794b6d2e3bb0da6200b663fa565e7459853a396c885933822520ec12f
[@] Public Key : eef5bc528f92a677cf25b2a574858a8260ee27ed8ff9134a99c8f54f629c74e21b1b19
ca93bd181ef7e9922295f576f7ad0111b29cd68009812ce081c74e5a31
[@] Pub Key Hash : f10c89ae22a31d7e95abdab913e2d1eee1fe0092
[@] Blockchain
9 -> 9 -> {'99261eb646696af903700b6126056eac289ed2e7cd7648572de8219544837548': {'vout': [0], 'txn': <transaction.TXN object at 0x7fa59e37b370>}}
None
##########---------- Node ----------##########
[@] Private Key : 5c68085c1ae7b08e23c2dc16d1e08dd9ba42e5c5f765b75ca42ef4e67c60af34
[@] Public Key : 03501620f33d91a4796a9064f44bd7385475b224880c56233e28ba987c6900981c7c9de
88de22ccbeef5c7a36fa2da407c63bdf14cf2f42b8aafb46dbbdaaa41
[@] Pub Key Hash : 47a4352e855f1eb66d2a1edaf873428545035b17
[@] Blockchain
9 -> 9 -> {'99261eb646696af903700b6126056eac289ed2e7cd7648572de8219544837548': {'vout': [0], 'txn': <transaction.TXN object at 0x7fa59e37b730>}}
None

Transactions Created

[****************------ CREATING-TXN-----************]
[#] From: dc8b202ad8ecadffafc7d1aa5aa4b696bdaa437c
[#] To: f10c89ae22a31d7e95abdab913e2d1eee1fe0092
[+] Amount: 10
[****************------ CREATING-TXN-----************]
[#] From: dc8b202ad8ecadffafc7d1aa5aa4b696bdaa437c
[#] To: 47a4352e855f1eb66d2a1edaf873428545035b17
[+] Amount: 10
T: Thread-1 [CREATED] [TXN]
T: Thread-1 [CREATED] [TXN]

Nodes receive Transaction

T: Thread-1 [RECEIVED] [TXN]
T: Thread-1 [RECEIVED] [TXN]
T: Thread-3 [RECEIVED] [TXN]
T: Thread-2 [RECEIVED] [TXN]
T: Thread-3 [RECEIVED] [TXN]
T: Thread-2 [RECEIVED] [TXN]

Node 1 creates Block

 ##########---------- Block ----------##########
[@] Nonce : 36841
[@] Hash : 0000450737917e2d614173fe1e8d866507411c75c797c38355aa342675388b55
[@] Prev Block Hash : 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
[@] Bits : 3
[@] Merkle Root : 21931f86c91616da9528f15df4b3da43b879c0325eddfa29a80236c806f148a3
##########---------- TXN ----------##########
[@] TXNID : 3371529ac1139726e934c9c1ee530ac6f6d3e458f5f90a5a40d23284d4ffa8c5
#####----- Input_txn -----#####
[@] TXNID : 0000000000000000000000000000000000000000000000000000000000000000
[@] Vout : -1
[@] Sig Script : bbe841999d597959e8ecaeffd4370fc986cad10e2db82db103f4
7b39435557caa809c8f471fadce5d93073ec43952aa9aca76bb5e992a6f0416d142e23cac18732f
0cebd6f98e066648c0e1d92c5a5de64705292aa03ba81f6aa6184f9cc83bf222dfae48d5ce5b56c
ba07c538efba84f82be699824f1678596b0009f1ed8c5a
#####----- Output TXN -----#####
[@] Amount : 50
[@] Script Pub Key : dc8b202ad8ecadffafc7d1aa5aa4b696bdaa437c
##########---------- TXN ----------##########
[@] TXNID : 22eac2119f1fb2ab42f89b4984dc11d63e9f2fdfc5f0133d7d1de5f3ed93f6b9
#####----- Input_txn -----#####
[@] TXNID : 99261eb646696af903700b6126056eac289ed2e7cd7648572de8219544837548
[@] Vout : 0
[@] Sig Script : 40ad21a23b1757c92e8ccf6d480435494be144faa87f9c883b3c1100fa2d876e4c1946
8e465237dfe5faf3ef552d25df69c56382d1a2582e9588a973e6f9b34632f0cebd6f98e066648c0
e1d92c5a5de64705292aa03ba81f6aa6184f9cc83bf222dfae48d5ce5b56cba07c538efba84f82b
e699824f1678596b0009f1ed8c5a
#####----- Output TXN -----#####
[@] Amount : 10
[@] Script Pub Key : f10c89ae22a31d7e95abdab913e2d1eee1fe0092
#####----- Output TXN -----#####
[@] Amount : 40
[@] Script Pub Key : dc8b202ad8ecadffafc7d1aa5aa4b696bdaa437c
##########---------- TXN ----------##########
[@] TXNID : 8d1da70aaa10685f9b0776a4b519a4f953e15cd720e748246877b2c21ecad641
#####----- Input_txn -----#####
[@] TXNID : 99261eb646696af903700b6126056eac289ed2e7cd7648572de8219544837548
[@] Vout : 0
[@] Sig Script : f82fd437bf99fa92c9b1b1037660a00e5e5e6d03839a3a112863fcb0271410352aa255
ec5d3092dd9830bd610ba743b090a699b195a9bdc0d8f0bca5d347cb8a32f0cebd6f98e066648c0e
1d92c5a5de64705292aa03ba81f6aa6184f9cc83bf222dfae48d5ce5b56cba07c538efba84f82be6
99824f1678596b0009f1ed8c5a
#####----- Output TXN -----#####
[@] Amount : 10
[@] Script Pub Key : 47a4352e855f1eb66d2a1edaf873428545035b17
#####----- Output TXN -----#####
[@] Amount : 40
[@] Script Pub Key : dc8b202ad8ecadffafc7d1aa5aa4b696bdaa437c

Threads receive block

T: Thread-1 [MINED] [BLOCK]
T: Thread-3 [RECEIVED] [BLOCK]
T: Thread-2 [RECEIVED] [BLOCK]

Final Nodes state

 ##########---------- Node ----------##########
[@] Private Key : 7070ffdae5897a54d2124914587caad3b6e1648f2e5eacd0ae2d8eeb25bf0a0b
[@] Public Key : 32f0cebd6f98e066648c0e1d92c5a5de64705292aa03ba81f6aa6184f9cc83bf222d
fae48d5ce5b56cba07c538efba84f82be699824f1678596b0009f1ed8c5a
[@] Pub Key Hash : dc8b202ad8ecadffafc7d1aa5aa4b696bdaa437c
[@] Blockchain
9 -> 9 -> {'99261eb646696af903700b6126056eac289ed2e7cd7648572de8219544837548': {'vout': [], 'txn': <transaction.TXN object at 0x7fa59e37b100>}}
3 -> 3 -> {'3371529ac1139726e934c9c1ee530ac6f6d3e458f5f90a5a40d23284d4ffa8c5': {'vout': [0], 'txn': <transaction.TXN object at 0x7fa59e384d00>}}
2 -> 2 -> {'22eac2119f1fb2ab42f89b4984dc11d63e9f2fdfc5f0133d7d1de5f3ed93f6b9': {'vout': [1], 'txn': <transaction.TXN object at 0x7fa59e3846d0>}}
8 -> d -> {'8d1da70aaa10685f9b0776a4b519a4f953e15cd720e748246877b2c21ecad641': {'vout': [1], 'txn': <transaction.TXN object at 0x7fa59e384280>}}
c -> 0 -> {'c0583a7c8b452431e7325fc89bbcf71b45d371e0703dbcaaf0d932f6994f2b51': {'vout': [0], 'txn': <transaction.TXN object at 0x7fa59e38b640>}}
7 -> 3 -> {'731f1e1b47aae77f6af664dd0dcf8cd86092fd3e3a5bdc767ac28e0bce1ccb51': {'vout': [0, 1], 'txn': <transaction.TXN object at 0x7fa59e38b220>}}
b -> e -> {'be40b74b74987db30c5bd7ccfef438db8916ecf41c6c169793dbb615b575ed31': {'vout': [0], 'txn': <transaction.TXN object at 0x7fa59e395220>}}
f -> 9 -> {'f953022d66559099b0a6273bed8264d31eb2d17c31ed4755ef4d2981c4abf329': {'vout': [0, 1], 'txn': <transaction.TXN object at 0x7fa59e395a00>}}
None
p: 0000000000000000000000000000000000000000000000000000000000000000 h: 0 id: 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f child: -> [ p: 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f h: 1 id: 0000450737917e2d614173fe1e8d866507411c75c797c38355aa342675388b55 child: -> [ p: 0000450737917e2d614173fe1e8d866507411c75c797c38355aa342675388b55 h: 2 id: 0000fee2b5d27728dd0f1059fed245cbcf5679f43bc1dda3c8f3e74bbe7ae566 child: -> [ p: 0000fee2b5d27728dd0f1059fed245cbcf5679f43bc1dda3c8f3e74bbe7ae566 h: 3 id: 000090b4c68274236560f4ce15b53ad6a6de5c7e3631513a5ccc210008e3116c child: -> []]]]
##########---------- Node ----------##########
[@] Private Key : 20b2965794b6d2e3bb0da6200b663fa565e7459853a396c885933822520ec12f
[@] Public Key : eef5bc528f92a677cf25b2a574858a8260ee27ed8ff9134a99c8f54f629c74e21b1b
19ca93bd181ef7e9922295f576f7ad0111b29cd68009812ce081c74e5a31
[@] Pub Key Hash : f10c89ae22a31d7e95abdab913e2d1eee1fe0092
[@] Blockchain
9 -> 9 -> {'99261eb646696af903700b6126056eac289ed2e7cd7648572de8219544837548': {'vout': [], 'txn': <transaction.TXN object at 0x7fa59e37b370>}}
3 -> 3 -> {'3371529ac1139726e934c9c1ee530ac6f6d3e458f5f90a5a40d23284d4ffa8c5': {'vout': [0], 'txn': <transaction.TXN object at 0x7fa59e384190>}}
2 -> 2 -> {'22eac2119f1fb2ab42f89b4984dc11d63e9f2fdfc5f0133d7d1de5f3ed93f6b9': {'vout': [1], 'txn': <transaction.TXN object at 0x7fa59e384730>}}
8 -> d -> {'8d1da70aaa10685f9b0776a4b519a4f953e15cd720e748246877b2c21ecad641': {'vout': [1], 'txn': <transaction.TXN object at 0x7fa59e384490>}}
c -> 0 -> {'c0583a7c8b452431e7325fc89bbcf71b45d371e0703dbcaaf0d932f6994f2b51': {'vout': [0], 'txn': <transaction.TXN object at 0x7fa59e384be0>}}
7 -> 3 -> {'731f1e1b47aae77f6af664dd0dcf8cd86092fd3e3a5bdc767ac28e0bce1ccb51': {'vout': [0, 1], 'txn': <transaction.TXN object at 0x7fa59e38d340>}}
b -> e -> {'be40b74b74987db30c5bd7ccfef438db8916ecf41c6c169793dbb615b575ed31': {'vout': [0], 'txn': <transaction.TXN object at 0x7fa59e38ddf0>}}
f -> 9 -> {'f953022d66559099b0a6273bed8264d31eb2d17c31ed4755ef4d2981c4abf329': {'vout': [0, 1], 'txn': <transaction.TXN object at 0x7fa59e38db80>}}
None
p: 0000000000000000000000000000000000000000000000000000000000000000 h: 0 id: 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f child: -> [ p: 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f h: 1 id: 0000450737917e2d614173fe1e8d866507411c75c797c38355aa342675388b55 child: -> [ p: 0000450737917e2d614173fe1e8d866507411c75c797c38355aa342675388b55 h: 2 id: 0000fee2b5d27728dd0f1059fed245cbcf5679f43bc1dda3c8f3e74bbe7ae566 child: -> [ p: 0000fee2b5d27728dd0f1059fed245cbcf5679f43bc1dda3c8f3e74bbe7ae566 h: 3 id: 000090b4c68274236560f4ce15b53ad6a6de5c7e3631513a5ccc210008e3116c child: -> []]]]
##########---------- Node ----------##########
[@] Private Key : 5c68085c1ae7b08e23c2dc16d1e08dd9ba42e5c5f765b75ca42ef4e67c60af34
[@] Public Key : 03501620f33d91a4796a9064f44bd7385475b224880c56233e28ba987c6900981c7c9
de88de22ccbeef5c7a36fa2da407c63bdf14cf2f42b8aafb46dbbdaaa41
[@] Pub Key Hash : 47a4352e855f1eb66d2a1edaf873428545035b17
[@] Blockchain
9 -> 9 -> {'99261eb646696af903700b6126056eac289ed2e7cd7648572de8219544837548': {'vout': [], 'txn': <transaction.TXN object at 0x7fa59e37b730>}}
3 -> 3 -> {'3371529ac1139726e934c9c1ee530ac6f6d3e458f5f90a5a40d23284d4ffa8c5': {'vout': [0], 'txn': <transaction.TXN object at 0x7fa59e38b6d0>}}
2 -> 2 -> {'22eac2119f1fb2ab42f89b4984dc11d63e9f2fdfc5f0133d7d1de5f3ed93f6b9': {'vout': [1], 'txn': <transaction.TXN object at 0x7fa59e38b7f0>}}
8 -> d -> {'8d1da70aaa10685f9b0776a4b519a4f953e15cd720e748246877b2c21ecad641': {'vout': [1], 'txn': <transaction.TXN object at 0x7fa59e38b970>}}
c -> 0 -> {'c0583a7c8b452431e7325fc89bbcf71b45d371e0703dbcaaf0d932f6994f2b51': {'vout': [0], 'txn': <transaction.TXN object at 0x7fa59e384eb0>}}
7 -> 3 -> {'731f1e1b47aae77f6af664dd0dcf8cd86092fd3e3a5bdc767ac28e0bce1ccb51': {'vout': [0, 1], 'txn': <transaction.TXN object at 0x7fa59e384d60>}}
b -> e -> {'be40b74b74987db30c5bd7ccfef438db8916ecf41c6c169793dbb615b575ed31': {'vout': [0], 'txn': <transaction.TXN object at 0x7fa59e38dee0>}}
f -> 9 -> {'f953022d66559099b0a6273bed8264d31eb2d17c31ed4755ef4d2981c4abf329': {'vout': [0, 1], 'txn': <transaction.TXN object at 0x7fa59e38dca0>}}
None
p: 0000000000000000000000000000000000000000000000000000000000000000 h: 0 id: 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f child: -> [ p: 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f h: 1 id: 0000450737917e2d614173fe1e8d866507411c75c797c38355aa342675388b55 child: -> [ p: 0000450737917e2d614173fe1e8d866507411c75c797c38355aa342675388b55 h: 2 id: 0000fee2b5d27728dd0f1059fed245cbcf5679f43bc1dda3c8f3e74bbe7ae566 child: -> [ p: 0000fee2b5d27728dd0f1059fed245cbcf5679f43bc1dda3c8f3e74bbe7ae566 h: 3 id: 000090b4c68274236560f4ce15b53ad6a6de5c7e3631513a5ccc210008e3116c child: -> []]]]

References

About

Simulating an implementation of complete Bitcoin system with multi-transaction support

Topics

Resources

Stars

7 stars

Watchers

3 watching

Forks

Releases

Packages

Contributors

Languages