Browse Source

blockchain data structure and initial functions

master
arnaucube 5 years ago
parent
commit
cb7a4f857d
2 changed files with 176 additions and 0 deletions
  1. +80
    -0
      core/blockchain.go
  2. +96
    -0
      core/blockchain_test.go

+ 80
- 0
core/blockchain.go

@ -0,0 +1,80 @@
package core
import (
"errors"
"slothdb/db"
"time"
)
type Blockchain struct {
Id []byte // Id allows to have multiple blockchains
Genesis Hash
LastBlock *Block
db *db.Db
}
func NewBlockchain(database *db.Db) *Blockchain {
blockchain := &Blockchain{
Id: []byte{},
Genesis: Hash{},
LastBlock: &Block{},
db: database,
}
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{},
}
return block
}
func (bc *Blockchain) GetHeight() uint64 {
return bc.LastBlock.Height
}
func (bc *Blockchain) GetLastBlock() *Block {
return bc.LastBlock
}
func (bc *Blockchain) AddBlock(block *Block) error {
bc.LastBlock = block
err := bc.db.Put(block.Hash[:], block.Bytes())
return err
}
func (bc *Blockchain) GetBlock(hash Hash) (*Block, error) {
v, err := bc.db.Get(hash[:])
if err != nil {
return nil, err
}
block, err := BlockFromBytes(v)
if err != nil {
return nil, err
}
return block, nil
}
func (bc *Blockchain) GetPrevBlock(hash Hash) (*Block, error) {
currentBlock, err := bc.GetBlock(hash)
if err != nil {
return nil, err
}
if currentBlock.PrevHash.IsZero() {
return nil, errors.New("This was the oldest block")
}
prevBlock, err := bc.GetBlock(currentBlock.PrevHash)
if err != nil {
return nil, err
}
return prevBlock, nil
}

+ 96
- 0
core/blockchain_test.go

@ -0,0 +1,96 @@
package core
import (
"io/ioutil"
"slothdb/db"
"testing"
"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)
block := bc.NewBlock([]Tx{})
block2, err := BlockFromBytes(block.Bytes())
assert.Nil(t, err)
assert.Equal(t, block2.Bytes(), block.Bytes())
}
func TestGetBlock(t *testing.T) {
dir, err := ioutil.TempDir("", "db")
assert.Nil(t, err)
db, err := db.New(dir)
assert.Nil(t, err)
bc := NewBlockchain(db)
block := bc.NewBlock([]Tx{})
assert.Equal(t, block.Height, uint64(1))
err = bc.AddBlock(block)
assert.Nil(t, err)
block2, err := bc.GetBlock(block.Hash)
assert.Nil(t, err)
assert.Equal(t, block.Bytes(), block2.Bytes())
}
func TestGetPrevBlock(t *testing.T) {
dir, err := ioutil.TempDir("", "db")
assert.Nil(t, err)
db, err := db.New(dir)
assert.Nil(t, err)
difficulty := 1
bc := NewBlockchain(db)
for i := 0; i < 10; i++ {
block := bc.NewBlock([]Tx{})
block.CalculatePoW(difficulty)
assert.Equal(t, block.Height, uint64(i+1))
err = bc.AddBlock(block)
assert.Nil(t, err)
assert.Equal(t, bc.LastBlock.Height, block.Height)
}
block9, err := bc.GetPrevBlock(bc.LastBlock.Hash)
assert.Nil(t, err)
assert.Equal(t, block9.Height, uint64(9))
block8, err := bc.GetPrevBlock(block9.Hash)
assert.Nil(t, err)
assert.Equal(t, block8.Height, uint64(8))
currentBlock := bc.LastBlock
for err == nil {
currentBlock, err = bc.GetPrevBlock(currentBlock.Hash)
}
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")))
dir, err := ioutil.TempDir("", "db")
assert.Nil(t, err)
db, err := db.New(dir)
assert.Nil(t, err)
bc := NewBlockchain(db)
var txs []Tx
tx := NewTx(addr0, addr1, []Input{}, []Output{})
txs = append(txs, *tx)
block := bc.NewBlock(txs)
block2, err := BlockFromBytes(block.Bytes())
assert.Nil(t, err)
assert.Equal(t, block2.Bytes(), block.Bytes())
}

Loading…
Cancel
Save