mirror of
https://github.com/arnaucube/slowlorisdb.git
synced 2026-02-28 05:46:48 +01:00
updated data structures, moved NewBlock under Node functions
This commit is contained in:
@@ -10,9 +10,9 @@ import (
|
||||
type Block struct {
|
||||
Height uint64
|
||||
PrevHash Hash
|
||||
NextHash Hash
|
||||
Txs []Tx
|
||||
Miner Address
|
||||
MinerPubK *ecdsa.PublicKey // tmp meanwhile no ecrecover function
|
||||
Timestamp time.Time
|
||||
Nonce uint64
|
||||
Hash Hash
|
||||
@@ -23,9 +23,9 @@ func (block Block) Copy() *Block {
|
||||
return &Block{
|
||||
Height: block.Height,
|
||||
PrevHash: block.PrevHash,
|
||||
NextHash: block.NextHash,
|
||||
Txs: block.Txs,
|
||||
Miner: block.Miner,
|
||||
MinerPubK: block.MinerPubK,
|
||||
Timestamp: block.Timestamp,
|
||||
Nonce: block.Nonce,
|
||||
Hash: block.Hash,
|
||||
@@ -67,15 +67,6 @@ func CheckBlockPoW(block *Block, difficulty uint64) bool {
|
||||
return CheckPoW(HashBytes(blockCopy.Bytes()), difficulty)
|
||||
}
|
||||
|
||||
func VerifyBlockSignature(pubK *ecdsa.PublicKey, block *Block) bool {
|
||||
sig, err := SignatureFromBytes(block.Signature)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return VerifySignature(pubK, block.Hash[:], *sig)
|
||||
}
|
||||
|
||||
func BlockFromBytes(b []byte) (*Block, error) {
|
||||
var block *Block
|
||||
err := json.Unmarshal(b, &block)
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
func TestBlock(t *testing.T) {
|
||||
block := &Block{
|
||||
PrevHash: HashBytes([]byte("prevhash")),
|
||||
NextHash: HashBytes([]byte("nextHash")),
|
||||
Txs: []Tx{},
|
||||
Miner: Address(HashBytes([]byte("addrfromminer"))),
|
||||
Timestamp: time.Now(),
|
||||
@@ -38,7 +37,6 @@ func TestBlock(t *testing.T) {
|
||||
func TestNewBlock(t *testing.T) {
|
||||
block := &Block{
|
||||
PrevHash: HashBytes([]byte("prevhash")),
|
||||
NextHash: HashBytes([]byte("nextHash")),
|
||||
Txs: []Tx{},
|
||||
Miner: Address(HashBytes([]byte("addrfromminer"))),
|
||||
Timestamp: time.Now(),
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/arnaucube/slowlorisdb/db"
|
||||
)
|
||||
|
||||
type PoA struct {
|
||||
AuthMiners []*ecdsa.PublicKey
|
||||
}
|
||||
|
||||
type Blockchain struct {
|
||||
Id []byte // Id allows to have multiple blockchains
|
||||
Difficulty uint64
|
||||
Genesis Hash
|
||||
LastBlock *Block
|
||||
db *db.Db
|
||||
blockdb *db.Db
|
||||
txdb *db.Db
|
||||
PoA PoA
|
||||
}
|
||||
|
||||
func NewBlockchain(database *db.Db, dif uint64) *Blockchain {
|
||||
@@ -21,23 +28,25 @@ func NewBlockchain(database *db.Db, dif uint64) *Blockchain {
|
||||
Difficulty: dif,
|
||||
Genesis: HashBytes([]byte("genesis")),
|
||||
LastBlock: &Block{},
|
||||
db: database,
|
||||
blockdb: database,
|
||||
PoA: PoA{},
|
||||
}
|
||||
return blockchain
|
||||
}
|
||||
|
||||
func (bc *Blockchain) NewBlock(txs []Tx) *Block {
|
||||
block := &Block{
|
||||
Height: bc.GetHeight() + 1,
|
||||
PrevHash: bc.LastBlock.Hash,
|
||||
Txs: txs,
|
||||
Miner: Address{}, // TODO put the node address
|
||||
Timestamp: time.Now(),
|
||||
Nonce: 0,
|
||||
Hash: Hash{},
|
||||
Signature: []byte{},
|
||||
func NewPoABlockchain(database *db.Db, authNodes []*ecdsa.PublicKey) *Blockchain {
|
||||
poa := PoA{
|
||||
AuthMiners: authNodes,
|
||||
}
|
||||
return block
|
||||
blockchain := &Blockchain{
|
||||
Id: []byte{},
|
||||
Difficulty: uint64(0),
|
||||
Genesis: HashBytes([]byte("genesis")), // tmp
|
||||
LastBlock: &Block{},
|
||||
blockdb: database,
|
||||
PoA: poa,
|
||||
}
|
||||
return blockchain
|
||||
}
|
||||
|
||||
func (bc *Blockchain) GetHeight() uint64 {
|
||||
@@ -50,12 +59,12 @@ func (bc *Blockchain) GetLastBlock() *Block {
|
||||
|
||||
func (bc *Blockchain) AddBlock(block *Block) error {
|
||||
bc.LastBlock = block
|
||||
err := bc.db.Put(block.Hash[:], block.Bytes())
|
||||
err := bc.blockdb.Put(block.Hash[:], block.Bytes())
|
||||
return err
|
||||
}
|
||||
|
||||
func (bc *Blockchain) GetBlock(hash Hash) (*Block, error) {
|
||||
v, err := bc.db.Get(hash[:])
|
||||
v, err := bc.blockdb.Get(hash[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -81,3 +90,31 @@ func (bc *Blockchain) GetPrevBlock(hash Hash) (*Block, error) {
|
||||
|
||||
return prevBlock, nil
|
||||
}
|
||||
|
||||
func (bc *Blockchain) VerifyBlockSignature(block *Block) bool {
|
||||
// check if the signer is one of the blockchain.AuthMiners
|
||||
signerIsMiner := false
|
||||
for _, pubK := range bc.PoA.AuthMiners {
|
||||
if bytes.Equal(PackPubK(pubK), block.Miner[:]) {
|
||||
signerIsMiner = true
|
||||
}
|
||||
}
|
||||
if !signerIsMiner && len(bc.PoA.AuthMiners) > 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
// get the signature
|
||||
sig, err := SignatureFromBytes(block.Signature)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// check if the signature is by the miner
|
||||
return VerifySignature(block.MinerPubK, block.Hash[:], *sig)
|
||||
}
|
||||
|
||||
// func (bc *Blockchain) Mint(toAddr Address, amount uint64) error {
|
||||
// fromAddr := Address(HashBytes([]byte("mint")))
|
||||
// out :=
|
||||
// tx := NewTx(fromAddr, toAddr, []Input, )
|
||||
// }
|
||||
|
||||
@@ -3,19 +3,27 @@ package core
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/arnaucube/slowlorisdb/db"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBlockchainDataStructure(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "db")
|
||||
assert.Nil(t, err)
|
||||
db, err := db.New(dir)
|
||||
assert.Nil(t, err)
|
||||
|
||||
bc := NewBlockchain(db, uint64(1))
|
||||
block := bc.NewBlock([]Tx{})
|
||||
// dir, err := ioutil.TempDir("", "db")
|
||||
// assert.Nil(t, err)
|
||||
// db, err := db.New(dir)
|
||||
// assert.Nil(t, err)
|
||||
//
|
||||
// bc := NewBlockchain(db, uint64(1))
|
||||
block := &Block{
|
||||
PrevHash: Hash{},
|
||||
Txs: []Tx{},
|
||||
Miner: Address{},
|
||||
Timestamp: time.Now(),
|
||||
Nonce: 0,
|
||||
Hash: HashBytes([]byte("blockhash")),
|
||||
}
|
||||
|
||||
block2, err := BlockFromBytes(block.Bytes())
|
||||
assert.Nil(t, err)
|
||||
@@ -30,7 +38,15 @@ func TestGetBlock(t *testing.T) {
|
||||
|
||||
bc := NewBlockchain(db, uint64(1))
|
||||
|
||||
block := bc.NewBlock([]Tx{})
|
||||
block := &Block{
|
||||
Height: uint64(1),
|
||||
PrevHash: Hash{},
|
||||
Txs: []Tx{},
|
||||
Miner: Address{},
|
||||
Timestamp: time.Now(),
|
||||
Nonce: 0,
|
||||
Hash: HashBytes([]byte("blockhash")),
|
||||
}
|
||||
assert.Equal(t, block.Height, uint64(1))
|
||||
|
||||
err = bc.AddBlock(block)
|
||||
@@ -49,10 +65,20 @@ func TestGetPrevBlock(t *testing.T) {
|
||||
|
||||
bc := NewBlockchain(db, uint64(1))
|
||||
|
||||
var prevHash Hash
|
||||
for i := 0; i < 10; i++ {
|
||||
block := bc.NewBlock([]Tx{})
|
||||
block := &Block{
|
||||
Height: uint64(i + 1),
|
||||
PrevHash: prevHash,
|
||||
Txs: []Tx{},
|
||||
Miner: Address{},
|
||||
Timestamp: time.Now(),
|
||||
Nonce: 0,
|
||||
Hash: Hash{},
|
||||
}
|
||||
block.CalculatePoW(bc.Difficulty)
|
||||
assert.Equal(t, block.Height, uint64(i+1))
|
||||
prevHash = block.Hash
|
||||
|
||||
err = bc.AddBlock(block)
|
||||
assert.Nil(t, err)
|
||||
@@ -73,6 +99,7 @@ func TestGetPrevBlock(t *testing.T) {
|
||||
assert.Equal(t, err.Error(), "This was the oldest block")
|
||||
}
|
||||
|
||||
/*
|
||||
func TestAddBlockWithTx(t *testing.T) {
|
||||
addr0 := Address(HashBytes([]byte("addr0")))
|
||||
addr1 := Address(HashBytes([]byte("addr1")))
|
||||
@@ -87,9 +114,47 @@ func TestAddBlockWithTx(t *testing.T) {
|
||||
var txs []Tx
|
||||
tx := NewTx(addr0, addr1, []Input{}, []Output{})
|
||||
txs = append(txs, *tx)
|
||||
block := bc.NewBlock(txs)
|
||||
block := &Block{
|
||||
PrevHash: Hash{},
|
||||
NextHash: Hash{},
|
||||
Txs: txs,
|
||||
Miner: Address{},
|
||||
Timestamp: time.Now(),
|
||||
Nonce: 0,
|
||||
Hash: HashBytes([]byte("blockhash")),
|
||||
}
|
||||
|
||||
block2, err := BlockFromBytes(block.Bytes())
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, block2.Bytes(), block.Bytes())
|
||||
}
|
||||
|
||||
func TestPoABlockchainDataStructure(t *testing.T) {
|
||||
dir, err := ioutil.TempDir("", "db")
|
||||
assert.Nil(t, err)
|
||||
db, err := db.New(dir)
|
||||
assert.Nil(t, err)
|
||||
|
||||
var authNodesPubK []*ecdsa.PublicKey
|
||||
for i := 0; i < 3; i++ {
|
||||
privK, err := NewKey()
|
||||
assert.Nil(t, err)
|
||||
authNodesPubK = append(authNodesPubK, &privK.PublicKey)
|
||||
}
|
||||
|
||||
bc := NewPoABlockchain(db, authNodesPubK)
|
||||
block := &Block{
|
||||
PrevHash: Hash{},
|
||||
NextHash: Hash{},
|
||||
Txs: []Tx{},
|
||||
Miner: Address{},
|
||||
Timestamp: time.Now(),
|
||||
Nonce: 0,
|
||||
Hash: HashBytes([]byte("blockhash")),
|
||||
}
|
||||
|
||||
block2, err := BlockFromBytes(block.Bytes())
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, block2.Bytes(), block.Bytes())
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -94,7 +94,6 @@ func Sign(privK *ecdsa.PrivateKey, m []byte) (*Signature, error) {
|
||||
|
||||
func VerifySignature(pubK *ecdsa.PublicKey, m []byte, sig Signature) bool {
|
||||
hashMsg := HashBytes(m)
|
||||
|
||||
verified := ecdsa.Verify(pubK, hashMsg[:], sig.R, sig.S)
|
||||
return verified
|
||||
}
|
||||
|
||||
@@ -46,5 +46,7 @@ func CheckTx(tx *Tx) bool {
|
||||
if totalIn < totalOut {
|
||||
return false
|
||||
}
|
||||
|
||||
// TODO check signature
|
||||
return true
|
||||
}
|
||||
|
||||
36
node/node.go
36
node/node.go
@@ -2,31 +2,28 @@ package node
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"time"
|
||||
|
||||
"github.com/arnaucube/slowlorisdb/core"
|
||||
"github.com/arnaucube/slowlorisdb/db"
|
||||
)
|
||||
|
||||
type Node struct {
|
||||
PrivK *ecdsa.PrivateKey
|
||||
Addr core.Address
|
||||
Bc *core.Blockchain
|
||||
Miner bool // indicates if the node is running as a miner
|
||||
PendingTxs []core.Tx
|
||||
}
|
||||
|
||||
func NewNode(db *db.Db, dif uint64) (*Node, error) {
|
||||
privK, err := core.NewKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
func NewNode(privK *ecdsa.PrivateKey, bc *core.Blockchain, isMiner bool) (*Node, error) {
|
||||
addr := core.AddressFromPrivK(privK)
|
||||
|
||||
bc := core.NewBlockchain(db, dif)
|
||||
|
||||
node := &Node{
|
||||
PrivK: privK,
|
||||
Addr: addr,
|
||||
Bc: bc,
|
||||
PrivK: privK,
|
||||
Addr: addr,
|
||||
Bc: bc,
|
||||
Miner: isMiner,
|
||||
PendingTxs: []core.Tx{},
|
||||
}
|
||||
return node, nil
|
||||
}
|
||||
@@ -44,7 +41,7 @@ func (node *Node) AddToPendingTxs(tx core.Tx) {
|
||||
}
|
||||
|
||||
func (node *Node) BlockFromPendingTxs() (*core.Block, error) {
|
||||
block := node.Bc.NewBlock(node.PendingTxs)
|
||||
block := node.NewBlock(node.PendingTxs)
|
||||
err := block.CalculatePoW(node.Bc.Difficulty)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -56,3 +53,18 @@ func (node *Node) BlockFromPendingTxs() (*core.Block, error) {
|
||||
block.Signature = sig.Bytes()
|
||||
return block, nil
|
||||
}
|
||||
|
||||
func (node *Node) NewBlock(txs []core.Tx) *core.Block {
|
||||
block := &core.Block{
|
||||
Height: node.Bc.GetHeight() + 1,
|
||||
PrevHash: node.Bc.LastBlock.Hash,
|
||||
Txs: txs,
|
||||
Miner: core.Address{},
|
||||
MinerPubK: &node.PrivK.PublicKey,
|
||||
Timestamp: time.Now(),
|
||||
Nonce: 0,
|
||||
Hash: core.Hash{},
|
||||
Signature: []byte{},
|
||||
}
|
||||
return block
|
||||
}
|
||||
|
||||
@@ -15,7 +15,12 @@ func TestNode(t *testing.T) {
|
||||
db, err := db.New(dir)
|
||||
assert.Nil(t, err)
|
||||
|
||||
node, err := NewNode(db, uint64(1))
|
||||
privK, err := core.NewKey()
|
||||
assert.Nil(t, err)
|
||||
|
||||
dif := uint64(1)
|
||||
bc := core.NewBlockchain(db, dif)
|
||||
node, err := NewNode(privK, bc, true)
|
||||
assert.Nil(t, err)
|
||||
|
||||
assert.Equal(t, node.Addr, core.AddressFromPrivK(node.PrivK))
|
||||
@@ -27,7 +32,12 @@ func TestNodeSignature(t *testing.T) {
|
||||
db, err := db.New(dir)
|
||||
assert.Nil(t, err)
|
||||
|
||||
node, err := NewNode(db, uint64(1))
|
||||
privK, err := core.NewKey()
|
||||
assert.Nil(t, err)
|
||||
|
||||
dif := uint64(1)
|
||||
bc := core.NewBlockchain(db, dif)
|
||||
node, err := NewNode(privK, bc, true)
|
||||
assert.Nil(t, err)
|
||||
|
||||
m := []byte("test")
|
||||
@@ -43,7 +53,12 @@ func TestBlockFromPendingTxs(t *testing.T) {
|
||||
db, err := db.New(dir)
|
||||
assert.Nil(t, err)
|
||||
|
||||
node, err := NewNode(db, uint64(1))
|
||||
privK, err := core.NewKey()
|
||||
assert.Nil(t, err)
|
||||
|
||||
dif := uint64(1)
|
||||
bc := core.NewBlockchain(db, dif)
|
||||
node, err := NewNode(privK, bc, true)
|
||||
assert.Nil(t, err)
|
||||
|
||||
addr0 := core.Address(core.HashBytes([]byte("addr0")))
|
||||
@@ -53,7 +68,7 @@ func TestBlockFromPendingTxs(t *testing.T) {
|
||||
block, err := node.BlockFromPendingTxs()
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, core.CheckBlockPoW(block, node.Bc.Difficulty))
|
||||
assert.True(t, core.VerifyBlockSignature(&node.PrivK.PublicKey, block))
|
||||
assert.True(t, node.Bc.VerifyBlockSignature(block))
|
||||
}
|
||||
|
||||
func TestBlockFromPendingTxsIteration(t *testing.T) {
|
||||
@@ -62,7 +77,12 @@ func TestBlockFromPendingTxsIteration(t *testing.T) {
|
||||
db, err := db.New(dir)
|
||||
assert.Nil(t, err)
|
||||
|
||||
node, err := NewNode(db, uint64(1))
|
||||
privK, err := core.NewKey()
|
||||
assert.Nil(t, err)
|
||||
|
||||
dif := uint64(1)
|
||||
bc := core.NewBlockchain(db, dif)
|
||||
node, err := NewNode(privK, bc, true)
|
||||
assert.Nil(t, err)
|
||||
|
||||
addr0 := core.Address(core.HashBytes([]byte("addr0")))
|
||||
@@ -74,5 +94,5 @@ func TestBlockFromPendingTxsIteration(t *testing.T) {
|
||||
block, err := node.BlockFromPendingTxs()
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, core.CheckBlockPoW(block, node.Bc.Difficulty))
|
||||
assert.True(t, core.VerifyBlockSignature(&node.PrivK.PublicKey, block))
|
||||
assert.True(t, node.Bc.VerifyBlockSignature(block))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user