├── tests ├── test_block.py ├── __init__.py ├── config │ ├── valid │ │ └── config.yml │ └── invalid │ │ ├── config_corrupt_hash.yml │ │ ├── config_corrupt_previous_hash.yml │ │ └── config_corrupt_transactions.yml ├── test_blockchain.py └── data │ ├── invalid │ ├── invalid_blockchain_corrupt_hash.json │ ├── invalid_blockchain_corrupt_previous_hash.json │ └── invalid_blockchain_corrupt_transactions.json │ └── valid │ └── valid_blockchain.json ├── _config.yml ├── .gitignore ├── libbc ├── __init__.py ├── transaction.py ├── ledgerentry.py ├── block.py └── blockchain.py ├── config.yml ├── main.py ├── README.md └── data └── sumeet-blockchain.json /tests/test_block.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | __pycache__ 3 | *.pyc -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | from .test_blockchain import TestBlockChainMethods 2 | -------------------------------------------------------------------------------- /libbc/__init__.py: -------------------------------------------------------------------------------- 1 | from .blockchain import BlockChain 2 | from .ledgerentry import LedgerEntry 3 | -------------------------------------------------------------------------------- /tests/config/valid/config.yml: -------------------------------------------------------------------------------- 1 | # Block chain config 2 | 3 | name: valid_blockchain 4 | # block mining difficulty 5 | difficulty: 4 6 | # miner reward 7 | reward: 10 8 | # test mode false, does not dump or read blockchain file 9 | testMode: false 10 | 11 | # file dump configs 12 | dump: 13 | dir: data/valid 14 | # if filename is null, use blockchain name 15 | file: null 16 | -------------------------------------------------------------------------------- /tests/config/invalid/config_corrupt_hash.yml: -------------------------------------------------------------------------------- 1 | # Block chain config 2 | 3 | name: invalid_blockchain_corrupt_hash 4 | # block mining difficulty 5 | difficulty: 4 6 | # miner reward 7 | reward: 10 8 | # test mode false, does not dump or read blockchain file 9 | testMode: false 10 | 11 | # file dump configs 12 | dump: 13 | dir: data/invalid 14 | # if filename is null, use blockchain name 15 | file: null 16 | -------------------------------------------------------------------------------- /tests/config/invalid/config_corrupt_previous_hash.yml: -------------------------------------------------------------------------------- 1 | # Block chain config 2 | 3 | name: invalid_blockchain_corrupt_previous_hash 4 | # block mining difficulty 5 | difficulty: 4 6 | # miner reward 7 | reward: 10 8 | # test mode false, does not dump or read blockchain file 9 | testMode: false 10 | 11 | # file dump configs 12 | dump: 13 | dir: data/invalid 14 | # if filename is null, use blockchain name 15 | file: null 16 | -------------------------------------------------------------------------------- /tests/config/invalid/config_corrupt_transactions.yml: -------------------------------------------------------------------------------- 1 | # Block chain config 2 | 3 | name: invalid_blockchain_corrupt_transactions 4 | # block mining difficulty 5 | difficulty: 4 6 | # miner reward 7 | reward: 10 8 | # test mode false, does not dump or read blockchain file 9 | testMode: false 10 | 11 | # file dump configs 12 | dump: 13 | dir: data/invalid 14 | # if filename is null, use blockchain name 15 | file: null 16 | -------------------------------------------------------------------------------- /config.yml: -------------------------------------------------------------------------------- 1 | # Block chain config 2 | 3 | name: sumeet-blockchain 4 | 5 | # block mining difficulty 6 | difficulty: 4 7 | 8 | # miner reward 9 | reward: 10 10 | 11 | # test mode false, does not dump or read blockchain file 12 | testMode: false 13 | 14 | 15 | # file dump configs 16 | dump: 17 | dir: data 18 | # if filename is null, use blockchain name 19 | file: null 20 | # frequency of dump, after every 'block', or 'end' 21 | frequency: block 22 | -------------------------------------------------------------------------------- /libbc/transaction.py: -------------------------------------------------------------------------------- 1 | """ 2 | Transaction 3 | """ 4 | 5 | 6 | class Transaction: 7 | def __init__(self, fromUser, toUser, amount): 8 | self.__fromUser = fromUser 9 | self.__toUser = toUser 10 | self.__amount = amount 11 | 12 | @property 13 | def fromUser(self): 14 | return self.__fromUser 15 | 16 | @property 17 | def toUser(self): 18 | return self.__toUser 19 | 20 | @property 21 | def amount(self): 22 | return self.__amount 23 | 24 | @property 25 | def summary(self): 26 | return dict(fromUser=self.fromUser, 27 | toUser=self.toUser, 28 | amount=self.amount, 29 | ) 30 | -------------------------------------------------------------------------------- /libbc/ledgerentry.py: -------------------------------------------------------------------------------- 1 | """ 2 | LedgerEntry: 3 | Every ledger entry record creates 2 transactions 4 | """ 5 | 6 | from .transaction import Transaction 7 | 8 | 9 | class LedgerEntry: 10 | def __init__(self, fromUser, toUser, amount): 11 | self.__creditTransaction = Transaction(fromUser, toUser, amount) 12 | self.__debitTransaction = Transaction(toUser, fromUser, amount * -1) 13 | 14 | @property 15 | def creditTransaction(self): 16 | return self.__creditTransaction 17 | 18 | @property 19 | def debitTransaction(self): 20 | return self.__debitTransaction 21 | 22 | @property 23 | def transactions(self): 24 | return [ 25 | self.creditTransaction, 26 | self.debitTransaction, 27 | ] 28 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | """ 2 | Demonstrates usage of the BlockChain demo library 3 | """ 4 | 5 | import os 6 | from libbc import BlockChain 7 | from libbc import LedgerEntry 8 | 9 | # create block chain instance with difficulty 1 and reward 10 units 10 | currentDir = os.path.dirname(__file__) 11 | configPath = os.path.join(currentDir, 'config.yml') 12 | 13 | with BlockChain(configPath, currentDir) as bc: 14 | # create list of transactions from ledger entry 15 | listOfTransactions = [] 16 | listOfTransactions += LedgerEntry('userA', 'userB', 400).transactions 17 | listOfTransactions += LedgerEntry('userA', 'userC', 200).transactions 18 | # add list of transactions to the block chain 19 | bc.add_block(listOfTransactions, 'sumeetsarkar') 20 | 21 | # list the entire block chain so far 22 | print('\n\nBlock chain so far...') 23 | print('---------------------') 24 | bc.list_chain() 25 | 26 | # create list of transactions from ledger entry 27 | listOfTransactions = [] 28 | listOfTransactions += LedgerEntry('userA', 'userB', 900).transactions 29 | listOfTransactions += LedgerEntry('userC', 'userD', 500).transactions 30 | # add list of transactions to the block chain 31 | bc.add_block(listOfTransactions, 'sumeetsarkar') 32 | 33 | # list the entire block chain so far 34 | print('\n\nBlock chain so far...') 35 | print('---------------------') 36 | bc.list_chain() 37 | 38 | # check the validity of the block chain 39 | print('\n\nBlock chain validity', bc.is_valid()) 40 | 41 | bc.compute_statement_for_user('userA') 42 | bc.compute_statement_for_user('userB') 43 | bc.compute_statement_for_user('userC') 44 | bc.compute_statement_for_user('userD') 45 | bc.compute_statement_for_user('sumeetsarkar') 46 | bc.compute_statement_for_user('sumeet-blockchain') 47 | -------------------------------------------------------------------------------- /tests/test_blockchain.py: -------------------------------------------------------------------------------- 1 | """ 2 | Validates the sample block chain 3 | """ 4 | 5 | import os 6 | import json 7 | import unittest 8 | 9 | from libbc import BlockChain 10 | 11 | 12 | class TestBlockChainMethods(unittest.TestCase): 13 | 14 | def setUp(self): 15 | # prepare file paths 16 | self.__currentDir = os.path.dirname(__file__) 17 | self.__configValid = os.path.join( 18 | self.__currentDir, 'config/valid', 'config.yml') 19 | self.__configInvalidCorruptHash = os.path.join( 20 | self.__currentDir, 'config/invalid', 'config_corrupt_hash.yml') 21 | self.__configInvalidCorruptPreviousHash = os.path.join( 22 | self.__currentDir, 'config/invalid', 'config_corrupt_previous_hash.yml') 23 | self.__configInvalidCorruptTransaction = os.path.join( 24 | self.__currentDir, 'config/invalid', 'config_corrupt_transactions.yml') 25 | 26 | def test_valid(self): 27 | with BlockChain(self.__configValid, self.__currentDir) as bc: 28 | result = bc.is_valid() 29 | self.assertTrue(result[0]) 30 | self.assertIsNone(result[1]) 31 | 32 | def test_invalid_hash(self): 33 | with BlockChain(self.__configInvalidCorruptHash, self.__currentDir) as bc: 34 | result = bc.is_valid() 35 | self.assertFalse(result[0]) 36 | self.assertIsNotNone(result[1]) 37 | 38 | def test_invalid_previous_hash(self): 39 | with BlockChain(self.__configInvalidCorruptPreviousHash, self.__currentDir) as bc: 40 | result = bc.is_valid() 41 | self.assertFalse(result[0]) 42 | self.assertIsNotNone(result[1]) 43 | 44 | def test_invalid_corrupt_transaction(self): 45 | with BlockChain(self.__configInvalidCorruptTransaction, self.__currentDir) as bc: 46 | result = bc.is_valid() 47 | self.assertFalse(result[0]) 48 | self.assertIsNotNone(result[1]) 49 | 50 | def test_compute_statement_for_user(self): 51 | with BlockChain(self.__configValid, self.__currentDir) as bc: 52 | totalCredit, totalDebit = bc.compute_statement_for_user( 53 | 'userA', False) 54 | self.assertEqual(totalCredit, 0) 55 | self.assertEqual(totalDebit, -3000) 56 | totalCredit, totalDebit = bc.compute_statement_for_user( 57 | 'userC', False) 58 | self.assertEqual(totalCredit, 400) 59 | self.assertEqual(totalDebit, -1000) 60 | 61 | 62 | if __name__ == '__main__': 63 | unittest.main() 64 | -------------------------------------------------------------------------------- /tests/data/invalid/invalid_blockchain_corrupt_hash.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "version": "1", 4 | "previousHash": -1, 5 | "merkelRoot": -1, 6 | "timeInSeconds": "1539805452", 7 | "hash": "f3f6388ca55f468ffc2d87073944c20b26c9519eb31560eeade15f0daa89bb80", 8 | "nounce": 0, 9 | "difficulty": 0, 10 | "numTransactions": 0, 11 | "transactions": [] 12 | }, 13 | { 14 | "version": "1", 15 | "previousHash": "f3f6388ca55f468ffc2d87073944c20b26c9519eb31560eeade15f0daa89bb80", 16 | "merkelRoot": "e6b8da89aa107105dd309131ebf607f875c135bacc4d030205794e224b1f7d01", 17 | "timeInSeconds": "1539805452", 18 | "hash": "000000512efb131c4f62e8d470d23d764f7220818213fd87dd40c0f081c2ab34", 19 | "nounce": 27598251, 20 | "difficulty": 6, 21 | "numTransactions": 6, 22 | "transactions": [ 23 | { 24 | "fromUser": "sumeet-blockchain", 25 | "toUser": "sumeetsarkar", 26 | "amount": 10 27 | }, 28 | { 29 | "fromUser": "sumeetsarkar", 30 | "toUser": "sumeet-blockchain", 31 | "amount": -10 32 | }, 33 | { 34 | "fromUser": "userA", 35 | "toUser": "userB", 36 | "amount": 400 37 | }, 38 | { 39 | "fromUser": "userB", 40 | "toUser": "userA", 41 | "amount": -400 42 | }, 43 | { 44 | "fromUser": "userA", 45 | "toUser": "userC", 46 | "amount": 200 47 | }, 48 | { 49 | "fromUser": "userC", 50 | "toUser": "userA", 51 | "amount": -200 52 | } 53 | ] 54 | }, 55 | { 56 | "version": "1", 57 | "previousHash": "000000512efb131c4f62e8d470d23d764f7220818213fd87dd40c0f081c2ab34", 58 | "merkelRoot": "85904c2e9b04ee07709055efae00202fb993ac32dae918b7b9d8b3d308e563d6", 59 | "timeInSeconds": "1539805600", 60 | "hash": "000000bceeedbb3f8b570612305fa8049afdbc199551bf47eecbb665e7450067", 61 | "nounce": 2471841, 62 | "difficulty": 6, 63 | "numTransactions": 6, 64 | "transactions": [ 65 | { 66 | "fromUser": "sumeet-blockchain", 67 | "toUser": "sumeetsarkar", 68 | "amount": 10 69 | }, 70 | { 71 | "fromUser": "sumeetsarkar", 72 | "toUser": "sumeet-blockchain", 73 | "amount": -10 74 | }, 75 | { 76 | "fromUser": "userA", 77 | "toUser": "userB", 78 | "amount": 900 79 | }, 80 | { 81 | "fromUser": "userB", 82 | "toUser": "userA", 83 | "amount": -900 84 | }, 85 | { 86 | "fromUser": "userC", 87 | "toUser": "userD", 88 | "amount": 500 89 | }, 90 | { 91 | "fromUser": "userD", 92 | "toUser": "userC", 93 | "amount": -500 94 | } 95 | ] 96 | } 97 | ] -------------------------------------------------------------------------------- /tests/data/invalid/invalid_blockchain_corrupt_previous_hash.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "version": "1", 4 | "previousHash": -1, 5 | "merkelRoot": -1, 6 | "timeInSeconds": "1539805452", 7 | "hash": "f3f6388ca55f468ffc2d87073944c20b26c9519eb31560eeade15f0daa89bb80", 8 | "nounce": 0, 9 | "difficulty": 0, 10 | "numTransactions": 0, 11 | "transactions": [] 12 | }, 13 | { 14 | "version": "1", 15 | "previousHash": "f3f6388ca55f468ffc2d87073944c20b26c9519eb31560eeade15f0daa89bb80", 16 | "merkelRoot": "e6b8da89aa107105dd309131ebf607f875c135bacc4d030205794e224b1f7d01", 17 | "timeInSeconds": "1539805452", 18 | "hash": "000000512efb131c4f62e8d470d23d764f7220818213fd87dd40c0f081c2ab34", 19 | "nounce": 27598251, 20 | "difficulty": 6, 21 | "numTransactions": 6, 22 | "transactions": [ 23 | { 24 | "fromUser": "sumeet-blockchain", 25 | "toUser": "sumeetsarkar", 26 | "amount": 10 27 | }, 28 | { 29 | "fromUser": "sumeetsarkar", 30 | "toUser": "sumeet-blockchain", 31 | "amount": -10 32 | }, 33 | { 34 | "fromUser": "userA", 35 | "toUser": "userB", 36 | "amount": 400 37 | }, 38 | { 39 | "fromUser": "userB", 40 | "toUser": "userA", 41 | "amount": -400 42 | }, 43 | { 44 | "fromUser": "userA", 45 | "toUser": "userC", 46 | "amount": 200 47 | }, 48 | { 49 | "fromUser": "userC", 50 | "toUser": "userA", 51 | "amount": -200 52 | } 53 | ] 54 | }, 55 | { 56 | "version": "1", 57 | "previousHash": "000000512efb13112362e8d470d23d764f7220818213fd87dd40c0f081c2ab34", 58 | "merkelRoot": "85904c2e9b04ee07709055efae00202fb993ac32dae918b7b9d8b3d308e563d6", 59 | "timeInSeconds": "1539805600", 60 | "hash": "000000bceeedbb3f8b570612305fa8049afdbc199551bf47eecbb665e7450067", 61 | "nounce": 2471841, 62 | "difficulty": 6, 63 | "numTransactions": 6, 64 | "transactions": [ 65 | { 66 | "fromUser": "sumeet-blockchain", 67 | "toUser": "sumeetsarkar", 68 | "amount": 10 69 | }, 70 | { 71 | "fromUser": "sumeetsarkar", 72 | "toUser": "sumeet-blockchain", 73 | "amount": -10 74 | }, 75 | { 76 | "fromUser": "userA", 77 | "toUser": "userB", 78 | "amount": 900 79 | }, 80 | { 81 | "fromUser": "userB", 82 | "toUser": "userA", 83 | "amount": -900 84 | }, 85 | { 86 | "fromUser": "userC", 87 | "toUser": "userD", 88 | "amount": 500 89 | }, 90 | { 91 | "fromUser": "userD", 92 | "toUser": "userC", 93 | "amount": -500 94 | } 95 | ] 96 | } 97 | ] -------------------------------------------------------------------------------- /tests/data/invalid/invalid_blockchain_corrupt_transactions.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "version": "1", 4 | "previousHash": -1, 5 | "merkelRoot": -1, 6 | "timeInSeconds": "1539805452", 7 | "hash": "f3f6388ca55f468ffc2d87073944c20b26c9519eb31560eeade15f0daa89bb80", 8 | "nounce": 0, 9 | "difficulty": 0, 10 | "numTransactions": 0, 11 | "transactions": [] 12 | }, 13 | { 14 | "version": "1", 15 | "previousHash": "f3f6388ca55f468ffc2d87073944c20b26c9519eb31560eeade15f0daa89bb80", 16 | "merkelRoot": "e6b8da89aa107105dd309131ebf607f875c135bacc4d030205794e224b1f7d01", 17 | "timeInSeconds": "1539805452", 18 | "hash": "000000512efb131c4f62e8d470d23d764f7220818213fd87dd40c0f081c2ab34", 19 | "nounce": 27598251, 20 | "difficulty": 6, 21 | "numTransactions": 6, 22 | "transactions": [ 23 | { 24 | "fromUser": "sumeet-blockchain", 25 | "toUser": "sumeetsarkar", 26 | "amount": 10 27 | }, 28 | { 29 | "fromUser": "sumeetsarkar", 30 | "toUser": "sumeet-blockchain", 31 | "amount": -10 32 | }, 33 | { 34 | "fromUser": "userA", 35 | "toUser": "userB", 36 | "amount": 400 37 | }, 38 | { 39 | "fromUser": "userB", 40 | "toUser": "userA", 41 | "amount": -400 42 | }, 43 | { 44 | "fromUser": "userA", 45 | "toUser": "userC", 46 | "amount": 200 47 | }, 48 | { 49 | "fromUser": "userC", 50 | "toUser": "userA", 51 | "amount": -200 52 | } 53 | ] 54 | }, 55 | { 56 | "version": "1", 57 | "previousHash": "000000512efb131c4f62e8d470d23d764f7220818213fd87dd40c0f081c2ab34", 58 | "merkelRoot": "85904c2e9b04ee07709055efae00202fb993ac32dae918b7b9d8b3d308e563d6", 59 | "timeInSeconds": "1539805600", 60 | "hash": "000000bceeedbb3f8b57060b105fa8049afdbc199551bf47eecbb665e7450067", 61 | "nounce": 2471841, 62 | "difficulty": 6, 63 | "numTransactions": 6, 64 | "transactions": [ 65 | { 66 | "fromUser": "sumeet-blockchain", 67 | "toUser": "sumeetsarkar", 68 | "amount": 10 69 | }, 70 | { 71 | "fromUser": "sumeetsarkar", 72 | "toUser": "sumeet-blockchain", 73 | "amount": -10 74 | }, 75 | { 76 | "fromUser": "userA", 77 | "toUser": "userB", 78 | "amount": 1100 79 | }, 80 | { 81 | "fromUser": "userB", 82 | "toUser": "userA", 83 | "amount": -900 84 | }, 85 | { 86 | "fromUser": "userC", 87 | "toUser": "userD", 88 | "amount": 500 89 | }, 90 | { 91 | "fromUser": "userD", 92 | "toUser": "userC", 93 | "amount": -500 94 | } 95 | ] 96 | } 97 | ] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > Sample BlockChain demo lib in python 2 | 3 | ## Quickstart 4 | 5 | ### [main.py](main.py) demostrates sample usage of BlockChain package 6 | 7 | Run app 8 | ``` 9 | python3 main.py 10 | ``` 11 | 12 | Run test 13 | ``` 14 | python3 -m unittest tests/test_blockchain.py 15 | ``` 16 | 17 | ## Package usage 18 | ### [BlockChain](libbc/blockchain.py) 19 | 20 | The class BlockChain is used as a context manager 21 | 22 | Upon instantiation it, 23 | - Reads & loads the yaml config 24 | - If run in testMode, all operations are in memory and previous blockchain state is neither read from file, nor new blocks are dumped to file on end 25 | - However, testMode or not, if the loaded chain is empty, a genesis block is created and transactions are accepted so on 26 | 27 | ```python 28 | from libbc import BlockChain 29 | 30 | configPath = 31 | currentDir = 32 | 33 | with BlockChain(configPath, currentDir) as bc: 34 | 35 | # add transactions to the block chain, 36 | # arg1: transaction array 37 | # arg2: miner account 38 | # Note: every add block call to blockchain 39 | # adds a ledger entry of the miner reward 40 | bc.add_block([], 'sumeetsarkar') 41 | 42 | # list the block chain so far in json 43 | bc.list_chain() 44 | 45 | # checks for validity of the block chain 46 | # returns tuple 47 | # True, None 48 | # False, Corrupted Block instance 49 | # Blockchain is first validated before every block addition 50 | bc.is_valid() 51 | 52 | # prints account summary of transactions for given user 53 | # returns tuple, (totalCredit, totalDebit) 54 | bc.compute_statement_for_user('userA') 55 | ``` 56 | 57 | ### [LedgerEntry](libbc/ledgerentry.py) 58 | 59 | Each [LedgerEntry](libbc/ledgerentry.py) is recorded as two transactions using class [Transaction](libbc/transaction.py) 60 | 61 | ```python 62 | from libbc import LedgerEntry 63 | 64 | le = LedgerEntry('userA', 'userB', 400) 65 | 66 | # transactions is a property of LE, returning the array of transactions in ledger 67 | le.transactions 68 | ``` 69 | 70 | ## [BlockChain Config](config.yml) 71 | ```yaml 72 | # Block chain config 73 | 74 | name: 75 | 76 | # block mining difficulty 77 | difficulty: 4 78 | 79 | # miner reward 80 | reward: 10 81 | 82 | # test mode false, does not dump or read blockchain file 83 | # transactions are volatile 84 | testMode: false 85 | 86 | 87 | # file dump configs 88 | dump: 89 | dir: data 90 | # if filename is null, use blockchain name 91 | file: null 92 | # frequency of dump, after every 'block', or 'end' 93 | frequency: block 94 | 95 | ``` 96 | 97 | ## Block Definition from BlockChain 98 | 99 | Following information is captured in every block 100 | - Block version 101 | - Previous block hash 102 | - Block hash 103 | - Merkel root of transactions (includes miner reward) 104 | - Time in seconds of request for block creation 105 | - Nounce 106 | - Difficulty 107 | - Number of transactions 108 | - List of transactions 109 | 110 | 111 | ## Hash Algorithm 112 | 113 | ### SHA256(SHA256(Block_Header)) 114 | 115 | Block_Header = (version + previousHash + merkelRoot + timeInSeconds + Nounce) 116 | 117 | 118 | ## Sample Block 119 | 120 | ```json 121 | { 122 | "version": "1", 123 | "previousHash": "837dd71bf9814c03689aad9a9c963df41421de96fe40dae2e1b56898d3aeb5c7", 124 | "merkelRoot": "e6b8da89aa107105dd309131ebf607f875c135bacc4d030205794e224b1f7d01", 125 | "timeInSeconds": "1539871539", 126 | "hash": "000094fb9324ccf419b6c8eee13c068dcf24d7976d47839c1c7d73daf35c4f9a", 127 | "nounce": 35955, 128 | "difficulty": 4, 129 | "numTransactions": 6, 130 | "transactions": [ 131 | { 132 | "fromUser": "sumeet-blockchain", 133 | "toUser": "sumeetsarkar", 134 | "amount": 10 135 | }, 136 | { 137 | "fromUser": "sumeetsarkar", 138 | "toUser": "sumeet-blockchain", 139 | "amount": -10 140 | }, 141 | { 142 | "fromUser": "userA", 143 | "toUser": "userB", 144 | "amount": 400 145 | }, 146 | { 147 | "fromUser": "userB", 148 | "toUser": "userA", 149 | "amount": -400 150 | }, 151 | { 152 | "fromUser": "userA", 153 | "toUser": "userC", 154 | "amount": 200 155 | }, 156 | { 157 | "fromUser": "userC", 158 | "toUser": "userA", 159 | "amount": -200 160 | } 161 | ] 162 | }, 163 | ``` -------------------------------------------------------------------------------- /tests/data/valid/valid_blockchain.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "version": "1", 4 | "previousHash": -1, 5 | "merkelRoot": -1, 6 | "timeInSeconds": "1539809774", 7 | "hash": "cec28aaa0de2aa3df6cdd4390b25b39325a20e48cc12a28971da21cdb3317e43", 8 | "nounce": 0, 9 | "difficulty": 0, 10 | "numTransactions": 0, 11 | "transactions": [] 12 | }, 13 | { 14 | "version": "1", 15 | "previousHash": "cec28aaa0de2aa3df6cdd4390b25b39325a20e48cc12a28971da21cdb3317e43", 16 | "merkelRoot": "e6b8da89aa107105dd309131ebf607f875c135bacc4d030205794e224b1f7d01", 17 | "timeInSeconds": "1539809774", 18 | "hash": "00004c2deae5eed5ccfa33041d84c8bcf06f07bcace24b6fb73b2f07e36871a8", 19 | "nounce": 3811, 20 | "difficulty": 4, 21 | "numTransactions": 6, 22 | "transactions": [ 23 | { 24 | "fromUser": "sumeet-blockchain", 25 | "toUser": "sumeetsarkar", 26 | "amount": 10 27 | }, 28 | { 29 | "fromUser": "sumeetsarkar", 30 | "toUser": "sumeet-blockchain", 31 | "amount": -10 32 | }, 33 | { 34 | "fromUser": "userA", 35 | "toUser": "userB", 36 | "amount": 400 37 | }, 38 | { 39 | "fromUser": "userB", 40 | "toUser": "userA", 41 | "amount": -400 42 | }, 43 | { 44 | "fromUser": "userA", 45 | "toUser": "userC", 46 | "amount": 200 47 | }, 48 | { 49 | "fromUser": "userC", 50 | "toUser": "userA", 51 | "amount": -200 52 | } 53 | ] 54 | }, 55 | { 56 | "version": "1", 57 | "previousHash": "00004c2deae5eed5ccfa33041d84c8bcf06f07bcace24b6fb73b2f07e36871a8", 58 | "merkelRoot": "85904c2e9b04ee07709055efae00202fb993ac32dae918b7b9d8b3d308e563d6", 59 | "timeInSeconds": "1539809774", 60 | "hash": "0000e429ca7a07b64cf525deb0f94d2d47db257e8faeb33c7798aecb0962e84b", 61 | "nounce": 42544, 62 | "difficulty": 4, 63 | "numTransactions": 6, 64 | "transactions": [ 65 | { 66 | "fromUser": "sumeet-blockchain", 67 | "toUser": "sumeetsarkar", 68 | "amount": 10 69 | }, 70 | { 71 | "fromUser": "sumeetsarkar", 72 | "toUser": "sumeet-blockchain", 73 | "amount": -10 74 | }, 75 | { 76 | "fromUser": "userA", 77 | "toUser": "userB", 78 | "amount": 900 79 | }, 80 | { 81 | "fromUser": "userB", 82 | "toUser": "userA", 83 | "amount": -900 84 | }, 85 | { 86 | "fromUser": "userC", 87 | "toUser": "userD", 88 | "amount": 500 89 | }, 90 | { 91 | "fromUser": "userD", 92 | "toUser": "userC", 93 | "amount": -500 94 | } 95 | ] 96 | }, 97 | { 98 | "version": "1", 99 | "previousHash": "0000e429ca7a07b64cf525deb0f94d2d47db257e8faeb33c7798aecb0962e84b", 100 | "merkelRoot": "e6b8da89aa107105dd309131ebf607f875c135bacc4d030205794e224b1f7d01", 101 | "timeInSeconds": "1539891309", 102 | "hash": "00001e162987626cbbd979183790692daaee261765181e80317db9c522c0de68", 103 | "nounce": 27475, 104 | "difficulty": 4, 105 | "numTransactions": 6, 106 | "transactions": [ 107 | { 108 | "fromUser": "sumeet-blockchain", 109 | "toUser": "sumeetsarkar", 110 | "amount": 10 111 | }, 112 | { 113 | "fromUser": "sumeetsarkar", 114 | "toUser": "sumeet-blockchain", 115 | "amount": -10 116 | }, 117 | { 118 | "fromUser": "userA", 119 | "toUser": "userB", 120 | "amount": 400 121 | }, 122 | { 123 | "fromUser": "userB", 124 | "toUser": "userA", 125 | "amount": -400 126 | }, 127 | { 128 | "fromUser": "userA", 129 | "toUser": "userC", 130 | "amount": 200 131 | }, 132 | { 133 | "fromUser": "userC", 134 | "toUser": "userA", 135 | "amount": -200 136 | } 137 | ] 138 | }, 139 | { 140 | "version": "1", 141 | "previousHash": "00001e162987626cbbd979183790692daaee261765181e80317db9c522c0de68", 142 | "merkelRoot": "85904c2e9b04ee07709055efae00202fb993ac32dae918b7b9d8b3d308e563d6", 143 | "timeInSeconds": "1539891309", 144 | "hash": "000050d7df20f0b49933897219d500038cc1f5a34e78d04dd21da593edeabc0f", 145 | "nounce": 172547, 146 | "difficulty": 4, 147 | "numTransactions": 6, 148 | "transactions": [ 149 | { 150 | "fromUser": "sumeet-blockchain", 151 | "toUser": "sumeetsarkar", 152 | "amount": 10 153 | }, 154 | { 155 | "fromUser": "sumeetsarkar", 156 | "toUser": "sumeet-blockchain", 157 | "amount": -10 158 | }, 159 | { 160 | "fromUser": "userA", 161 | "toUser": "userB", 162 | "amount": 900 163 | }, 164 | { 165 | "fromUser": "userB", 166 | "toUser": "userA", 167 | "amount": -900 168 | }, 169 | { 170 | "fromUser": "userC", 171 | "toUser": "userD", 172 | "amount": 500 173 | }, 174 | { 175 | "fromUser": "userD", 176 | "toUser": "userC", 177 | "amount": -500 178 | } 179 | ] 180 | } 181 | ] -------------------------------------------------------------------------------- /libbc/block.py: -------------------------------------------------------------------------------- 1 | """ 2 | Block 3 | """ 4 | 5 | import json 6 | import time 7 | import datetime 8 | import hashlib 9 | from .transaction import Transaction 10 | 11 | 12 | class Block: 13 | def __init__(self, jsonData, listOfTransaction=[], previousHash=-1, difficulty=0): 14 | if jsonData: 15 | self.__load_from_json(jsonData) 16 | else: 17 | self.initialize(listOfTransaction, previousHash, difficulty) 18 | self.__strData = self.__version + \ 19 | str(self.__previousHash) + str(self.__merkelRoot) + \ 20 | str(self.__timeInSeconds) 21 | 22 | @property 23 | def listOfTransaction(self): 24 | return self.__listOfTransaction 25 | 26 | @property 27 | def previousHash(self): 28 | return self.__previousHash 29 | 30 | @property 31 | def hash(self): 32 | return self.__hash 33 | 34 | @property 35 | def summary(self): 36 | return dict(version=self.__version, 37 | previousHash=self.previousHash, 38 | merkelRoot=self.__merkelRoot, 39 | timeInSeconds=str(self.__timeInSeconds), 40 | hash=self.hash, 41 | nounce=self.__nounce, 42 | difficulty=self.__difficulty, 43 | numTransactions=len(self.listOfTransaction), 44 | ) 45 | 46 | # private method 47 | def initialize(self, listOfTransaction, previousHash, difficulty): 48 | self.__version = '1' 49 | self.__listOfTransaction = listOfTransaction 50 | self.__previousHash = previousHash 51 | self.__hash = -1 52 | self.__timeInSeconds = int(time.mktime( 53 | datetime.datetime.today().timetuple())) 54 | self.__difficulty = difficulty 55 | # below fields are to precompute static data for quicker __compute_hash iterations 56 | listOfTransactionInStringArray = self.__build_transactions_array_of_strings() 57 | # build merkel root of the transactions 58 | self.__merkelRoot = self.__build_merkel_root( 59 | listOfTransactionInStringArray) 60 | # build string concatenated data, used to compute block hash (except nounce) 61 | # nounce is the only variable incrementer in hash 62 | self.__nounce = 0 63 | 64 | # private method 65 | 66 | def __load_from_json(self, jsonData): 67 | self.__version = jsonData.get('version') 68 | self.__previousHash = jsonData.get('previousHash') 69 | self.__hash = jsonData.get('hash') 70 | self.__timeInSeconds = jsonData.get('timeInSeconds') 71 | self.__difficulty = jsonData.get('difficulty') 72 | self.__merkelRoot = jsonData.get('merkelRoot') 73 | self.__nounce = jsonData.get('nounce') 74 | self.__listOfTransaction = [] 75 | for t in jsonData.get('transactions'): 76 | tran = Transaction(t.get('fromUser'), t.get( 77 | 'toUser'), t.get('amount')) 78 | self.__listOfTransaction.append(tran) 79 | 80 | # private method 81 | 82 | def __build_sha256_hexdigest(self, strdata): 83 | b = bytes(strdata, 'UTF8') 84 | h = hashlib.sha256() 85 | h.update(b) 86 | return h.hexdigest() 87 | 88 | # private method 89 | 90 | def __build_transactions_array_of_strings(self): 91 | list = [] 92 | for t in self.__listOfTransaction: 93 | list.append(json.dumps(t.summary)) 94 | return list 95 | 96 | # private method 97 | 98 | def __build_merkel_root(self, list): 99 | n = len(list) 100 | if n == 1: 101 | return list[0] 102 | elif n == 0: 103 | return -1 104 | nextList = [] 105 | if n % 2 != 0: 106 | l = n - 2 107 | else: 108 | l = n - 1 109 | for i in range(0, l, 2): 110 | leaf1 = self.__build_sha256_hexdigest(list[i]) 111 | leaf2 = self.__build_sha256_hexdigest(list[i + 1]) 112 | combinedLeaf = self.__build_sha256_hexdigest(leaf1 + leaf2) 113 | nextList.append(combinedLeaf) 114 | if l == n - 2: 115 | leafOdd = self.__build_sha256_hexdigest(list[n - 1]) 116 | nextList.append(leafOdd) 117 | return self.__build_merkel_root(nextList) 118 | 119 | # private method 120 | 121 | def __compute_hash(self): 122 | strdata = self.__strData + str(self.__nounce) 123 | # SHA256(SHA256(Block_Header)) 124 | return self.__build_sha256_hexdigest(str(self.__build_sha256_hexdigest(strdata))) 125 | 126 | # private method 127 | 128 | def __generate_diffculty_string(self): 129 | difficultyString = '' 130 | difficulty = self.__difficulty 131 | while difficulty != 0: 132 | difficultyString += '0' 133 | difficulty -= 1 134 | return difficultyString 135 | 136 | def is_hash_matching(self): 137 | difficultyString = self.__generate_diffculty_string() 138 | return self.hash[0:int(self.__difficulty)] == difficultyString and self.hash == self.__compute_hash() 139 | 140 | def is_merkel_matching(self): 141 | listOfTransactionInStringArray = self.__build_transactions_array_of_strings() 142 | return self.__merkelRoot == self.__build_merkel_root(listOfTransactionInStringArray) 143 | 144 | def mine(self): 145 | print('\n\nMining new block chain with difficulty: ' + 146 | str(self.__difficulty)) 147 | h = self.__compute_hash() 148 | difficultyString = self.__generate_diffculty_string() 149 | # mine until the difficulty criteria is met with generated hash 150 | while h[0:int(self.__difficulty)] != difficultyString: 151 | # update nounce each time to generate different hash, which may meet the difficulty criteria 152 | self.__nounce += 1 153 | h = self.__compute_hash() 154 | # set the computed hash 155 | self.__hash = h 156 | -------------------------------------------------------------------------------- /libbc/blockchain.py: -------------------------------------------------------------------------------- 1 | """ 2 | BlockChain 3 | """ 4 | 5 | import os 6 | import sys 7 | import json 8 | import yaml 9 | from .block import Block 10 | from .ledgerentry import LedgerEntry 11 | 12 | 13 | class BlockChain: 14 | 15 | def __init__(self, configPath, fileRootDir=''): 16 | if configPath is None: 17 | raise Exception('Config file Path missing') 18 | self.__configPath = configPath 19 | self.__fileRootDir = fileRootDir 20 | 21 | def __enter__(self): 22 | try: 23 | # read yaml file and load 24 | with open(self.__configPath) as f: 25 | self.__ymlConfig = next(yaml.load_all(f)) 26 | self.__applyConfig() 27 | return self 28 | except Exception as e: 29 | print('Error reading config file', self.__configPath, e) 30 | 31 | def __exit__(self, *args): 32 | self.dump_blockchain_to_file() 33 | 34 | def __applyConfig(self): 35 | # initialize empty chain 36 | self.__chain = [] 37 | # load values from yaml file 38 | self.__name = self.__ymlConfig['name'] 39 | self.__difficulty = self.__ymlConfig['difficulty'] 40 | self.__minerReward = self.__ymlConfig['reward'] 41 | self.__previousHashForGenesis = self.__ymlConfig.get( 42 | 'genesisPreviousHash', -1) 43 | self.__testMode = self.__ymlConfig['testMode'] 44 | # check if file dump config is specified, mandatory if testMode is False 45 | if self.__ymlConfig.get('dump') is None and self.__testMode is False: 46 | raise Exception('No file dump information specified in config') 47 | if self.__testMode is False: 48 | dirname = self.__ymlConfig.get('dump')['dir'] 49 | filename = self.__ymlConfig.get('dump').get('file') 50 | self.__dumpFrequency = self.__ymlConfig.get( 51 | 'dump').get('frequency', 'block') 52 | if filename is None: 53 | filename = self.__name 54 | filename += '.json' 55 | # form file dump path 56 | self.__filePath = os.path.join( 57 | self.__fileRootDir, dirname, filename) 58 | self.__load_blockchain_from_file() 59 | else: 60 | self.__dumpFrequency = None 61 | self.__filePath = None 62 | self.__chain.append(self.__create_genesis_block()) 63 | 64 | def __load_blockchain_from_file(self): 65 | """Loads previously saved blockchain json from file 66 | If file is empty/ or read error, creates genesis block and starts the chain 67 | """ 68 | try: 69 | with open(self.__filePath, 'rt') as f: 70 | jsonArray = json.load(f) 71 | for jsonBlock in jsonArray: 72 | self.__chain.append(Block(jsonBlock)) 73 | except Exception as e: 74 | print('Error loading blockchain from file', self.__filePath, e) 75 | finally: 76 | if len(self.__chain) == 0: 77 | self.__chain.append(self.__create_genesis_block()) 78 | 79 | # private method 80 | 81 | def __create_genesis_block(self): 82 | # create and return genesis block only if chain is empty 83 | if len(self.__chain) == 0: 84 | genesisblock = Block(None, [], self.__previousHashForGenesis, 0) 85 | genesisblock.mine() 86 | return genesisblock 87 | else: 88 | raise Exception( 89 | 'Genesis block can only be created when chain is empty') 90 | 91 | # private method 92 | 93 | def __get_last_block(self): 94 | # check if chain is empty 95 | if len(self.__chain) == 0: 96 | raise Exception('Empty chain') 97 | else: 98 | return self.__chain[len(self.__chain) - 1] 99 | 100 | def add_block(self, listOfTransactions, minerName): 101 | # check for block chain validity 102 | isValid, compromisedBlock = self.is_valid() 103 | if isValid is False: 104 | raise Exception(self.__name + ' block chain is compromised!', 105 | isValid, compromisedBlock.summary) 106 | # get last block in chain 107 | lastBlockInChain = self.__get_last_block() 108 | # create new block with concatenated 1 reward transaction + list of transactions to add in block 109 | listOfTransactions = LedgerEntry( 110 | self.__name, minerName, self.__minerReward).transactions + listOfTransactions 111 | newBlock = Block(None, listOfTransactions, 112 | lastBlockInChain.hash, self.__difficulty) 113 | # Proof of Work Phase: mine new block with set diffculty 114 | newBlock.mine() 115 | # append newly mined block to the block chain 116 | self.__chain.append(newBlock) 117 | if self.__dumpFrequency == 'block': 118 | self.dump_blockchain_to_file() 119 | 120 | def is_valid(self): 121 | previousHash = self.__previousHashForGenesis 122 | for block in self.__chain: 123 | if block.is_hash_matching() is False: 124 | return False, block 125 | if block.is_merkel_matching() is False: 126 | return False, block 127 | if block.previousHash != previousHash: 128 | return False, block 129 | previousHash = block.hash 130 | return True, None 131 | 132 | def dump_blockchain_to_file(self): 133 | if self.__filePath is None: 134 | return 135 | jsonArray = [] 136 | for block in self.__chain: 137 | parsedTransaction = [] 138 | for tran in block.listOfTransaction: 139 | parsedTransaction.append(tran.summary) 140 | parsedData = json.loads(json.dumps(block.summary)) 141 | parsedData['transactions'] = parsedTransaction 142 | jsonArray.append(parsedData) 143 | with open(self.__filePath, 'w+') as f: 144 | json.dump(jsonArray, f, indent=2) 145 | 146 | def list_chain(self): 147 | for block in self.__chain: 148 | parsedTransaction = [] 149 | for tran in block.listOfTransaction: 150 | parsedTransaction.append(tran.summary) 151 | parsedData = json.loads(json.dumps(block.summary)) 152 | parsedData['transactions'] = parsedTransaction 153 | print(json.dumps(parsedData, indent=2)) 154 | 155 | def compute_statement_for_user(self, user, logSummary=True): 156 | totalDebit = 0 157 | totalCredit = 0 158 | if logSummary: 159 | print('\nLisiting ' + user + ' transactions...') 160 | for block in self.__chain: 161 | for tran in block.listOfTransaction: 162 | if tran.fromUser == user and tran.amount > 0: 163 | totalDebit -= tran.amount 164 | if logSummary: 165 | print(tran.summary) 166 | elif tran.toUser == user and tran.amount > 0: 167 | totalCredit += tran.amount 168 | if logSummary: 169 | print(tran.summary) 170 | if logSummary: 171 | print('Credits : ' + str(totalCredit)) 172 | print('Debits : ' + str(totalDebit)) 173 | print('Balance : ' + str(totalCredit + totalDebit)) 174 | return totalCredit, totalDebit 175 | -------------------------------------------------------------------------------- /data/sumeet-blockchain.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "version": "1", 4 | "previousHash": -1, 5 | "merkelRoot": -1, 6 | "timeInSeconds": "1539871539", 7 | "hash": "837dd71bf9814c03689aad9a9c963df41421de96fe40dae2e1b56898d3aeb5c7", 8 | "nounce": 0, 9 | "difficulty": 0, 10 | "numTransactions": 0, 11 | "transactions": [] 12 | }, 13 | { 14 | "version": "1", 15 | "previousHash": "837dd71bf9814c03689aad9a9c963df41421de96fe40dae2e1b56898d3aeb5c7", 16 | "merkelRoot": "e6b8da89aa107105dd309131ebf607f875c135bacc4d030205794e224b1f7d01", 17 | "timeInSeconds": "1539871539", 18 | "hash": "000094fb9324ccf419b6c8eee13c068dcf24d7976d47839c1c7d73daf35c4f9a", 19 | "nounce": 35955, 20 | "difficulty": 4, 21 | "numTransactions": 6, 22 | "transactions": [ 23 | { 24 | "fromUser": "sumeet-blockchain", 25 | "toUser": "sumeetsarkar", 26 | "amount": 10 27 | }, 28 | { 29 | "fromUser": "sumeetsarkar", 30 | "toUser": "sumeet-blockchain", 31 | "amount": -10 32 | }, 33 | { 34 | "fromUser": "userA", 35 | "toUser": "userB", 36 | "amount": 400 37 | }, 38 | { 39 | "fromUser": "userB", 40 | "toUser": "userA", 41 | "amount": -400 42 | }, 43 | { 44 | "fromUser": "userA", 45 | "toUser": "userC", 46 | "amount": 200 47 | }, 48 | { 49 | "fromUser": "userC", 50 | "toUser": "userA", 51 | "amount": -200 52 | } 53 | ] 54 | }, 55 | { 56 | "version": "1", 57 | "previousHash": "000094fb9324ccf419b6c8eee13c068dcf24d7976d47839c1c7d73daf35c4f9a", 58 | "merkelRoot": "85904c2e9b04ee07709055efae00202fb993ac32dae918b7b9d8b3d308e563d6", 59 | "timeInSeconds": "1539871540", 60 | "hash": "0000bd24ef3bf01bfa95e4a946653bbcaf63ff264873dbc3babcee7386db21f6", 61 | "nounce": 42021, 62 | "difficulty": 4, 63 | "numTransactions": 6, 64 | "transactions": [ 65 | { 66 | "fromUser": "sumeet-blockchain", 67 | "toUser": "sumeetsarkar", 68 | "amount": 10 69 | }, 70 | { 71 | "fromUser": "sumeetsarkar", 72 | "toUser": "sumeet-blockchain", 73 | "amount": -10 74 | }, 75 | { 76 | "fromUser": "userA", 77 | "toUser": "userB", 78 | "amount": 900 79 | }, 80 | { 81 | "fromUser": "userB", 82 | "toUser": "userA", 83 | "amount": -900 84 | }, 85 | { 86 | "fromUser": "userC", 87 | "toUser": "userD", 88 | "amount": 500 89 | }, 90 | { 91 | "fromUser": "userD", 92 | "toUser": "userC", 93 | "amount": -500 94 | } 95 | ] 96 | }, 97 | { 98 | "version": "1", 99 | "previousHash": "0000bd24ef3bf01bfa95e4a946653bbcaf63ff264873dbc3babcee7386db21f6", 100 | "merkelRoot": "e6b8da89aa107105dd309131ebf607f875c135bacc4d030205794e224b1f7d01", 101 | "timeInSeconds": "1539871575", 102 | "hash": "00007737d592bf23462e8804576cf6c35e9bd9b26ada1c9eb55562e4344283db", 103 | "nounce": 510028, 104 | "difficulty": 4, 105 | "numTransactions": 6, 106 | "transactions": [ 107 | { 108 | "fromUser": "sumeet-blockchain", 109 | "toUser": "sumeetsarkar", 110 | "amount": 10 111 | }, 112 | { 113 | "fromUser": "sumeetsarkar", 114 | "toUser": "sumeet-blockchain", 115 | "amount": -10 116 | }, 117 | { 118 | "fromUser": "userA", 119 | "toUser": "userB", 120 | "amount": 400 121 | }, 122 | { 123 | "fromUser": "userB", 124 | "toUser": "userA", 125 | "amount": -400 126 | }, 127 | { 128 | "fromUser": "userA", 129 | "toUser": "userC", 130 | "amount": 200 131 | }, 132 | { 133 | "fromUser": "userC", 134 | "toUser": "userA", 135 | "amount": -200 136 | } 137 | ] 138 | }, 139 | { 140 | "version": "1", 141 | "previousHash": "00007737d592bf23462e8804576cf6c35e9bd9b26ada1c9eb55562e4344283db", 142 | "merkelRoot": "85904c2e9b04ee07709055efae00202fb993ac32dae918b7b9d8b3d308e563d6", 143 | "timeInSeconds": "1539871578", 144 | "hash": "000012cf97ed3273bd799e84b6cba5c8116dba1f7369dd496fc4fa4806e6adcb", 145 | "nounce": 11216, 146 | "difficulty": 4, 147 | "numTransactions": 6, 148 | "transactions": [ 149 | { 150 | "fromUser": "sumeet-blockchain", 151 | "toUser": "sumeetsarkar", 152 | "amount": 10 153 | }, 154 | { 155 | "fromUser": "sumeetsarkar", 156 | "toUser": "sumeet-blockchain", 157 | "amount": -10 158 | }, 159 | { 160 | "fromUser": "userA", 161 | "toUser": "userB", 162 | "amount": 900 163 | }, 164 | { 165 | "fromUser": "userB", 166 | "toUser": "userA", 167 | "amount": -900 168 | }, 169 | { 170 | "fromUser": "userC", 171 | "toUser": "userD", 172 | "amount": 500 173 | }, 174 | { 175 | "fromUser": "userD", 176 | "toUser": "userC", 177 | "amount": -500 178 | } 179 | ] 180 | }, 181 | { 182 | "version": "1", 183 | "previousHash": "000012cf97ed3273bd799e84b6cba5c8116dba1f7369dd496fc4fa4806e6adcb", 184 | "merkelRoot": "e6b8da89aa107105dd309131ebf607f875c135bacc4d030205794e224b1f7d01", 185 | "timeInSeconds": "1539871622", 186 | "hash": "000021c2b5d916d53e7322ae639c5879f4126264d3b59e73792cbef55954b4e0", 187 | "nounce": 8164, 188 | "difficulty": 4, 189 | "numTransactions": 6, 190 | "transactions": [ 191 | { 192 | "fromUser": "sumeet-blockchain", 193 | "toUser": "sumeetsarkar", 194 | "amount": 10 195 | }, 196 | { 197 | "fromUser": "sumeetsarkar", 198 | "toUser": "sumeet-blockchain", 199 | "amount": -10 200 | }, 201 | { 202 | "fromUser": "userA", 203 | "toUser": "userB", 204 | "amount": 400 205 | }, 206 | { 207 | "fromUser": "userB", 208 | "toUser": "userA", 209 | "amount": -400 210 | }, 211 | { 212 | "fromUser": "userA", 213 | "toUser": "userC", 214 | "amount": 200 215 | }, 216 | { 217 | "fromUser": "userC", 218 | "toUser": "userA", 219 | "amount": -200 220 | } 221 | ] 222 | }, 223 | { 224 | "version": "1", 225 | "previousHash": "000021c2b5d916d53e7322ae639c5879f4126264d3b59e73792cbef55954b4e0", 226 | "merkelRoot": "85904c2e9b04ee07709055efae00202fb993ac32dae918b7b9d8b3d308e563d6", 227 | "timeInSeconds": "1539871622", 228 | "hash": "00002a91aee2a62863d96062bc3847b5fa682a2176ffe0a849e5151d36b4e033", 229 | "nounce": 30436, 230 | "difficulty": 4, 231 | "numTransactions": 6, 232 | "transactions": [ 233 | { 234 | "fromUser": "sumeet-blockchain", 235 | "toUser": "sumeetsarkar", 236 | "amount": 10 237 | }, 238 | { 239 | "fromUser": "sumeetsarkar", 240 | "toUser": "sumeet-blockchain", 241 | "amount": -10 242 | }, 243 | { 244 | "fromUser": "userA", 245 | "toUser": "userB", 246 | "amount": 900 247 | }, 248 | { 249 | "fromUser": "userB", 250 | "toUser": "userA", 251 | "amount": -900 252 | }, 253 | { 254 | "fromUser": "userC", 255 | "toUser": "userD", 256 | "amount": 500 257 | }, 258 | { 259 | "fromUser": "userD", 260 | "toUser": "userC", 261 | "amount": -500 262 | } 263 | ] 264 | }, 265 | { 266 | "version": "1", 267 | "previousHash": "00002a91aee2a62863d96062bc3847b5fa682a2176ffe0a849e5151d36b4e033", 268 | "merkelRoot": "e6b8da89aa107105dd309131ebf607f875c135bacc4d030205794e224b1f7d01", 269 | "timeInSeconds": "1539871623", 270 | "hash": "00004867299b74e8aa169922760b64f79a4f90ac20e862b407d33ffcc0390145", 271 | "nounce": 139391, 272 | "difficulty": 4, 273 | "numTransactions": 6, 274 | "transactions": [ 275 | { 276 | "fromUser": "sumeet-blockchain", 277 | "toUser": "sumeetsarkar", 278 | "amount": 10 279 | }, 280 | { 281 | "fromUser": "sumeetsarkar", 282 | "toUser": "sumeet-blockchain", 283 | "amount": -10 284 | }, 285 | { 286 | "fromUser": "userA", 287 | "toUser": "userB", 288 | "amount": 400 289 | }, 290 | { 291 | "fromUser": "userB", 292 | "toUser": "userA", 293 | "amount": -400 294 | }, 295 | { 296 | "fromUser": "userA", 297 | "toUser": "userC", 298 | "amount": 200 299 | }, 300 | { 301 | "fromUser": "userC", 302 | "toUser": "userA", 303 | "amount": -200 304 | } 305 | ] 306 | }, 307 | { 308 | "version": "1", 309 | "previousHash": "00004867299b74e8aa169922760b64f79a4f90ac20e862b407d33ffcc0390145", 310 | "merkelRoot": "85904c2e9b04ee07709055efae00202fb993ac32dae918b7b9d8b3d308e563d6", 311 | "timeInSeconds": "1539871624", 312 | "hash": "0000731f55d9ab76a82b100aa9c713d79bdaf21b14a7f64cecce055e1cab5ae7", 313 | "nounce": 12546, 314 | "difficulty": 4, 315 | "numTransactions": 6, 316 | "transactions": [ 317 | { 318 | "fromUser": "sumeet-blockchain", 319 | "toUser": "sumeetsarkar", 320 | "amount": 10 321 | }, 322 | { 323 | "fromUser": "sumeetsarkar", 324 | "toUser": "sumeet-blockchain", 325 | "amount": -10 326 | }, 327 | { 328 | "fromUser": "userA", 329 | "toUser": "userB", 330 | "amount": 900 331 | }, 332 | { 333 | "fromUser": "userB", 334 | "toUser": "userA", 335 | "amount": -900 336 | }, 337 | { 338 | "fromUser": "userC", 339 | "toUser": "userD", 340 | "amount": 500 341 | }, 342 | { 343 | "fromUser": "userD", 344 | "toUser": "userC", 345 | "amount": -500 346 | } 347 | ] 348 | }, 349 | { 350 | "version": "1", 351 | "previousHash": "0000731f55d9ab76a82b100aa9c713d79bdaf21b14a7f64cecce055e1cab5ae7", 352 | "merkelRoot": "e6b8da89aa107105dd309131ebf607f875c135bacc4d030205794e224b1f7d01", 353 | "timeInSeconds": "1539871625", 354 | "hash": "000055e26126d5292e090f4af75bd5034228f3b40234db7420a3433888164a49", 355 | "nounce": 4998, 356 | "difficulty": 4, 357 | "numTransactions": 6, 358 | "transactions": [ 359 | { 360 | "fromUser": "sumeet-blockchain", 361 | "toUser": "sumeetsarkar", 362 | "amount": 10 363 | }, 364 | { 365 | "fromUser": "sumeetsarkar", 366 | "toUser": "sumeet-blockchain", 367 | "amount": -10 368 | }, 369 | { 370 | "fromUser": "userA", 371 | "toUser": "userB", 372 | "amount": 400 373 | }, 374 | { 375 | "fromUser": "userB", 376 | "toUser": "userA", 377 | "amount": -400 378 | }, 379 | { 380 | "fromUser": "userA", 381 | "toUser": "userC", 382 | "amount": 200 383 | }, 384 | { 385 | "fromUser": "userC", 386 | "toUser": "userA", 387 | "amount": -200 388 | } 389 | ] 390 | }, 391 | { 392 | "version": "1", 393 | "previousHash": "000055e26126d5292e090f4af75bd5034228f3b40234db7420a3433888164a49", 394 | "merkelRoot": "85904c2e9b04ee07709055efae00202fb993ac32dae918b7b9d8b3d308e563d6", 395 | "timeInSeconds": "1539871625", 396 | "hash": "000047f4b56d7a2bf03a37b8a7b66d8ef9309c22a2d925d4fc92a5e1136ecd62", 397 | "nounce": 121136, 398 | "difficulty": 4, 399 | "numTransactions": 6, 400 | "transactions": [ 401 | { 402 | "fromUser": "sumeet-blockchain", 403 | "toUser": "sumeetsarkar", 404 | "amount": 10 405 | }, 406 | { 407 | "fromUser": "sumeetsarkar", 408 | "toUser": "sumeet-blockchain", 409 | "amount": -10 410 | }, 411 | { 412 | "fromUser": "userA", 413 | "toUser": "userB", 414 | "amount": 900 415 | }, 416 | { 417 | "fromUser": "userB", 418 | "toUser": "userA", 419 | "amount": -900 420 | }, 421 | { 422 | "fromUser": "userC", 423 | "toUser": "userD", 424 | "amount": 500 425 | }, 426 | { 427 | "fromUser": "userD", 428 | "toUser": "userC", 429 | "amount": -500 430 | } 431 | ] 432 | }, 433 | { 434 | "version": "1", 435 | "previousHash": "000047f4b56d7a2bf03a37b8a7b66d8ef9309c22a2d925d4fc92a5e1136ecd62", 436 | "merkelRoot": "e6b8da89aa107105dd309131ebf607f875c135bacc4d030205794e224b1f7d01", 437 | "timeInSeconds": "1539871626", 438 | "hash": "00009cd709d9b839929f485c0cf2f3d9ace89ebcb540adb6406f50558c7f12d3", 439 | "nounce": 211081, 440 | "difficulty": 4, 441 | "numTransactions": 6, 442 | "transactions": [ 443 | { 444 | "fromUser": "sumeet-blockchain", 445 | "toUser": "sumeetsarkar", 446 | "amount": 10 447 | }, 448 | { 449 | "fromUser": "sumeetsarkar", 450 | "toUser": "sumeet-blockchain", 451 | "amount": -10 452 | }, 453 | { 454 | "fromUser": "userA", 455 | "toUser": "userB", 456 | "amount": 400 457 | }, 458 | { 459 | "fromUser": "userB", 460 | "toUser": "userA", 461 | "amount": -400 462 | }, 463 | { 464 | "fromUser": "userA", 465 | "toUser": "userC", 466 | "amount": 200 467 | }, 468 | { 469 | "fromUser": "userC", 470 | "toUser": "userA", 471 | "amount": -200 472 | } 473 | ] 474 | }, 475 | { 476 | "version": "1", 477 | "previousHash": "00009cd709d9b839929f485c0cf2f3d9ace89ebcb540adb6406f50558c7f12d3", 478 | "merkelRoot": "85904c2e9b04ee07709055efae00202fb993ac32dae918b7b9d8b3d308e563d6", 479 | "timeInSeconds": "1539871627", 480 | "hash": "0000726bdf87037ceb093608b4e2cf876f3f9e16f5c058cdac9ed414be0459f1", 481 | "nounce": 9012, 482 | "difficulty": 4, 483 | "numTransactions": 6, 484 | "transactions": [ 485 | { 486 | "fromUser": "sumeet-blockchain", 487 | "toUser": "sumeetsarkar", 488 | "amount": 10 489 | }, 490 | { 491 | "fromUser": "sumeetsarkar", 492 | "toUser": "sumeet-blockchain", 493 | "amount": -10 494 | }, 495 | { 496 | "fromUser": "userA", 497 | "toUser": "userB", 498 | "amount": 900 499 | }, 500 | { 501 | "fromUser": "userB", 502 | "toUser": "userA", 503 | "amount": -900 504 | }, 505 | { 506 | "fromUser": "userC", 507 | "toUser": "userD", 508 | "amount": 500 509 | }, 510 | { 511 | "fromUser": "userD", 512 | "toUser": "userC", 513 | "amount": -500 514 | } 515 | ] 516 | }, 517 | { 518 | "version": "1", 519 | "previousHash": "0000726bdf87037ceb093608b4e2cf876f3f9e16f5c058cdac9ed414be0459f1", 520 | "merkelRoot": "e6b8da89aa107105dd309131ebf607f875c135bacc4d030205794e224b1f7d01", 521 | "timeInSeconds": "1539872156", 522 | "hash": "00003579a78ed4aad835bb3e3340cd7d33a70f690dd1fa951eba0e6c7dc64c80", 523 | "nounce": 228576, 524 | "difficulty": 4, 525 | "numTransactions": 6, 526 | "transactions": [ 527 | { 528 | "fromUser": "sumeet-blockchain", 529 | "toUser": "sumeetsarkar", 530 | "amount": 10 531 | }, 532 | { 533 | "fromUser": "sumeetsarkar", 534 | "toUser": "sumeet-blockchain", 535 | "amount": -10 536 | }, 537 | { 538 | "fromUser": "userA", 539 | "toUser": "userB", 540 | "amount": 400 541 | }, 542 | { 543 | "fromUser": "userB", 544 | "toUser": "userA", 545 | "amount": -400 546 | }, 547 | { 548 | "fromUser": "userA", 549 | "toUser": "userC", 550 | "amount": 200 551 | }, 552 | { 553 | "fromUser": "userC", 554 | "toUser": "userA", 555 | "amount": -200 556 | } 557 | ] 558 | }, 559 | { 560 | "version": "1", 561 | "previousHash": "00003579a78ed4aad835bb3e3340cd7d33a70f690dd1fa951eba0e6c7dc64c80", 562 | "merkelRoot": "85904c2e9b04ee07709055efae00202fb993ac32dae918b7b9d8b3d308e563d6", 563 | "timeInSeconds": "1539872157", 564 | "hash": "0000d5842cd27e5a1965725c442ffa6acab88061f735a9be8f5e34a8b076cfb7", 565 | "nounce": 9576, 566 | "difficulty": 4, 567 | "numTransactions": 6, 568 | "transactions": [ 569 | { 570 | "fromUser": "sumeet-blockchain", 571 | "toUser": "sumeetsarkar", 572 | "amount": 10 573 | }, 574 | { 575 | "fromUser": "sumeetsarkar", 576 | "toUser": "sumeet-blockchain", 577 | "amount": -10 578 | }, 579 | { 580 | "fromUser": "userA", 581 | "toUser": "userB", 582 | "amount": 900 583 | }, 584 | { 585 | "fromUser": "userB", 586 | "toUser": "userA", 587 | "amount": -900 588 | }, 589 | { 590 | "fromUser": "userC", 591 | "toUser": "userD", 592 | "amount": 500 593 | }, 594 | { 595 | "fromUser": "userD", 596 | "toUser": "userC", 597 | "amount": -500 598 | } 599 | ] 600 | }, 601 | { 602 | "version": "1", 603 | "previousHash": "0000d5842cd27e5a1965725c442ffa6acab88061f735a9be8f5e34a8b076cfb7", 604 | "merkelRoot": "e6b8da89aa107105dd309131ebf607f875c135bacc4d030205794e224b1f7d01", 605 | "timeInSeconds": "1539872268", 606 | "hash": "00000e2681bba5d54cc519ab601628c379d489ccc2365c9cf838f8a2adb4d984", 607 | "nounce": 51558, 608 | "difficulty": 4, 609 | "numTransactions": 6, 610 | "transactions": [ 611 | { 612 | "fromUser": "sumeet-blockchain", 613 | "toUser": "sumeetsarkar", 614 | "amount": 10 615 | }, 616 | { 617 | "fromUser": "sumeetsarkar", 618 | "toUser": "sumeet-blockchain", 619 | "amount": -10 620 | }, 621 | { 622 | "fromUser": "userA", 623 | "toUser": "userB", 624 | "amount": 400 625 | }, 626 | { 627 | "fromUser": "userB", 628 | "toUser": "userA", 629 | "amount": -400 630 | }, 631 | { 632 | "fromUser": "userA", 633 | "toUser": "userC", 634 | "amount": 200 635 | }, 636 | { 637 | "fromUser": "userC", 638 | "toUser": "userA", 639 | "amount": -200 640 | } 641 | ] 642 | }, 643 | { 644 | "version": "1", 645 | "previousHash": "00000e2681bba5d54cc519ab601628c379d489ccc2365c9cf838f8a2adb4d984", 646 | "merkelRoot": "85904c2e9b04ee07709055efae00202fb993ac32dae918b7b9d8b3d308e563d6", 647 | "timeInSeconds": "1539872268", 648 | "hash": "0000e3443233f2976f5ccc2f543f4acec2993903b89e911802545039c363b4c0", 649 | "nounce": 52829, 650 | "difficulty": 4, 651 | "numTransactions": 6, 652 | "transactions": [ 653 | { 654 | "fromUser": "sumeet-blockchain", 655 | "toUser": "sumeetsarkar", 656 | "amount": 10 657 | }, 658 | { 659 | "fromUser": "sumeetsarkar", 660 | "toUser": "sumeet-blockchain", 661 | "amount": -10 662 | }, 663 | { 664 | "fromUser": "userA", 665 | "toUser": "userB", 666 | "amount": 900 667 | }, 668 | { 669 | "fromUser": "userB", 670 | "toUser": "userA", 671 | "amount": -900 672 | }, 673 | { 674 | "fromUser": "userC", 675 | "toUser": "userD", 676 | "amount": 500 677 | }, 678 | { 679 | "fromUser": "userD", 680 | "toUser": "userC", 681 | "amount": -500 682 | } 683 | ] 684 | }, 685 | { 686 | "version": "1", 687 | "previousHash": "0000e3443233f2976f5ccc2f543f4acec2993903b89e911802545039c363b4c0", 688 | "merkelRoot": "e6b8da89aa107105dd309131ebf607f875c135bacc4d030205794e224b1f7d01", 689 | "timeInSeconds": "1539872278", 690 | "hash": "0000cde2ee566f55fe536731b912817aaabb6eefcd727119b96c769747262fd0", 691 | "nounce": 113743, 692 | "difficulty": 4, 693 | "numTransactions": 6, 694 | "transactions": [ 695 | { 696 | "fromUser": "sumeet-blockchain", 697 | "toUser": "sumeetsarkar", 698 | "amount": 10 699 | }, 700 | { 701 | "fromUser": "sumeetsarkar", 702 | "toUser": "sumeet-blockchain", 703 | "amount": -10 704 | }, 705 | { 706 | "fromUser": "userA", 707 | "toUser": "userB", 708 | "amount": 400 709 | }, 710 | { 711 | "fromUser": "userB", 712 | "toUser": "userA", 713 | "amount": -400 714 | }, 715 | { 716 | "fromUser": "userA", 717 | "toUser": "userC", 718 | "amount": 200 719 | }, 720 | { 721 | "fromUser": "userC", 722 | "toUser": "userA", 723 | "amount": -200 724 | } 725 | ] 726 | }, 727 | { 728 | "version": "1", 729 | "previousHash": "0000cde2ee566f55fe536731b912817aaabb6eefcd727119b96c769747262fd0", 730 | "merkelRoot": "85904c2e9b04ee07709055efae00202fb993ac32dae918b7b9d8b3d308e563d6", 731 | "timeInSeconds": "1539872278", 732 | "hash": "00007ed784d52b25e79b2c9e1795250cae050efe8a930b74427803e80171f193", 733 | "nounce": 28366, 734 | "difficulty": 4, 735 | "numTransactions": 6, 736 | "transactions": [ 737 | { 738 | "fromUser": "sumeet-blockchain", 739 | "toUser": "sumeetsarkar", 740 | "amount": 10 741 | }, 742 | { 743 | "fromUser": "sumeetsarkar", 744 | "toUser": "sumeet-blockchain", 745 | "amount": -10 746 | }, 747 | { 748 | "fromUser": "userA", 749 | "toUser": "userB", 750 | "amount": 900 751 | }, 752 | { 753 | "fromUser": "userB", 754 | "toUser": "userA", 755 | "amount": -900 756 | }, 757 | { 758 | "fromUser": "userC", 759 | "toUser": "userD", 760 | "amount": 500 761 | }, 762 | { 763 | "fromUser": "userD", 764 | "toUser": "userC", 765 | "amount": -500 766 | } 767 | ] 768 | }, 769 | { 770 | "version": "1", 771 | "previousHash": "00007ed784d52b25e79b2c9e1795250cae050efe8a930b74427803e80171f193", 772 | "merkelRoot": "e6b8da89aa107105dd309131ebf607f875c135bacc4d030205794e224b1f7d01", 773 | "timeInSeconds": "1539877829", 774 | "hash": "00007078e658f6f277fdcdf3234265e153b77886a62630eac6ac6d507176f152", 775 | "nounce": 50817, 776 | "difficulty": 4, 777 | "numTransactions": 6, 778 | "transactions": [ 779 | { 780 | "fromUser": "sumeet-blockchain", 781 | "toUser": "sumeetsarkar", 782 | "amount": 10 783 | }, 784 | { 785 | "fromUser": "sumeetsarkar", 786 | "toUser": "sumeet-blockchain", 787 | "amount": -10 788 | }, 789 | { 790 | "fromUser": "userA", 791 | "toUser": "userB", 792 | "amount": 400 793 | }, 794 | { 795 | "fromUser": "userB", 796 | "toUser": "userA", 797 | "amount": -400 798 | }, 799 | { 800 | "fromUser": "userA", 801 | "toUser": "userC", 802 | "amount": 200 803 | }, 804 | { 805 | "fromUser": "userC", 806 | "toUser": "userA", 807 | "amount": -200 808 | } 809 | ] 810 | }, 811 | { 812 | "version": "1", 813 | "previousHash": "00007078e658f6f277fdcdf3234265e153b77886a62630eac6ac6d507176f152", 814 | "merkelRoot": "85904c2e9b04ee07709055efae00202fb993ac32dae918b7b9d8b3d308e563d6", 815 | "timeInSeconds": "1539877829", 816 | "hash": "0000a0e8c6eb5304a0ea37d890cd31c09a9bd365dabd7324bea898cd714a3953", 817 | "nounce": 136495, 818 | "difficulty": 4, 819 | "numTransactions": 6, 820 | "transactions": [ 821 | { 822 | "fromUser": "sumeet-blockchain", 823 | "toUser": "sumeetsarkar", 824 | "amount": 10 825 | }, 826 | { 827 | "fromUser": "sumeetsarkar", 828 | "toUser": "sumeet-blockchain", 829 | "amount": -10 830 | }, 831 | { 832 | "fromUser": "userA", 833 | "toUser": "userB", 834 | "amount": 900 835 | }, 836 | { 837 | "fromUser": "userB", 838 | "toUser": "userA", 839 | "amount": -900 840 | }, 841 | { 842 | "fromUser": "userC", 843 | "toUser": "userD", 844 | "amount": 500 845 | }, 846 | { 847 | "fromUser": "userD", 848 | "toUser": "userC", 849 | "amount": -500 850 | } 851 | ] 852 | }, 853 | { 854 | "version": "1", 855 | "previousHash": "0000a0e8c6eb5304a0ea37d890cd31c09a9bd365dabd7324bea898cd714a3953", 856 | "merkelRoot": "e6b8da89aa107105dd309131ebf607f875c135bacc4d030205794e224b1f7d01", 857 | "timeInSeconds": "1539877840", 858 | "hash": "00006eb9eb0222d1e1441639d83cefd945e25d0e0818763896db194c0441232e", 859 | "nounce": 134247, 860 | "difficulty": 4, 861 | "numTransactions": 6, 862 | "transactions": [ 863 | { 864 | "fromUser": "sumeet-blockchain", 865 | "toUser": "sumeetsarkar", 866 | "amount": 10 867 | }, 868 | { 869 | "fromUser": "sumeetsarkar", 870 | "toUser": "sumeet-blockchain", 871 | "amount": -10 872 | }, 873 | { 874 | "fromUser": "userA", 875 | "toUser": "userB", 876 | "amount": 400 877 | }, 878 | { 879 | "fromUser": "userB", 880 | "toUser": "userA", 881 | "amount": -400 882 | }, 883 | { 884 | "fromUser": "userA", 885 | "toUser": "userC", 886 | "amount": 200 887 | }, 888 | { 889 | "fromUser": "userC", 890 | "toUser": "userA", 891 | "amount": -200 892 | } 893 | ] 894 | }, 895 | { 896 | "version": "1", 897 | "previousHash": "00006eb9eb0222d1e1441639d83cefd945e25d0e0818763896db194c0441232e", 898 | "merkelRoot": "85904c2e9b04ee07709055efae00202fb993ac32dae918b7b9d8b3d308e563d6", 899 | "timeInSeconds": "1539877841", 900 | "hash": "0000afa7a9a1b24138900541d9843da74248450e9d5080c58b16e8f25b429af7", 901 | "nounce": 4968, 902 | "difficulty": 4, 903 | "numTransactions": 6, 904 | "transactions": [ 905 | { 906 | "fromUser": "sumeet-blockchain", 907 | "toUser": "sumeetsarkar", 908 | "amount": 10 909 | }, 910 | { 911 | "fromUser": "sumeetsarkar", 912 | "toUser": "sumeet-blockchain", 913 | "amount": -10 914 | }, 915 | { 916 | "fromUser": "userA", 917 | "toUser": "userB", 918 | "amount": 900 919 | }, 920 | { 921 | "fromUser": "userB", 922 | "toUser": "userA", 923 | "amount": -900 924 | }, 925 | { 926 | "fromUser": "userC", 927 | "toUser": "userD", 928 | "amount": 500 929 | }, 930 | { 931 | "fromUser": "userD", 932 | "toUser": "userC", 933 | "amount": -500 934 | } 935 | ] 936 | }, 937 | { 938 | "version": "1", 939 | "previousHash": "0000afa7a9a1b24138900541d9843da74248450e9d5080c58b16e8f25b429af7", 940 | "merkelRoot": "e6b8da89aa107105dd309131ebf607f875c135bacc4d030205794e224b1f7d01", 941 | "timeInSeconds": "1539880076", 942 | "hash": "0000bf834cd885ae2399d7165f065567a993d398de845b38bbec58ab87969dec", 943 | "nounce": 127338, 944 | "difficulty": 4, 945 | "numTransactions": 6, 946 | "transactions": [ 947 | { 948 | "fromUser": "sumeet-blockchain", 949 | "toUser": "sumeetsarkar", 950 | "amount": 10 951 | }, 952 | { 953 | "fromUser": "sumeetsarkar", 954 | "toUser": "sumeet-blockchain", 955 | "amount": -10 956 | }, 957 | { 958 | "fromUser": "userA", 959 | "toUser": "userB", 960 | "amount": 400 961 | }, 962 | { 963 | "fromUser": "userB", 964 | "toUser": "userA", 965 | "amount": -400 966 | }, 967 | { 968 | "fromUser": "userA", 969 | "toUser": "userC", 970 | "amount": 200 971 | }, 972 | { 973 | "fromUser": "userC", 974 | "toUser": "userA", 975 | "amount": -200 976 | } 977 | ] 978 | }, 979 | { 980 | "version": "1", 981 | "previousHash": "0000bf834cd885ae2399d7165f065567a993d398de845b38bbec58ab87969dec", 982 | "merkelRoot": "85904c2e9b04ee07709055efae00202fb993ac32dae918b7b9d8b3d308e563d6", 983 | "timeInSeconds": "1539880077", 984 | "hash": "00009fd16fdae525e31ed8b8939288dac73d2c4869aaf514b22e6b565b17dadc", 985 | "nounce": 109719, 986 | "difficulty": 4, 987 | "numTransactions": 6, 988 | "transactions": [ 989 | { 990 | "fromUser": "sumeet-blockchain", 991 | "toUser": "sumeetsarkar", 992 | "amount": 10 993 | }, 994 | { 995 | "fromUser": "sumeetsarkar", 996 | "toUser": "sumeet-blockchain", 997 | "amount": -10 998 | }, 999 | { 1000 | "fromUser": "userA", 1001 | "toUser": "userB", 1002 | "amount": 900 1003 | }, 1004 | { 1005 | "fromUser": "userB", 1006 | "toUser": "userA", 1007 | "amount": -900 1008 | }, 1009 | { 1010 | "fromUser": "userC", 1011 | "toUser": "userD", 1012 | "amount": 500 1013 | }, 1014 | { 1015 | "fromUser": "userD", 1016 | "toUser": "userC", 1017 | "amount": -500 1018 | } 1019 | ] 1020 | }, 1021 | { 1022 | "version": "1", 1023 | "previousHash": "00009fd16fdae525e31ed8b8939288dac73d2c4869aaf514b22e6b565b17dadc", 1024 | "merkelRoot": "e6b8da89aa107105dd309131ebf607f875c135bacc4d030205794e224b1f7d01", 1025 | "timeInSeconds": "1539890882", 1026 | "hash": "0000f175dc4aa3e8863008ab2c8fb45b706bf5053f68387d177c0e6c372ddc22", 1027 | "nounce": 109966, 1028 | "difficulty": 4, 1029 | "numTransactions": 6, 1030 | "transactions": [ 1031 | { 1032 | "fromUser": "sumeet-blockchain", 1033 | "toUser": "sumeetsarkar", 1034 | "amount": 10 1035 | }, 1036 | { 1037 | "fromUser": "sumeetsarkar", 1038 | "toUser": "sumeet-blockchain", 1039 | "amount": -10 1040 | }, 1041 | { 1042 | "fromUser": "userA", 1043 | "toUser": "userB", 1044 | "amount": 400 1045 | }, 1046 | { 1047 | "fromUser": "userB", 1048 | "toUser": "userA", 1049 | "amount": -400 1050 | }, 1051 | { 1052 | "fromUser": "userA", 1053 | "toUser": "userC", 1054 | "amount": 200 1055 | }, 1056 | { 1057 | "fromUser": "userC", 1058 | "toUser": "userA", 1059 | "amount": -200 1060 | } 1061 | ] 1062 | }, 1063 | { 1064 | "version": "1", 1065 | "previousHash": "0000f175dc4aa3e8863008ab2c8fb45b706bf5053f68387d177c0e6c372ddc22", 1066 | "merkelRoot": "85904c2e9b04ee07709055efae00202fb993ac32dae918b7b9d8b3d308e563d6", 1067 | "timeInSeconds": "1539890882", 1068 | "hash": "0000bb599443a8b2ef98e821ac13e380f8f82ba3bd607948f39b35813911516b", 1069 | "nounce": 28537, 1070 | "difficulty": 4, 1071 | "numTransactions": 6, 1072 | "transactions": [ 1073 | { 1074 | "fromUser": "sumeet-blockchain", 1075 | "toUser": "sumeetsarkar", 1076 | "amount": 10 1077 | }, 1078 | { 1079 | "fromUser": "sumeetsarkar", 1080 | "toUser": "sumeet-blockchain", 1081 | "amount": -10 1082 | }, 1083 | { 1084 | "fromUser": "userA", 1085 | "toUser": "userB", 1086 | "amount": 900 1087 | }, 1088 | { 1089 | "fromUser": "userB", 1090 | "toUser": "userA", 1091 | "amount": -900 1092 | }, 1093 | { 1094 | "fromUser": "userC", 1095 | "toUser": "userD", 1096 | "amount": 500 1097 | }, 1098 | { 1099 | "fromUser": "userD", 1100 | "toUser": "userC", 1101 | "amount": -500 1102 | } 1103 | ] 1104 | }, 1105 | { 1106 | "version": "1", 1107 | "previousHash": "0000bb599443a8b2ef98e821ac13e380f8f82ba3bd607948f39b35813911516b", 1108 | "merkelRoot": "e6b8da89aa107105dd309131ebf607f875c135bacc4d030205794e224b1f7d01", 1109 | "timeInSeconds": "1539890994", 1110 | "hash": "0000b737821389469419ea3e481a3169735b88ada22d5e75de7174d356ee6b03", 1111 | "nounce": 21525, 1112 | "difficulty": 4, 1113 | "numTransactions": 6, 1114 | "transactions": [ 1115 | { 1116 | "fromUser": "sumeet-blockchain", 1117 | "toUser": "sumeetsarkar", 1118 | "amount": 10 1119 | }, 1120 | { 1121 | "fromUser": "sumeetsarkar", 1122 | "toUser": "sumeet-blockchain", 1123 | "amount": -10 1124 | }, 1125 | { 1126 | "fromUser": "userA", 1127 | "toUser": "userB", 1128 | "amount": 400 1129 | }, 1130 | { 1131 | "fromUser": "userB", 1132 | "toUser": "userA", 1133 | "amount": -400 1134 | }, 1135 | { 1136 | "fromUser": "userA", 1137 | "toUser": "userC", 1138 | "amount": 200 1139 | }, 1140 | { 1141 | "fromUser": "userC", 1142 | "toUser": "userA", 1143 | "amount": -200 1144 | } 1145 | ] 1146 | }, 1147 | { 1148 | "version": "1", 1149 | "previousHash": "0000b737821389469419ea3e481a3169735b88ada22d5e75de7174d356ee6b03", 1150 | "merkelRoot": "85904c2e9b04ee07709055efae00202fb993ac32dae918b7b9d8b3d308e563d6", 1151 | "timeInSeconds": "1539890995", 1152 | "hash": "00000f7de5a56fbee6792f405f92de67dc517dcfc76a9e0368b0795fd0219877", 1153 | "nounce": 26682, 1154 | "difficulty": 4, 1155 | "numTransactions": 6, 1156 | "transactions": [ 1157 | { 1158 | "fromUser": "sumeet-blockchain", 1159 | "toUser": "sumeetsarkar", 1160 | "amount": 10 1161 | }, 1162 | { 1163 | "fromUser": "sumeetsarkar", 1164 | "toUser": "sumeet-blockchain", 1165 | "amount": -10 1166 | }, 1167 | { 1168 | "fromUser": "userA", 1169 | "toUser": "userB", 1170 | "amount": 900 1171 | }, 1172 | { 1173 | "fromUser": "userB", 1174 | "toUser": "userA", 1175 | "amount": -900 1176 | }, 1177 | { 1178 | "fromUser": "userC", 1179 | "toUser": "userD", 1180 | "amount": 500 1181 | }, 1182 | { 1183 | "fromUser": "userD", 1184 | "toUser": "userC", 1185 | "amount": -500 1186 | } 1187 | ] 1188 | } 1189 | ] --------------------------------------------------------------------------------