From 16f99b279a1448bff65184882bbb84be24ba6136 Mon Sep 17 00:00:00 2001 From: arnaucube Date: Sun, 7 Apr 2019 23:19:06 +0200 Subject: [PATCH] updated data structures, moved NewBlock under Node functions --- core/block.go | 13 +------ core/block_test.go | 2 - core/blockchain.go | 69 +++++++++++++++++++++++++-------- core/blockchain_test.go | 85 ++++++++++++++++++++++++++++++++++++----- core/keys.go | 1 - core/tx.go | 2 + node/node.go | 36 +++++++++++------ node/node_test.go | 32 +++++++++++++--- 8 files changed, 182 insertions(+), 58 deletions(-) diff --git a/core/block.go b/core/block.go index dad7ce9..f69b59e 100644 --- a/core/block.go +++ b/core/block.go @@ -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) diff --git a/core/block_test.go b/core/block_test.go index 7515e2e..9c6891c 100644 --- a/core/block_test.go +++ b/core/block_test.go @@ -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(), diff --git a/core/blockchain.go b/core/blockchain.go index 22f0e23..9d3b4b2 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -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, + } + blockchain := &Blockchain{ + Id: []byte{}, + Difficulty: uint64(0), + Genesis: HashBytes([]byte("genesis")), // tmp + LastBlock: &Block{}, + blockdb: database, + PoA: poa, } - return block + 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, ) +// } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 667f6cf..940e244 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -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()) } +*/ diff --git a/core/keys.go b/core/keys.go index 5f6b91f..90709e5 100644 --- a/core/keys.go +++ b/core/keys.go @@ -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 } diff --git a/core/tx.go b/core/tx.go index cc1d98f..4ad4c0d 100644 --- a/core/tx.go +++ b/core/tx.go @@ -46,5 +46,7 @@ func CheckTx(tx *Tx) bool { if totalIn < totalOut { return false } + + // TODO check signature return true } diff --git a/node/node.go b/node/node.go index 2610348..2bcddba 100644 --- a/node/node.go +++ b/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 +} diff --git a/node/node_test.go b/node/node_test.go index db4d53c..7a31e7d 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -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)) }