Bitcoin killer
Simple blockchain implementation on the spring-framework
Nodes communicate with each other via http.
- Block model
data class Block(
val index: Long, // block index
val previousHash: String, // hash of previous block
val hash: String, // current block hash
val data: String, // current block data
val nonce: Long // nonce
)
hash = sha256(concatenation of index, previousHash, data and nonce fields)
A block is valid provided the hash ends with 4 zeros.
- HttpMessages models
Incoming message about generating newBlock by another node
sealed class HttpIncomingMessage {
data class NewBlockMessage(val block: Block): HttpIncomingMessage()
}
Outgoing messages: BlockValidationError, BlockAcceptedMessage, LastBlockMessage, BlockChainMessage
sealed class HttpOutgoingMessage {
/**
* block is invalid
*/
data class BlockValidationError(val message: String, val block: Block): HttpOutgoingMessage()
/**
* block was accepted by node
*/
data class BlockAcceptedMessage(val block: Block): HttpOutgoingMessage()
/**
* get last block in chain
*/
data class LastBlockMessage(val block: Block) : HttpIncomingMessage()
/**
* get all blockchain
*/
data class BlockChainMessage(val blocks: List<Block>) : HttpIncomingMessage()
}
- To send a new block, use the
/newBlock
POST request:
{
"block": {
"index": 40,
"previousHash": "016d74c33fd2204f6fc18b170ab7d1009560e6204432e335385c43b57e890000",
"hash": "95a12cfce7e3599fc33e910ce3694c534802b4b1add7e1232b4d847905630000",
"data": "OYHcMGVHtElBN8c6ieEkuH63kMlL2oRj2tLG5NCh86y3IGmIctK04z4AhkzOUZLoPJC04mIpFEsUBt4",
"nonce": 1012199802390308277
}
}
- To get a new block, use the
/lastBlock
GET request. Response:
{
"block": {
"index": 1,
"previousHash": "",
"hash": "2f8660a39f4ef07a7cd784b5f5140197d95addd17183d25837580df586170000",
"data": "p9PmGmjLj5N0qxaP4MW6yHBsGQxODwhcQdaDFV4CIkOSi3UU0fn6YK4R",
"nonce": 8344120720967856628
}
}
- To get a blockchain, use the
/blockChain
GET request. Response:
{
"blocks": [
{
"index": 1,
"previousHash": "",
"hash": "2f8660a39f4ef07a7cd784b5f5140197d95addd17183d25837580df586170000",
"data": "p9PmGmjLj5N0qxaP4MW6yHBsGQxODwhcQdaDFV4CIkOSi3UU0fn6YK4R",
"nonce": 8344120720967856628
},
{
"index": 2,
"previousHash": "2f8660a39f4ef07a7cd784b5f5140197d95addd17183d25837580df586170000",
"hash": "6e176cdeabbcaf2ef2a5c9013e5242180bb790b3b556c9b2b0d13daafe0f0000",
"data": "p4nLxoVZPrj3ZFQv2W8G3LaSHk3uUFOZWi0RmeN9RnnhB3vmy0cD25CqL8CSThagAX",
"nonce": -8988250733424672812
}
]
}
- To start or stop use
/start
and/stop
GET requests respectively - To generate genesis block use
/generateGenesys
GET request
Each node can use its own approach to calculate the nonce - sequentially increase by 1, increase by Fibonacci, use a random value.
To configure generation strategy pass blockchain.generationStrategyName
into application.yml file:
blockchain:
generationStrategyName: RANDOM # or INCREMENT or FIBONACCI
./install.sh
It builds 2 docker images:
- vitekkor/vitcoin:{latestVersion} - blockchain node
- vitekkor/vitcoin-start-script:{latestVersion} - script to start mining blocks
docker-compose up
To stop nodes run stopNodes.sh script:
./stopNodes.sh localhost:8080 localhost:8081 localhost:8082
NB: 8080, 8081 and 8082 are external docker containers ports
- Add one more node to services:
# file: docker-compose.yml
node4:
image: vitekkor/vitcoin:1.0.0
volumes:
- ./application-node_4.yml:/etc/vitekkor/vitcoin/application.yml
restart: always
ports:
- "8083:8080"
- Provide application-node_4.yml configuration
# file: application-node_4.yml
blockchain:
generationStrategyName: # RANDOM or INCREMENT or FIBONACCI
nodes: # list of blockchain nodes
- uri: http://node1:8080
- uri: http://node2:8080
- uri: http://node3:8080
- Add new node to the another nodes configuration
E.g. application-node_1.yml:
# file: application-node_1.yml
blockchain:
generationStrategyName: RANDOM
nodes:
- uri: http://node2:8080
- uri: http://node3:8080
- uri: http://node4:8080
- Add new node arg to startScript
# file: docker-compose.yml
start-script:
image: vitekkor/vitcoin-start-script:1.0.0
restart: no
environment:
NODES: "node1:8080 node2:8080 node3:8080 node4:8080"
depends_on:
- node1
- node2
- node3
- node4