A simplified PoC for Bitcoin

Applied Crypto Studio
19 min readAug 22, 2019

The Bitcoin has been fascinating for several years, which also triggered the arise of the whole blockchain industry. However, the Bitcoin is somehow too complex to be clearly recognized as a promising technique composed of cryptography, distributed systems and FinTech. This article aims to simplify some detail settings and introduce the proof of concept of Bitcoin through JavaScript. Also, this story could be regarded as an extension of @spenserhuang‘s article Learn & Build a Javascript Blockchain.

Background requirements

Audiences of this story are expected to keep an open mind and acknowledge some basic JavaScript programming skills. First, the cryptographic part mainly requires digital signature and hash function, some previous stories might provide some conceptually understanding. Secondly, the consensus algorithm, proof of work, will be implemented in the application as the distributed system part. Finally, a basic object-oriented programing concept is required before starting this story.

Conceptually introduction

Fundamentally, we are writing a blockchain which is a “chain-of-blocks”, and each block contains many “transactions”; aside from that, there are many “users” who own private keys so that they can transfer and mine. The overview gives us a concept to write some “objects” over a top-down viewpoint. Each object mentioned above is described as a class in the programming language.

Begin to construct

NPM and Git

Let’s start with the npm tool. If npm has not been installed, refer to this site. My developing version is 6.11.1, perhaps you might need a close version. The following command may help to check the version of npm.

npm -v

Then, git is also an import tool before the construction, find some instruction here if git is still unavailable on your computer.

Start the PoC for Bitcoin

I prepared a project composed of some JavaScript code to gradually implement a PoC for Bitcoin. First, go to the file path you like, clone the repository BitcoinPoC and enter the folder after download.

cd your/path
git clone https://github.com/Kylesstory/BitcoinPoC.git
cd ./BitcoinPoC/

Then, some existing library may help us a lot while dealing with hash functions and the ECDSA digital signature. These libraries have been utilized in the sample codes. So, let’s install them first.

npm install

Ideally, the required libraries will be automatically installed if you’re lucky. Have a look what we just installed:

npm list

A similar result might look like this:

npm listbitcoinpoc@1.0.0 your/path/BitcoinPoC
├── crypto@1.0.1
├── crypto-js@3.1.9-1├─┬ elliptic@6.5.0│ ├── bn.js@4.11.8│ ├── brorand@1.1.0│ ├─┬ hash.js@1.1.7│ │ ├── inherits@2.0.4 │ │ └── minimalistic-assert@1.0.1 │ ├─┬ hmac-drbg@1.0.1│ │ ├── hash.js@1.1.7 │ │ ├── minimalistic-assert@1.0.1 │ │ └── minimalistic-crypto-utils@1.0.1 │ ├── inherits@2.0.4│ ├── minimalistic-assert@1.0.1│ └── minimalistic-crypto-utils@1.0.1└── hex-to-binary@1.0.1

Assume you’re a lucky guy, now we can forget the npm and git things; then look forward to focus on implementing a simplified Bitcoin blockchain. Let’s open file PoCBitcoin.js in your preferred text editor like Sublime or VSCode, it may look like this.

Proof of Concept for Bitcoin

As previously mentioned, the code has been almost completed. The first 5 lines are imported libraries; line 12 to 21 are some global variables; line 23 to 111 are some general functions which could help some repetitive works. The program begins from line 296. We’ll focus on the classes from line 115 to line 294, the objects User, Transaction, Block and Blockchain we mentioned in the beginning. All blanks need to be filled will be labeled by [ write code here ].

User (part 1)

Let’s begin from the User class. In Bitcoin, a user owns a pair of private key and public key along with the mnemonic and an address.

The private / public key pair makes the user unique because he or she can sign digital signatures that cannot be forged by others who does not own the private key. That makes users distinguishable and not replaceable (and also the immutable of the signed content). That’s also why each user should keep their private key secretly.

The mnemonic could be realized as the copy of secret key encoded into a human-readable format like 12 or 24 English words. It is not implemented here for clear.

The public key represents for a user. However the public key is too long as an identifier so that the addresses are proposed to replace the public keys. Conceptually, the address is the hash value of the public key. By the collision-resistant property of hash functions, different public keys become different addresses in an overwhelming probability so the addresses could still be identifiers of users. The detail implementation could be found here, which is composed of a series of hash functions (SHA256 and RIPEMD-160), checksum and Base58 encoding. For clear expression, we just simplified addresses as the “shortHash” of the public key, which “shortHash” is a pre-defined SHA256 based hash function in this program.

User object for Bitcoin PoC

The constructor() means it create a User object without any parameter. At first, we need a pair of private/public key pair. This could be achieved with the aid of library ec.

constructor(){ // to create a new user with name, secret key, public key, address and balance
// 1. create public key and secret key
this.key = ec.genKeyPair();
// Note. In Bitcoin and Etherum, there are mechanisms to avoid secret key losing.
// In Bitcoin improvement proposal 39, their is a technique called mnemonic which
// encodes the secret key into English words, users can write it down as the cold storage of secret key.
// Still that sentence, we omit it for clear.
}

Then, we need to add a line to compute users’ addresses. Although the address is conceptually the hash value of public key, it is somewhat complete to implement so that we just “shortHash” the public key as the address.

constructor(){ // to create a new user with name, secret key, public key, address and balance
// 1. create public key and secret key
this.key = ec.genKeyPair();
// Note. In Bitcoin and Etherum, there are mechanisms to avoid secret key losing.
// In Bitcoin improvement proposal 39, their is a technique called mnemonic which
// encodes the secret key into English words, users can write it down as the cold storage of secret key.
// Still that sentence, we omit it for clear.

// 2. compute the address
const publicKey = this.key.getPublic();
// Warn! This is a simplified version of address, not the official one.
this.address = shortHash(publicKey.getX().toString('hex') + publicKey.getY().toString('hex'));
}

Third, register the address to a global user list so that the created user could be found by enter “users[address]”.

constructor(){ // to create a new user with name, secret key, public key, address and balance
// 1. create public key and secret key
this.key = ec.genKeyPair();
// Note. In Bitcoin and Etherum, there are mechanisms to avoid secret key losing.
// In Bitcoin improvement proposal 39, their is a technique called mnemonic which
// encodes the secret key into English words, users can write it down as the cold storage of secret key.
// Still that sentence, we omit it for clear.

// 2. compute the address
const publicKey = this.key.getPublic();
// Warn! This is a simplified version of address, not the official one.
this.address = shortHash(publicKey.getX().toString('hex') + publicKey.getY().toString('hex'));
// 3. register the address to the blockchain
users[this.address] = this;
addresses.push(this.address);
}

Following, let’s glimpse the Transaction class.

Transaction object for BitcoincPoC

For short, transaction is sometimes abbreviated as tx. Then, while looking at the constructor of transaction, there are 4 parameters: from, to, amount, and tip. The former two are addresses, and the later two are numbers. It is intuitive that a transaction is sent by user[from], sent to user[to], with amount and tip.

Imagine the scenario you have a dinner in the restaurant in US, you’ll pay the price (amount) to the restaurant for food as well as the tip to the waiters for service. Bitcoin employees the similar concept: while a user transfers a specific amount of Bitcoin to another user, a small piece of tip is required as the service fee for the transaction verifier who participants in mining and maintaining the robust of the blockchain. The transaction sender decides how much the tip is and then he/ she signs the transaction using his / her private key to authorize the transaction.

Let’s come back to the User class concerning on the transfer function. Three parameters to, amount and tip will be passed in to construct a transaction. We have several things to fulfill in the function entity. First, the balance is verified first to ensure the transfer may success.

transfer(to, amount, tip){ // to transfer money to someone
// 1. make sure users' balance if enough to transfer
if (users[this.address].balance >= (amount + tip)){

} else{
console.log('Insufficient balance.')
}
}

Second, if sufficient fund is checked, create a transaction with the parameters and it’s own address.

transfer(to, amount, tip){ // to transfer money to someone
// 1. make sure users' balance if enough to transfer
if (users[this.address].balance >= (amount + tip)){
// 2. create a transaction
const tx = new Transaction(this.address, to, amount, tip);
const txString = tx.toString();
} else{
console.log('Insufficient balance.')
}
}

Third, the sender signs the transaction using its private key.

transfer(to, amount, tip){ // to transfer money to someone
// 1. make sure users' balance if enough to transfer
if (users[this.address].balance >= (amount + tip)){
// 2. create a transaction
const tx = new Transaction(this.address, to, amount, tip);
const txString = tx.toString();
// 3. sign the transaction
tx.signature = this.key.sign(txString);

} else{
console.log('Insufficient balance.')
}
}

Forth, publish the transaction to the blockchain (unpackagedTxs in this program).

transfer(to, amount, tip){ // to transfer money to someone
// 1. make sure users' balance if enough to transfer
if (users[this.address].balance >= (amount + tip)){
// 2. create a transaction
const tx = new Transaction(this.address, to, amount, tip);
const txString = tx.toString();
// 3. sign the transaction
tx.signature = this.key.sign(txString);
// 4. save the created transaction to 'unpackagedTxs'
unpackagedTxs.push(tx);

} else{
console.log('Insufficient balance.')
}
}

Now, we’ve finished the phased task. We built the User object, who has a pair of signing keys and an address as the identifier; besides, the user can transfer to someone through proposing transactions. Following, let’s temporarily leave the function mine() behind and take a look over the transaction class.

Transaction

Transaction object for Bitcoin PoC

What we need to do in this class is a bit easier. Just make the transaction verifiable afterward. Two things have to be done: make sure the transaction is signed, and it is signed correctly.

verify(){
// To make sure the transaction is valid.

// 1. Ensure 'this.signature' has been filled by some verifier.
if (this.signature === '') {
return false;
} else{

}
}

The commands above ensures the signature of this transaction is fulfilled; and the commands below verifies the digital signature of the sender.

verify(){
// To make sure the transaction is valid.

// 1. Ensure 'this.signature' has been filled by some verifier.
if (this.signature === '') {
return false;
} else{
// 2. Verify the validation of the digital signature.
const user = users[this.from];
return user.key.verify(this.toString(), this.signature);
}
}

It is really a piece of cake, right? Take a break, have your coffee ready and we’re moving forward to the Block class.

Block

Block object for Bitcoin PoC

Block is a bit more complex because it is the basic unit of blockchain. It works like a box concealing some data inside and attaches some meta-data outside, such as a HTTP package.

The concealing data is obviously the transaction data. In the official Bitcoin setting, the block size is set to 1MB which may contains dynamically hundreds of transactions depending on their size. To help understanding, it is set that each block may contains three transactions in this PoC. By the way, the merkle tree data structure is employed to make a proof of hierarchical hash footprint for transaction data. It sounds difficult so that it is also omitted here.

The metadata includes the timestamp, previousHash, nonce, and signature.

  1. The timestamp is straightforward.
  2. The previousHash plays a vital role in the blockchain. By the collision-resistant property of hash functions, the previousHash may stand for the previous block. Block n hasn’t been modified if the previousHash n kept in block n+1 is correct, and previousHash n-1 kept in block n ensures the correctness of block n-1. Recursively, the hash value of a previous block is stored in the current block. It repeatedly ensures the accuracy of the previous blocks, which finally constructs an immutable blockchain system. The is the main idea about how immutable the blockchain is.
  3. The nonce variable is the key factor of the famous consensus protocol, proof of work. By the uniform distribution property of hash functions, the outputs of hash functions are unpredictable unless you practically compute it. It creates an interesting and perhaps fair situation for each participant to compete calculating a ”target range” of hash values. More precisely, the transaction data, timestamp, and previousHash are fixed input fields, and miners are expected find an input nonce together with three aforementioned input fields to compute a great hash output which belongs to the desired range. I know the description is still a mist, sorry. For example, the hash value output locates uniformly random from 0 to 255 ; and the “target range” is “less than 32”. With the fixed transaction data, timestamp, and previousHash input, the miner keeps trying different nonces until hash(transaction data, timestamp, previousHash, nonce) = x and x < 32. Hope that the example may help understanding. The “nonce-finding” process is called as mining, or solve a puzzle. Actually it is not an easy job, and the first one who solves a puzzle will acquire a great amount of award. The mining award is initially 50 Bitcoins per block, but it reduces to half every four years. It is worthy to be noted that the “target range” is not fixed in Bitcoin; it dynamically arises or reduces to keep the average mining time is about 10 mins / block. For simplicity, this PoC project keeps it statistic at 3.
  4. After packaging transactions, collecting a timestamp and the previousHash, and mining a suitable nonce, the block verifier signs the block using her / his private key as the proof of work evidence (to claim the mining reward afterward).

Now, are you still awake? If so, let’s run into the code implementation. The puzzle is implemented by the cooperation of the User object and the Block object. Conceptually, the user mines with function mine(), and the block returns the validity through function challenge().

challenge(){ // if the hash value begins with three (defined by variable 'blockchain.difficulty') 0s
const binary = hexToBinary(this.hash);
// [ Write code here ]
// To ensure the found 'nonce' satisfy the puzzle challenge
// of Bitcoin proof of work with 'difficulty'.
}

The variable difficulty defines the number of a consecutive 0s at the most significant bits. For example, let difficulty=3, it means the block is valid if the block verifier finds a nonce so that the hash output of the block begins with at least three 0s. Try the following solution or you can write in your designing.

challenge(){ // if the hash value begins with three (defined by variable 'blockchain.difficulty') 0s
const binary = hexToBinary(this.hash);
let x = 0;
for (let i = 0; i < binary; i++){
if (binary[i] === '0'){
x += 1;
} else{
return false;
}
if (x >= blockchain.difficulty){
return true;
}
}
return false;
}

After the challenge() function, the block has to be verified valid so that the function verify() is also required. Four checks have to been implemented in this code section.

verify(){ // to verify a single block
if (this.signature === ''){
// 1. Ensure 'this.signature' has been filled by some verifier.
return false
}

}
  1. The signature of this block has been generated.
verify(){ // to verify a single block
if (this.signature === ''){
// 1. Ensure 'this.signature' has been filled by some verifier.
return false
}
if (this.hash !== shortHash(this.toString())){
// 2. Ensure 'this.hash' has been correctly computed.
// This step makes sure the block data hasn't been modified.
return false
}

}

2. The hash property is correctly computed.

verify(){ // to verify a single block
if (this.signature === ''){
// 1. Ensure 'this.signature' has been filled by some verifier.
return false
}
if (this.hash !== shortHash(this.toString())){
// 2. Ensure 'this.hash' has been correctly computed.
// This step makes sure the block data hasn't been modified.
return false
}
if (! this.challenge()){
// 3. Ensure the found 'this.nonce' in this block satisfies the Bitcoin puzzle.
return false
}

}

3. The puzzle in this block is solved.

verify(){ // to verify a single block
if (this.signature === ''){
// 1. Ensure 'this.signature' has been filled by some verifier.
return false
}
if (this.hash !== shortHash(this.toString())){
// 2. Ensure 'this.hash' has been correctly computed.
// This step makes sure the block data hasn't been modified.
return false
}
if (! this.challenge()){
// 3. Ensure the found 'this.nonce' in this block satisfies the Bitcoin puzzle.
return false
}
// 4. Verify the validation of the digital signature.
const user = users[this.verifier];
return user.key.verify(this.toString(), this.signature);
}

4. The signature of the block verifier is valid.

The block is valid if all these four checks pass. Then, let’s come back to the User object again to setup mining.

User (part 2)

Now we have built the block and its puzzle challenge verification. Let’s construct the mine() function step by step. There are six steps in total.

mine(){
// This is the proof of work, keep trying different nonces until satisfying the block challenge (puzzle)

// [ Write code here ]
// 1. collect the timestamp
const timestamp = new Date();

}
  1. setup the timestamp
mine(){ // to mine the coins
// This is the proof of work, keep trying different nonces until satisfying the block challenge (puzzle)

// 1. collect the timestamp
const timestamp = new Date();
// 2. pick several transactions (defined by variable 'capability')
// Warning. Bitcoin deals with transactions using Merkle tree data structure.
// In this PoC case, merkle tree is omitted for easy understanding.
const txs = [];
while (unpackagedTxs.length > 0 && txs.length < capability) { // if the block has space and there are unpackaged tx
const tx = unpackagedTxs.pop(0);
txs.push(tx);
}
const data = JSON.stringify(txs);
}

2. pick some transactions to package into block

mine(){ // to mine the coins
// This is the proof of work, keep trying different nonces until satisfying the block challenge (puzzle)

// 1. collect the timestamp
const timestamp = new Date();
// 2. pick several transactions (defined by variable 'capability')
// Warning. Bitcoin deals with transactions using Merkle tree data structure.
// In this PoC case, merkle tree is omitted for easy understanding.
const txs = [];
while (unpackagedTxs.length > 0 && txs.length < capability) { // if the block has space and there are unpackaged tx
const tx = unpackagedTxs.pop(0);
txs.push(tx);
}
const data = JSON.stringify(txs);
// 3. collect the hash value of previous block
const previousHash = blockchain.latestBlock().hash;
}

3. collect the hash value of the previous block

mine(){ // to mine the coins
// This is the proof of work, keep trying different nonces until satisfying the block challenge (puzzle)

// 1. collect the timestamp
const timestamp = new Date();
// 2. pick several transactions (defined by variable 'capability')
// Warning. Bitcoin deals with transactions using Merkle tree data structure.
// In this PoC case, merkle tree is omitted for easy understanding.
const txs = [];
while (unpackagedTxs.length > 0 && txs.length < capability) { // if the block has space and there are unpackaged tx
const tx = unpackagedTxs.pop(0);
txs.push(tx);
}
const data = JSON.stringify(txs);
// 3. collect the hash value of previous block
const previousHash = blockchain.latestBlock().hash;
// 4. try different nonces until solve the puzzle.
let nonce, block;
while (true){ // trying different nonces to satisfy the challenge
nonce = crypto.randomBytes(32).toString('hex');
block = new Block(timestamp, data, previousHash, nonce);
if (block.challenge()){
break;
}
}

}

4. mining

mine(){ // to mine the coins
// This is the proof of work, keep trying different nonces until satisfying the block challenge (puzzle)

// 1. collect the timestamp
const timestamp = new Date();
// 2. pick several transactions (defined by variable 'capability')
// Warning. Bitcoin deals with transactions using Merkle tree data structure.
// In this PoC case, merkle tree is omitted for easy understanding.
const txs = [];
while (unpackagedTxs.length > 0 && txs.length < capability) { // if the block has space and there are unpackaged tx
const tx = unpackagedTxs.pop(0);
txs.push(tx);
}
const data = JSON.stringify(txs);
// 3. collect the hash value of previous block
const previousHash = blockchain.latestBlock().hash;
// 4. try different nonces until solve the puzzle.
let nonce, block;
while (true){ // trying different nonces to satisfy the challenge
nonce = crypto.randomBytes(32).toString('hex');
block = new Block(timestamp, data, previousHash, nonce);
if (block.challenge()){
break;
}
}
// 5. sign the solved block
block.verifier = this.address;
block.signature = this.key.sign(block.toString());
// 6. add the block using 'blockchain.addblock()'
blockchain.addBlock(block);
}

5. sign the block after successfully mining

mine(){ // to mine the coins
// This is the proof of work, keep trying different nonces until satisfying the block challenge (puzzle)

// 1. collect the timestamp
const timestamp = new Date();
// 2. pick several transactions (defined by variable 'capability')
// Warning. Bitcoin deals with transactions using Merkle tree data structure.
// In this PoC case, merkle tree is omitted for easy understanding.
const txs = [];
while (unpackagedTxs.length > 0 && txs.length < capability) { // if the block has space and there are unpackaged tx
const tx = unpackagedTxs.pop(0);
txs.push(tx);
}
const data = JSON.stringify(txs);
// 3. collect the hash value of previous block
const previousHash = blockchain.latestBlock().hash;
// 4. try different nonces until solve the puzzle.
let nonce, block;
while (true){ // trying different nonces to satisfy the challenge
nonce = crypto.randomBytes(32).toString('hex');
block = new Block(timestamp, data, previousHash, nonce);
if (block.challenge()){
break;
}
}
// 5. sign the solved block
block.verifier = this.address;
block.signature = this.key.sign(block.toString());
// 6. add the block using 'blockchain.addblock()'
blockchain.addBlock(block);
}

6. publish this block to the blockchain

As you might notice, the 6th step have employed undefined function addBlock(block) in the Blockchain object. Let’s move on the last step to build a Blockchain.

Blockchain

With a quick glimpse of the constructor, it is obvious that the Blockchain object contains only three variables, the chain (of blocks), the mining difficulty and the mining reward. The first block is called the genesis block, which is quite different than other blocks. Some initial settings may be defined here. The only two work left here is to finish the addBlock(block) and the verifyAllBlocks() functions.

addBlock(block){ // to add a new block
// 1. verify the validity of the block
if (block.verify()){

} else{
console.log('Invalid block.')
}
}

The first thing is to verify the validity of the block desired to be added. Thanks god, it has been down in the Block object.

addBlock(block){ // to add a new block
// 1. verify the validity of the block
if (block.verify()){
// 1-1. verify the validity of all transactions
const txs = JSON.parse(block.data);
let validTxs = true, tx, sender;
for (let i = 0; i < txs.length; i++){ // for all txs in block, verify the signature
tx = new Transaction(txs[i]['from'], txs[i]['to'], txs[i]['amount'], txs[i]['tip']);
tx.signature = txs[i]['signature'];
if (! tx.verify()){
validTxs = false;
break;
}
} else{
console.log('Invalid block.')
}
}

The second thing is to check whether all transactions in this block are valid or not. It’s a bit messy, the above code conceptually rebuilds transactions objects and calls its function Transaction.verify() as the validity check.

addBlock(block){ // to add a new block
// 1. verify the validity of the block
if (block.verify()){
// 1-1. verify the validity of all transactions
const txs = JSON.parse(block.data);
let validTxs = true, tx, sender;
for (let i = 0; i < txs.length; i++){ // for all txs in block, verify the signature
tx = new Transaction(txs[i]['from'], txs[i]['to'], txs[i]['amount'], txs[i]['tip']);
tx.signature = txs[i]['signature'];
if (! tx.verify()){
validTxs = false;
break;
}
// 1-2. if all transactions are verified valid, deal with the payment
if (! validTxs){
console.log('Invalid transaction found.');
} else{
// 1-3. for each payment
for (let i = 0; i < txs.length; i++){ // for all txs in block
const tx = txs[i];
// 1-3-1. pay amount to tx.to
pay(tx.from, tx.to, tx.amount);
// 1-3-2. pay tip to the block verifyer
pay(tx.from, block.verifier, tx.tip);
// 1-3-3. record the transaction on the blockchain
txs[tx.hash] = tx; // record the transaction
}
} else{
console.log('Invalid block.')
}
}

Third, deal with the payment if all transactions are verified valid. The payment in Bitcoin relies on the unspent transaction object (UTXO). Because the story is too long and I’m tired so that we just forget it at this while. A pre-define function pay(from, to amount) is treated as an intuitive implementation to deal with the bill. For each transactions:

  1. the sender pays the receiver the “amount
  2. the sender pays the block verifier the “tip
  3. add the transaction to the history
addBlock(block){ // to add a new block
// 1. verify the validity of the block
if (block.verify()){
// 1-1. verify the validity of all transactions
const txs = JSON.parse(block.data);
let validTxs = true, tx, sender;
for (let i = 0; i < txs.length; i++){ // for all txs in block, verify the signature
tx = new Transaction(txs[i]['from'], txs[i]['to'], txs[i]['amount'], txs[i]['tip']);
tx.signature = txs[i]['signature'];
if (! tx.verify()){
validTxs = false;
break;
}
// 1-2. if all transactions are verified valid, deal with the payment
if (! validTxs){
console.log('Invalid transaction found.');
} else{
// 1-3. for each payment
for (let i = 0; i < txs.length; i++){ // for all txs in block
const tx = txs[i];
// 1-3-1. pay amount to tx.to
pay(tx.from, tx.to, tx.amount);
// 1-3-2. pay tip to the block verifyer
pay(tx.from, block.verifier, tx.tip);
// 1-3-3. record the transaction on the blockchain
txs[tx.hash] = tx; // record the transaction
// 1-4. deal with the block
// 1-4-1. the blockchain pays block award to the block verifier
pay(admin.address, block.verifier, this.reward);
// the admin pays the mining reward to the block verifier
// 1-4-2. add the block to the blockchain
this.chain.push(block);
}
} else{
console.log('Invalid block.')
}
}

Forth, the blockchain rewards the hard working block verifier and add this block to the blockchain.

Finally, we have the last function to implement. The verifyAllBlock() is relatively straightforward compared to aforementioned other functions.

verifyAllBlocks() { // to verify all blocks of the chain

// [ Write code here ]
// 1. for each block
for(let i = 1; i < this.chain.length; i++) {
const currentBlock = this.chain[i];
const previousBlock = this.chain[i - 1];
// 1-1. make sure the hash value of each block is kept in the next block
if (previousBlock.hash !== currentBlock.previousHash) {
return false;
}
}
console.log('Whole blockchain is verified correct.\n');
return true;
}
}

For each block, ensure the hash of the previousBlock is stored in the currentBlock.

verifyAllBlocks() { // to verify all blocks of the chain

// [ Write code here ]
// 1. for each block
for(let i = 1; i < this.chain.length; i++) {
const currentBlock = this.chain[i];
const previousBlock = this.chain[i - 1];
// 1-1. make sure the hash value of each block is kept in the next block
if (previousBlock.hash !== currentBlock.previousHash) {
return false;
}
// 1-2. make sure each block (except for the first block, genesis) is valid
if (! currentBlock.verify()) {
return false;
}
}
console.log('Whole blockchain is verified correct.\n');
return true;
}
}

Second, make sure all blocks are valid.

Congrats!! We have finished our Bitcoin PoC, it’s really a tough work (for writing as well). Hope this may help you practically realize more design details about the Bitcoin. If you really work hard, but the program doesn’t work, a ready program called index.js is available in the same directory. Any question or anything you found that I may misunderstand, please let me know. To be honest, many designs in Bitcoin have been omitted in this story, but it still looks unfriendly long. Hope that there will be some experts finish the omitted parts in the future.

If you enjoy the stories and willing to read more easily-understanding cryptographic or blockchain-related content, please give me some claps. I’ll be flattered if there are some sponsorship via Bitcoin or Ethereum.

Bitcoin: 36FmpfiDPVAJdxKtXM79Lj5G5awZgDNKar

Ethereum: 0x37fd7D56a7228344F1bca1132d7D1b1ED398FCaa

--

--

Applied Crypto Studio

We’re a group of experts major in applied cryptography and blockchain. Contact us for enterprise consulting and education.