@ -0,0 +1,73 @@ |
|||||
|
package core |
||||
|
|
||||
|
import ( |
||||
|
"encoding/json" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
type Input struct { |
||||
|
} |
||||
|
type Output struct { |
||||
|
} |
||||
|
|
||||
|
// Tx holds the data structure of a transaction
|
||||
|
type Tx struct { |
||||
|
From Address |
||||
|
To Address |
||||
|
InputCount uint64 |
||||
|
Inputs []Input |
||||
|
Outputs []Output |
||||
|
} |
||||
|
|
||||
|
func NewTx(from, to Address, in []Input, out []Output) *Tx { |
||||
|
tx := &Tx{ |
||||
|
From: from, |
||||
|
To: to, |
||||
|
InputCount: uint64(len(in)), |
||||
|
Inputs: in, |
||||
|
Outputs: out, |
||||
|
} |
||||
|
return tx |
||||
|
} |
||||
|
|
||||
|
// Block holds the data structure for the block
|
||||
|
type Block struct { |
||||
|
Height uint64 |
||||
|
PrevHash Hash |
||||
|
NextHash Hash |
||||
|
Txs []Tx |
||||
|
Miner Address |
||||
|
Timestamp time.Time |
||||
|
Nonce uint64 |
||||
|
Hash Hash |
||||
|
Signature []byte |
||||
|
} |
||||
|
|
||||
|
// Bytes outputs a byte array containing the data of the Block
|
||||
|
func (blk Block) Bytes() []byte { |
||||
|
b, _ := json.Marshal(blk) |
||||
|
return b |
||||
|
} |
||||
|
|
||||
|
func (blk *Block) GetNonce() uint64 { |
||||
|
return blk.Nonce |
||||
|
} |
||||
|
|
||||
|
func (blk *Block) IncrementNonce() { |
||||
|
blk.Nonce++ |
||||
|
} |
||||
|
func (block *Block) CalculatePoW(difficulty int) error { |
||||
|
hash := HashBytes(block.Bytes()) |
||||
|
for !CheckPoW(hash, difficulty) { |
||||
|
block.IncrementNonce() |
||||
|
hash = HashBytes(block.Bytes()) |
||||
|
} |
||||
|
block.Hash = hash |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
func BlockFromBytes(b []byte) (*Block, error) { |
||||
|
var block *Block |
||||
|
err := json.Unmarshal(b, &block) |
||||
|
return block, err |
||||
|
} |
@ -0,0 +1,68 @@ |
|||||
|
package core |
||||
|
|
||||
|
import ( |
||||
|
"testing" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/stretchr/testify/assert" |
||||
|
) |
||||
|
|
||||
|
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(), |
||||
|
Nonce: 0, |
||||
|
Hash: HashBytes([]byte("blockhash")), |
||||
|
} |
||||
|
|
||||
|
block, err := BlockFromBytes(block.Bytes()) |
||||
|
assert.Nil(t, err) |
||||
|
assert.Equal(t, block.Bytes(), block.Bytes()) |
||||
|
|
||||
|
difficulty := 2 |
||||
|
nonce, err := CalculatePoW(block, difficulty) |
||||
|
assert.Nil(t, err) |
||||
|
block.Nonce = nonce |
||||
|
h := HashBytes(block.Bytes()) |
||||
|
|
||||
|
// CheckPoW
|
||||
|
assert.True(t, CheckPoW(h, difficulty)) |
||||
|
} |
||||
|
|
||||
|
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(), |
||||
|
Nonce: 0, |
||||
|
Hash: HashBytes([]byte("blockhash")), |
||||
|
} |
||||
|
|
||||
|
block2, err := BlockFromBytes(block.Bytes()) |
||||
|
assert.Nil(t, err) |
||||
|
assert.Equal(t, block2.Bytes(), block.Bytes()) |
||||
|
|
||||
|
difficulty := 2 |
||||
|
nonce, err := CalculatePoW(block, difficulty) |
||||
|
assert.Nil(t, err) |
||||
|
block.Nonce = nonce |
||||
|
h := HashBytes(block.Bytes()) |
||||
|
|
||||
|
// CheckPoW
|
||||
|
assert.True(t, CheckPoW(h, difficulty)) |
||||
|
} |
||||
|
|
||||
|
func TestTx(t *testing.T) { |
||||
|
addr0 := Address(HashBytes([]byte("addr0"))) |
||||
|
addr1 := Address(HashBytes([]byte("addr1"))) |
||||
|
|
||||
|
tx := NewTx(addr0, addr1, []Input{}, []Output{}) |
||||
|
|
||||
|
assert.Equal(t, tx.From, addr0) |
||||
|
assert.Equal(t, tx.To, addr1) |
||||
|
} |