This project is a simple blockchain implementation with REST API. It supports basic operations like transferring tokens, mining blocks, getting various information about the state of blockchain and verifying transactions.
Project was designed to be as simple as possible and to demonstrate the basic principles of blockchain technology. It is not intended to be used in production. Main features are inspired by Ethereum and Bitcoin blockchains.
- Hash - a 32-bytes number that is generated from some data. Hash function is deterministic and works in "one way", which means that you can't get initial data from its hash. Different data produces different hashes, but the same data always produces the same hash.
- Private key - a 32-bytes number that is used to sign transactions and generate public key.
- Public key - a 33-bytes number that is used to verify signatures and generate account address.
- Account address - same thing as public key, may be used as its compressed version.
- Nonce - a number that is used to prevent replay attacks. It is incremented after each transaction. Nonces are stored in the blockchain, user should use the latest nonce for each transaction.
- Transaction - a record in the blockchain that represents a transfer of tokens from one account to another. It contains sender, receiver, amount, nonce and signature.
- Block - a record in the blockchain that contains a list of transactions, a nonce and a hash of the previous block. It is used to store transactions and to prevent tampering with the blockchain.
- Merkle tree - a binary tree that is used to store transactions in a block. It is used to verify transactions and to generate merkle proofs.
- Merkle proof - a list of hashes that is used to verify that a transaction is included in a block. It is used to prove that a transaction is valid and was included in a block.
- Target - a number that represents the difficulty for mining the block. It is used to adjust the difficulty of mining, prevent DDOS attacks and guarantee blockchain's workability for miners.
- Mining - a process of finding a nonce for a block that satisfies the target. It is used to add new blocks to the blockchain and to reward miners with new tokens.
- Signature - a 65-bytes number that is used to verify that a transaction was signed by the owner of the account.
- Project uses
secp256k1
elliptic curve for cryptography. It is the same curve that is used in Bitcoin and Ethereum blockchains. Public and private keys are generated over this curve. - For signing and verifying signatures projects uses ECDSA algorithm. It is a standard algorithm for signing and verifying messages over elliptic curves.
- For hashing project uses
blake2
algorithms.
Project uses PostgreSQL as a database. It is used to store blocks, transactions and accounts. Database contains 4 tables:
blocks
- contains information about blocks. It includes block number, hash, previous block hash, nonce, miner address, timestamp and merkle root.transactions
- contains information about transactions. It includes transaction hash, sender, receiver, amount, nonce, signature and block number.accounts
- contains information about accounts. It includes account address, nonce and balance.merkle_nodes
- contains information about merkle tree nodes.
While keeping project simple, it is possible to configure some parameters of the blockchain. Configuration is stored in
.env
file and can be changed by the user. Configuration includes:
SERVER_PORT
- port of the serverDB_URL
- URL of the database.NODE_MODE
- mode of the blockchain. Can betest
orfull
. Intest
mode, blocks are mined automatically. Infull
mode, blocks should be mined manually.MERKLE_TREE_SIZE
- size of the merkle tree. It is used to store transactions in a block. Should be a power of 2.BASE_REWARD
- reward for mining a block. It is a number of tokens that miner receives for mining a block.BLOCK_SIZE
- maximum number of transactions in a block. It is used to prevent DDOS attacks and to keep the blockchain size reasonable.TARGET
- initial target for the first block. It is used to adjust the difficulty of mining. Should be a 256-bit number.
/get_balance/{account_id}
- Returns balance of an account/get_transaction/{tx_hash}
- Returns transaction information by transaction hash/get_transactions/{account_id}
- Returns list of transactions for an account/get_nonce/{account_id}
- Returns current nonce for account/get_block_by_hash/{block_hash}
- Returns block information by block hash/get_block_by_id/{block_id}
- Returns block information by block id/get_proof/{tx_hash}
- Returns merkle proof for a transaction/get_target
- Returns current target for the next block/block_height
- Returns current block height
/transfer
- Transfers tokens from one account to another.
Method data:
{
"from": "0x123",
"to": "0x456",
"amount": 100,
"nonce": 1,
"signature": "0x123"
}
/try_mine
- Tries to mine the latest block. Iftest
mode is enabled, it will mine the block automatically. Otherwise, it will returnSuccess
if the block was mined successfully, andFail
otherwise. If block was mined successfully, it will be added to the blockchain, miner will receive a reward and all transactions in the block will be executed.
Method data:
{
"miner": "0x123",
"block_number": 1,
"block_nonce": 1,
"nonce": 1,
"signature": "0x123"
}
/set_target
- Sets target for the next block. Only accessible iftest
mode is enabled. Target is a 256-bit number that represents the difficulty of the block./mint
- Mints new coins to the account without making a transaction. Only accessible iftest
mode is enabled.
Method data:
{
"to": "0x123",
"amount": 100
}
/get_mode
- Returns current mode of the blockchain. Can betest
orfull
./set_mode
- Enables or disables test mode. In test mode, blocks are mined automatically. Accepts variantstest
andfull
.
Method data:
{
"mode": "test"
}
/generate_sig
- Generates signature for a given message and private key. Message should be a hash of the transaction encoded in hex format. Returns signature in hex format. Generates ECDSA signature over secp256k1 curve.
Method data:
{
"message": "0x123",
"private_key": "0x123"
}
/verify_sig
- Verifies signature for a given message, public key and signature. ReturnsSuccess
if the signature is valid, andFail
otherwise.
Method data:
{
"message": "0x123",
"public_key": "0x123",
"signature": "0x123"
}
/get_pub_key/{private_key}
- Returns public key for a given private key./verify_proof
- Verifies merkle proof for a given transaction. ReturnsSuccess
if the proof is valid, andFail
otherwise.
Method data:
{
"tx_hash": "0x123",
"proof": [
{
"hash": "0x123",
"parent_direction": "left"
},
{
"hash": "0x123",
"parent_direction": null
}
],
"root": "0x123"
}