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