mirror of
https://github.com/arnaucube/slowlorisdb.git
synced 2026-02-28 05:46:48 +01:00
blockchain data structure and initial functions
This commit is contained in:
80
core/blockchain.go
Normal file
80
core/blockchain.go
Normal file
@@ -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
core/blockchain_test.go
Normal file
96
core/blockchain_test.go
Normal file
@@ -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())
|
||||
}
|
||||
Reference in New Issue
Block a user