add node create blocks from pending txs

This commit is contained in:
arnaucube
2019-04-07 13:56:27 +02:00
parent 67e7f532e4
commit e122822151
9 changed files with 117 additions and 36 deletions

View File

@@ -43,6 +43,20 @@ type Block struct {
Signature []byte Signature []byte
} }
func (block Block) Copy() *Block {
return &Block{
Height: block.Height,
PrevHash: block.PrevHash,
NextHash: block.NextHash,
Txs: block.Txs,
Miner: block.Miner,
Timestamp: block.Timestamp,
Nonce: block.Nonce,
Hash: block.Hash,
Signature: block.Signature,
}
}
// Bytes outputs a byte array containing the data of the Block // Bytes outputs a byte array containing the data of the Block
func (blk Block) Bytes() []byte { func (blk Block) Bytes() []byte {
b, _ := json.Marshal(blk) b, _ := json.Marshal(blk)
@@ -56,16 +70,25 @@ func (blk *Block) GetNonce() uint64 {
func (blk *Block) IncrementNonce() { func (blk *Block) IncrementNonce() {
blk.Nonce++ blk.Nonce++
} }
func (block *Block) CalculatePoW(difficulty int) error { func (block *Block) CalculatePoW(difficulty uint64) error {
hash := HashBytes(block.Bytes()) blockCopy := block.Copy()
blockCopy.Hash = Hash{}
hash := HashBytes(blockCopy.Bytes())
for !CheckPoW(hash, difficulty) { for !CheckPoW(hash, difficulty) {
block.IncrementNonce() blockCopy.IncrementNonce()
hash = HashBytes(block.Bytes()) hash = HashBytes(blockCopy.Bytes())
} }
block.Hash = hash block.Hash = hash
return nil return nil
} }
func CheckBlockPoW(block *Block, difficulty uint64) bool {
blockCopy := block.Copy()
blockCopy.Hash = Hash{}
return CheckPoW(HashBytes(blockCopy.Bytes()), difficulty)
}
func BlockFromBytes(b []byte) (*Block, error) { func BlockFromBytes(b []byte) (*Block, error) {
var block *Block var block *Block
err := json.Unmarshal(b, &block) err := json.Unmarshal(b, &block)

View File

@@ -18,11 +18,14 @@ func TestBlock(t *testing.T) {
Hash: HashBytes([]byte("blockhash")), Hash: HashBytes([]byte("blockhash")),
} }
block, err := BlockFromBytes(block.Bytes()) blockParsed, err := BlockFromBytes(block.Bytes())
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, block.Bytes(), block.Bytes()) assert.Equal(t, blockParsed.Bytes(), block.Bytes())
difficulty := 2 blockCopy := block.Copy()
assert.Equal(t, blockCopy.Bytes(), block.Bytes())
difficulty := uint64(2)
nonce, err := CalculatePoW(block, difficulty) nonce, err := CalculatePoW(block, difficulty)
assert.Nil(t, err) assert.Nil(t, err)
block.Nonce = nonce block.Nonce = nonce
@@ -47,7 +50,7 @@ func TestNewBlock(t *testing.T) {
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, block2.Bytes(), block.Bytes()) assert.Equal(t, block2.Bytes(), block.Bytes())
difficulty := 2 difficulty := uint64(2)
nonce, err := CalculatePoW(block, difficulty) nonce, err := CalculatePoW(block, difficulty)
assert.Nil(t, err) assert.Nil(t, err)
block.Nonce = nonce block.Nonce = nonce

View File

@@ -8,18 +8,20 @@ import (
) )
type Blockchain struct { type Blockchain struct {
Id []byte // Id allows to have multiple blockchains Id []byte // Id allows to have multiple blockchains
Genesis Hash Difficulty uint64
LastBlock *Block Genesis Hash
db *db.Db LastBlock *Block
db *db.Db
} }
func NewBlockchain(database *db.Db) *Blockchain { func NewBlockchain(database *db.Db, dif uint64) *Blockchain {
blockchain := &Blockchain{ blockchain := &Blockchain{
Id: []byte{}, Id: []byte{},
Genesis: Hash{}, Difficulty: dif,
LastBlock: &Block{}, Genesis: HashBytes([]byte("genesis")),
db: database, LastBlock: &Block{},
db: database,
} }
return blockchain return blockchain
} }

View File

@@ -14,7 +14,7 @@ func TestBlockchainDataStructure(t *testing.T) {
db, err := db.New(dir) db, err := db.New(dir)
assert.Nil(t, err) assert.Nil(t, err)
bc := NewBlockchain(db) bc := NewBlockchain(db, uint64(1))
block := bc.NewBlock([]Tx{}) block := bc.NewBlock([]Tx{})
block2, err := BlockFromBytes(block.Bytes()) block2, err := BlockFromBytes(block.Bytes())
@@ -28,7 +28,7 @@ func TestGetBlock(t *testing.T) {
db, err := db.New(dir) db, err := db.New(dir)
assert.Nil(t, err) assert.Nil(t, err)
bc := NewBlockchain(db) bc := NewBlockchain(db, uint64(1))
block := bc.NewBlock([]Tx{}) block := bc.NewBlock([]Tx{})
assert.Equal(t, block.Height, uint64(1)) assert.Equal(t, block.Height, uint64(1))
@@ -47,12 +47,11 @@ func TestGetPrevBlock(t *testing.T) {
db, err := db.New(dir) db, err := db.New(dir)
assert.Nil(t, err) assert.Nil(t, err)
difficulty := 1 bc := NewBlockchain(db, uint64(1))
bc := NewBlockchain(db)
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
block := bc.NewBlock([]Tx{}) block := bc.NewBlock([]Tx{})
block.CalculatePoW(difficulty) block.CalculatePoW(bc.Difficulty)
assert.Equal(t, block.Height, uint64(i+1)) assert.Equal(t, block.Height, uint64(i+1))
err = bc.AddBlock(block) err = bc.AddBlock(block)
@@ -83,7 +82,7 @@ func TestAddBlockWithTx(t *testing.T) {
db, err := db.New(dir) db, err := db.New(dir)
assert.Nil(t, err) assert.Nil(t, err)
bc := NewBlockchain(db) bc := NewBlockchain(db, uint64(1))
var txs []Tx var txs []Tx
tx := NewTx(addr0, addr1, []Input{}, []Output{}) tx := NewTx(addr0, addr1, []Input{}, []Output{})

View File

@@ -31,7 +31,7 @@ type PoWData interface {
} }
// CheckPoW verifies the PoW difficulty of a Hash // CheckPoW verifies the PoW difficulty of a Hash
func CheckPoW(hash Hash, difficulty int) bool { func CheckPoW(hash Hash, difficulty uint64) bool {
var empty [32]byte var empty [32]byte
if !bytes.Equal(hash[:][0:difficulty], empty[0:difficulty]) { if !bytes.Equal(hash[:][0:difficulty], empty[0:difficulty]) {
return false return false
@@ -40,7 +40,7 @@ func CheckPoW(hash Hash, difficulty int) bool {
} }
// CalculatePoW calculates the nonce for the given data in order to fit in the current Proof of Work difficulty // CalculatePoW calculates the nonce for the given data in order to fit in the current Proof of Work difficulty
func CalculatePoW(data PoWData, difficulty int) (uint64, error) { func CalculatePoW(data PoWData, difficulty uint64) (uint64, error) {
hash := HashBytes(data.Bytes()) hash := HashBytes(data.Bytes())
for !CheckPoW(hash, difficulty) { for !CheckPoW(hash, difficulty) {
data.IncrementNonce() data.IncrementNonce()

View File

@@ -36,7 +36,7 @@ func (d *testData) IncrementNonce() {
} }
func TestPoW(t *testing.T) { func TestPoW(t *testing.T) {
difficulty := 2 difficulty := uint64(2)
data := &testData{ data := &testData{
Data: []byte("test"), Data: []byte("test"),
Nonce: 0, Nonce: 0,

View File

@@ -45,9 +45,9 @@ func AddressFromPrivK(privK *ecdsa.PrivateKey) Address {
return Address(h) return Address(h)
} }
func (sig *Signature) Bytes(r, s *big.Int) []byte { func (sig *Signature) Bytes() []byte {
b := r.Bytes() b := sig.R.Bytes()
b = append(b, s.Bytes()...) b = append(b, sig.S.Bytes()...)
return b return b
} }

View File

@@ -8,19 +8,20 @@ import (
) )
type Node struct { type Node struct {
PrivK *ecdsa.PrivateKey PrivK *ecdsa.PrivateKey
Addr core.Address Addr core.Address
Bc *core.Blockchain Bc *core.Blockchain
PendingTxs []core.Tx
} }
func NewNode(db *db.Db) (*Node, error) { func NewNode(db *db.Db, dif uint64) (*Node, error) {
privK, err := core.NewKey() privK, err := core.NewKey()
if err != nil { if err != nil {
return nil, err return nil, err
} }
addr := core.AddressFromPrivK(privK) addr := core.AddressFromPrivK(privK)
bc := core.NewBlockchain(db) bc := core.NewBlockchain(db, dif)
node := &Node{ node := &Node{
PrivK: privK, PrivK: privK,
@@ -33,3 +34,21 @@ func NewNode(db *db.Db) (*Node, error) {
func (node *Node) Sign(m []byte) (*core.Signature, error) { func (node *Node) Sign(m []byte) (*core.Signature, error) {
return core.Sign(node.PrivK, m) return core.Sign(node.PrivK, m)
} }
func (node *Node) AddToPendingTxs(tx core.Tx) {
node.PendingTxs = append(node.PendingTxs, tx)
}
func (node *Node) BlockFromPendingTxs() (*core.Block, error) {
block := node.Bc.NewBlock(node.PendingTxs)
err := block.CalculatePoW(node.Bc.Difficulty)
if err != nil {
return nil, err
}
sig, err := node.Sign(block.Bytes())
if err != nil {
return nil, err
}
block.Signature = sig.Bytes()
return block, nil
}

View File

@@ -15,7 +15,7 @@ func TestNode(t *testing.T) {
db, err := db.New(dir) db, err := db.New(dir)
assert.Nil(t, err) assert.Nil(t, err)
node, err := NewNode(db) node, err := NewNode(db, uint64(1))
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, node.Addr, core.AddressFromPrivK(node.PrivK)) assert.Equal(t, node.Addr, core.AddressFromPrivK(node.PrivK))
@@ -27,7 +27,7 @@ func TestNodeSignature(t *testing.T) {
db, err := db.New(dir) db, err := db.New(dir)
assert.Nil(t, err) assert.Nil(t, err)
node, err := NewNode(db) node, err := NewNode(db, uint64(1))
assert.Nil(t, err) assert.Nil(t, err)
m := []byte("test") m := []byte("test")
@@ -36,3 +36,38 @@ func TestNodeSignature(t *testing.T) {
pubK := node.PrivK.PublicKey pubK := node.PrivK.PublicKey
assert.True(t, core.VerifySignature(&pubK, m, *sig)) assert.True(t, core.VerifySignature(&pubK, m, *sig))
} }
func TestBlockFromPendingTxs(t *testing.T) {
dir, err := ioutil.TempDir("", "db")
assert.Nil(t, err)
db, err := db.New(dir)
assert.Nil(t, err)
node, err := NewNode(db, uint64(1))
assert.Nil(t, err)
addr0 := core.Address(core.HashBytes([]byte("addr0")))
addr1 := core.Address(core.HashBytes([]byte("addr1")))
tx := core.NewTx(addr0, addr1, []core.Input{}, []core.Output{})
node.AddToPendingTxs(*tx)
block, err := node.BlockFromPendingTxs()
assert.True(t, core.CheckBlockPoW(block, node.Bc.Difficulty))
// TODO add VerifyBlockSignature
}
// func TestBlockFromPendingTxsIteration(t *testing.T) {
// dir, err := ioutil.TempDir("", "db")
// assert.Nil(t, err)
// db, err := db.New(dir)
// assert.Nil(t, err)
//
// node, err := NewNode(db, uint64(1))
// assert.Nil(t, err)
//
// addr0 := core.Address(core.HashBytes([]byte("addr0")))
// addr1 := core.Address(core.HashBytes([]byte("addr1")))
// for i := 0; i < 10; i++ {
// tx := core.NewTx(addr0, addr1, []core.Input{}, []core.Output{})
//
// }
// }