Skip to content

Commit

Permalink
ExtraData field added to block
Browse files Browse the repository at this point in the history
  • Loading branch information
david-julien committed Jul 10, 2017
1 parent ce7dba1 commit 5a45c27
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 18 deletions.
20 changes: 15 additions & 5 deletions blockchain/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ import (
)

const (
// BlockSize is the maximum size of a block in bytes when marshaled (about 250K).
BlockSize = 1 << 18
// BlockHeaderLen is the length in bytes of a block header.
BlockHeaderLen = 2*(32/8) + 64/8 + 2*HashLen
// MaxBlockSize is the maximum size of a block in bytes when marshaled
// (about 250K).
MaxBlockSize = 1 << 18
)

// BlockHeader contains metadata about a block
Expand All @@ -28,6 +27,9 @@ type BlockHeader struct {
Time uint32
// Nonce starts at 0 and increments by 1 for every hash when mining
Nonce uint64
// ExtraData is an extra field that can be filled with arbitrary data to
// be stored in the block
ExtraData []byte
}

// Marshal converts a BlockHeader to a byte slice
Expand All @@ -48,10 +50,18 @@ func (bh *BlockHeader) Marshal() []byte {
buf = append(buf, bh.Target.Marshal()...)
buf = append(buf, tempBufTime...)
buf = append(buf, tempBufNonce...)
buf = append(buf, bh.ExtraData...)

return buf
}

// Len returns the length in bytes of the BlockHeader.
func (bh *BlockHeader) Len() int {
l := 2*(32/8) + 64/8 + 2*HashLen
l += len(bh.ExtraData)
return l
}

// Block represents a block in the blockchain. Contains transactions and header metadata.
type Block struct {
BlockHeader
Expand All @@ -60,7 +70,7 @@ type Block struct {

// Len returns the length in bytes of the Block.
func (b *Block) Len() int {
l := BlockHeaderLen
l := b.BlockHeader.Len()
for _, t := range b.Transactions {
l += t.Len()
}
Expand Down
33 changes: 33 additions & 0 deletions blockchain/block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package blockchain
import (
"bytes"
"testing"
"time"
)

func TestEncodeDecodeBlock(t *testing.T) {
Expand All @@ -25,3 +26,35 @@ func TestContainsTransaction(t *testing.T) {
t.Fail()
}
}

func TestBlockHeaderLen(t *testing.T) {
bh := &BlockHeader{
0,
NewHash(),
NewValidTarget(),
uint32(time.Now().Unix()),
0,
[]byte{0x00, 0x01, 0x02},
}

len := 2*(32/8) + 64/8 + 2*HashLen + 3

if bh.Len() != len {
t.Fail()
}

bh = &BlockHeader{
0,
NewHash(),
NewValidTarget(),
uint32(time.Now().Unix()),
0,
[]byte{},
}

len = 2*(32/8) + 64/8 + 2*HashLen

if bh.Len() != len {
t.Fail()
}
}
3 changes: 2 additions & 1 deletion blockchain/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
// - LastBlock = 0
// - There is only one transaction in the block, the CloudBase transaction that
// awards the miner with the block reward.
func Genesis(miner Address, target Hash, blockReward uint64) *Block {
func Genesis(miner Address, target Hash, blockReward uint64, extraData []byte) *Block {

cbReward := TxOutput{
Amount: blockReward,
Expand All @@ -38,6 +38,7 @@ func Genesis(miner Address, target Hash, blockReward uint64) *Block {
Target: target,
Time: uint32(time.Now().Unix()),
Nonce: 0,
ExtraData: extraData,
},
Transactions: []*Transaction{cbTx},
}
Expand Down
2 changes: 1 addition & 1 deletion blockchain/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ func TestGenesis(t *testing.T) {
miner := NewWallet()
currentTarget := BigIntToHash(MaxTarget)
currentBlockReward := uint64(25)
gb := Genesis(miner.Public(), currentTarget, currentBlockReward)
gb := Genesis(miner.Public(), currentTarget, currentBlockReward, []byte{})

// Check if the genesis block is equal to nil
if gb == nil {
Expand Down
23 changes: 20 additions & 3 deletions blockchain/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,11 @@ const (
BadGenesisBlockNumber
// BadGenesisTarget is returned when the genesis block's target is invalid.
BadGenesisTarget
// BadGenesisTime is returned when teh gensis block's time is invalid.
// BadGenesisTime is returned when the gensis block's time is invalid.
BadGenesisTime
// BadGenesisBlockSize is returned when the size of the block exceeds the
// maximum block size
BadGenesisBlockSize
// NilGenesisBlock is returned when the genesis block is equal to nil.
NilGenesisBlock
)
Expand Down Expand Up @@ -104,6 +107,9 @@ const (
// BadGenesisBlock is returned if the block is a genesis block and is
// invalid.
BadGenesisBlock
// BadBlockSize is returned when the size of the block exceeds the maximum
// block size
BadBlockSize
// NilBlock is returned when the block pointer is nil.
NilBlock
)
Expand Down Expand Up @@ -190,11 +196,17 @@ func ValidCloudBase(t *Transaction) (bool, CloudBaseTransactionCode) {

// ValidGenesisBlock checks whether a block is a valid genesis block.
func (bc *BlockChain) ValidGenesisBlock(gb *Block) (bool, GenesisBlockCode) {

// Check if the genesis block is equal to nil.
if gb == nil {
return false, NilGenesisBlock
}

// Check if the genesis block is too large.
if gb.Len() > MaxBlockSize {
return false, BadGenesisBlockSize
}

// Check if the genesis block's block number is equal to 0.
if gb.BlockHeader.BlockNumber != 0 ||
bc.Blocks[0] != gb {
Expand Down Expand Up @@ -234,12 +246,17 @@ func (bc *BlockChain) ValidGenesisBlock(gb *Block) (bool, GenesisBlockCode) {
// ValidBlock checks whether a block is valid.
func (bc *BlockChain) ValidBlock(b *Block) (bool, BlockCode) {

// Check if the block is equal to nil
// Check if the block is equal to nil.
if b == nil {
return false, NilBlock
}

// Check if the block is the genesis block
// Check if the block is too large.
if b.Len() > MaxBlockSize {
return false, BadBlockSize
}

// Check if the block is the genesis block.
if b.BlockHeader.BlockNumber == 0 || bc.Blocks[0] == b {
if valid, code := bc.ValidGenesisBlock(b); !valid {
log.Errorf("Invalid GenesisBlock, GenesisBlockCode: %d", code)
Expand Down
71 changes: 63 additions & 8 deletions blockchain/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,34 @@ func TestValidBlockNilBlock(t *testing.T) {
}
}

func TestValidBlockBadBlockSize(t *testing.T) {
bc, b := NewValidChainAndBlock()

for i := 0; i <= MaxBlockSize/TxOutputLen; i++ {
b.Transactions[0].Outputs = append(
b.Transactions[0].Outputs,
TxOutput{
0,
NewWallet().Public(),
},
)
}

valid, code := bc.ValidBlock(b)

if valid {
t.Fail()
}
if code != BadBlockSize {
t.Fail()
}
}

func TestValidBlockBadGenesisBlock(t *testing.T) {
miner := NewWallet()
currentTarget := BigIntToHash(MaxTarget)
currentBlockReward := uint64(25)
gb := Genesis(miner.Public(), currentTarget, currentBlockReward)
gb := Genesis(miner.Public(), currentTarget, currentBlockReward, []byte{})
gb.Target = BigIntToHash(BigExp(2, 255))
bc := &BlockChain{
Blocks: []*Block{gb},
Expand Down Expand Up @@ -407,7 +430,7 @@ func TestValidGenesisBlock(t *testing.T) {
miner := NewWallet()
currentTarget := BigIntToHash(MaxTarget)
currentBlockReward := uint64(25)
gb := Genesis(miner.Public(), currentTarget, currentBlockReward)
gb := Genesis(miner.Public(), currentTarget, currentBlockReward, []byte{})
bc := &BlockChain{
Blocks: []*Block{gb},
Head: HashSum(gb),
Expand Down Expand Up @@ -442,11 +465,43 @@ func TestValidGenesisBlockNilGenesisBlock(t *testing.T) {
}
}

func TestValidGenesisBlockBadGenesisBlockSize(t *testing.T) {
miner := NewWallet()
currentTarget := BigIntToHash(MaxTarget)
currentBlockReward := uint64(25)
gb := Genesis(miner.Public(), currentTarget, currentBlockReward, []byte{})

for i := 0; i <= MaxBlockSize/TxOutputLen; i++ {
gb.Transactions[0].Outputs = append(
gb.Transactions[0].Outputs,
TxOutput{
0,
NewWallet().Public(),
},
)
}

bc := &BlockChain{
Blocks: []*Block{gb},
Head: HashSum(gb),
}

valid, code := bc.ValidGenesisBlock(gb)

if valid {
t.Fail()
}

if code != BadGenesisBlockSize {
t.Fail()
}
}

func TestValidGenesisBlockBadGenesisBlockNumber(t *testing.T) {
miner := NewWallet()
currentTarget := BigIntToHash(MaxTarget)
currentBlockReward := uint64(25)
gb := Genesis(miner.Public(), currentTarget, currentBlockReward)
gb := Genesis(miner.Public(), currentTarget, currentBlockReward, []byte{})
gb.BlockHeader.BlockNumber = 1
bc := &BlockChain{
Blocks: []*Block{gb},
Expand Down Expand Up @@ -484,7 +539,7 @@ func TestValidGenesisBlockBadGenesisLastBlock(t *testing.T) {
miner := NewWallet()
currentTarget := BigIntToHash(MaxTarget)
currentBlockReward := uint64(25)
gb := Genesis(miner.Public(), currentTarget, currentBlockReward)
gb := Genesis(miner.Public(), currentTarget, currentBlockReward, []byte{})
gb.LastBlock = NewHash()
bc := &BlockChain{
Blocks: []*Block{gb},
Expand All @@ -506,7 +561,7 @@ func TestValidGenesisBlockBadGenesisTransactions(t *testing.T) {
miner := NewWallet()
currentTarget := BigIntToHash(MaxTarget)
currentBlockReward := uint64(25)
gb := Genesis(miner.Public(), currentTarget, currentBlockReward)
gb := Genesis(miner.Public(), currentTarget, currentBlockReward, []byte{})
gb.Transactions = append(gb.Transactions, NewTransaction())
bc := &BlockChain{
Blocks: []*Block{gb},
Expand All @@ -528,7 +583,7 @@ func TestValidGenesisBlockBadGenesisCloudBaseTransaction(t *testing.T) {
miner := NewWallet()
currentTarget := BigIntToHash(MaxTarget)
currentBlockReward := uint64(25)
gb := Genesis(miner.Public(), currentTarget, currentBlockReward)
gb := Genesis(miner.Public(), currentTarget, currentBlockReward, []byte{})
gb.Transactions[0] = NewTransaction()
bc := &BlockChain{
Blocks: []*Block{gb},
Expand All @@ -550,7 +605,7 @@ func TestValidGenesisBlockBadGenesisTarget(t *testing.T) {
miner := NewWallet()
currentTarget := BigIntToHash(MaxTarget)
currentBlockReward := uint64(25)
gb := Genesis(miner.Public(), currentTarget, currentBlockReward)
gb := Genesis(miner.Public(), currentTarget, currentBlockReward, []byte{})
gb.Target = BigIntToHash(BigExp(2, 255))
bc := &BlockChain{
Blocks: []*Block{gb},
Expand All @@ -572,7 +627,7 @@ func TestValidGenesisBlockBadGenesisTime(t *testing.T) {
miner := NewWallet()
currentTarget := BigIntToHash(MaxTarget)
currentBlockReward := uint64(25)
gb := Genesis(miner.Public(), currentTarget, currentBlockReward)
gb := Genesis(miner.Public(), currentTarget, currentBlockReward, []byte{})
gb.Time = 0
bc := &BlockChain{
Blocks: []*Block{gb},
Expand Down

0 comments on commit 5a45c27

Please sign in to comment.