Skip to content

Commit

Permalink
Merge pull request #88 from ubclaunchpad/85-block-extra-data
Browse files Browse the repository at this point in the history
85-block-extra-data
  • Loading branch information
jordanschalm committed Jul 12, 2017
2 parents 6788fe6 + d4c1fc0 commit f4f8b68
Show file tree
Hide file tree
Showing 10 changed files with 102 additions and 46 deletions.
24 changes: 11 additions & 13 deletions blockchain/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,6 @@ import (
"io"
)

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
)

// BlockHeader contains metadata about a block
type BlockHeader struct {
// BlockNumber is the position of the block within the blockchain
Expand All @@ -28,6 +21,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 +44,16 @@ 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 {
return len(bh.Marshal())
}

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

// Len returns the length in bytes of the Block.
func (b *Block) Len() int {
l := BlockHeaderLen
for _, t := range b.Transactions {
l += t.Len()
}
return l
return len(b.Marshal())
}

// Marshal converts a Block to a byte slice.
func (b *Block) Marshal() []byte {
buf := make([]byte, 0, b.Len())
var buf []byte
buf = append(buf, b.BlockHeader.Marshal()...)
for _, t := range b.Transactions {
buf = append(buf, t.Marshal()...)
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,
NewTestHash(),
NewValidTestTarget(),
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,
NewTestHash(),
NewValidTestTarget(),
uint32(time.Now().Unix()),
0,
[]byte{},
}

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

if bh.Len() != len {
t.Fail()
}
}
8 changes: 2 additions & 6 deletions blockchain/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,12 @@ type BlockChain struct {

// Len returns the length of the BlockChain when marshalled
func (bc *BlockChain) Len() int {
l := 0
for _, b := range bc.Blocks {
l += b.Len()
}
return l + HashLen
return len(bc.Marshal())
}

// Marshal converts the BlockChain to a byte slice.
func (bc *BlockChain) Marshal() []byte {
buf := make([]byte, 0, bc.Len())
var buf []byte
for _, b := range bc.Blocks {
buf = append(buf, b.Marshal()...)
}
Expand Down
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
22 changes: 9 additions & 13 deletions blockchain/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,6 @@ import (
"io"
)

const (
// TxHashPointerLen is the length in bytes of a hash pointer.
TxHashPointerLen = 32/8 + HashLen
// TxOutputLen is the length in bytes of a transaction output.
TxOutputLen = 64/8 + AddrLen
)

// TxHashPointer is a reference to a transaction on the blockchain.
type TxHashPointer struct {
BlockNumber uint32
Expand All @@ -21,9 +14,12 @@ type TxHashPointer struct {

// Marshal converts a TxHashPointer to a byte slice
func (thp TxHashPointer) Marshal() []byte {
buf := make([]byte, 4, TxHashPointerLen)
buf := make([]byte, 4)
binary.LittleEndian.PutUint32(buf, thp.BlockNumber)
buf = append(buf, thp.Hash.Marshal()...)
tempBufIndex := make([]byte, 4)
binary.LittleEndian.PutUint32(tempBufIndex, thp.Index)
buf = append(buf, tempBufIndex...)
return buf
}

Expand All @@ -35,7 +31,7 @@ type TxOutput struct {

// Marshal converts a TxOutput to a byte slice
func (to TxOutput) Marshal() []byte {
buf := make([]byte, 8, TxOutputLen)
buf := make([]byte, 8)
binary.LittleEndian.PutUint64(buf, to.Amount)
buf = append(buf, to.Recipient.Marshal()...)
return buf
Expand All @@ -50,12 +46,12 @@ type TxBody struct {

// Len returns the length of a transaction body
func (tb TxBody) Len() int {
return AddrLen + TxHashPointerLen + len(tb.Outputs)*TxOutputLen
return len(tb.Marshal())
}

// Marshal converts a TxBody to a byte slice
func (tb TxBody) Marshal() []byte {
buf := make([]byte, 0, tb.Len())
var buf []byte
buf = append(buf, tb.Sender.Marshal()...)
buf = append(buf, tb.Input.Marshal()...)
for _, out := range tb.Outputs {
Expand All @@ -79,12 +75,12 @@ type Transaction struct {

// Len returns the length in bytes of a transaction
func (t *Transaction) Len() int {
return t.TxBody.Len() + SigLen
return len(t.Marshal())
}

// Marshal converts a Transaction to a byte slice
func (t *Transaction) Marshal() []byte {
buf := make([]byte, 0, t.Len())
var buf []byte
buf = append(buf, t.TxBody.Marshal()...)
buf = append(buf, t.Sig.Marshal()...)
return buf
Expand Down
30 changes: 30 additions & 0 deletions blockchain/transaction_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package blockchain

import (
"testing"
)

func TestTxBodyLen(t *testing.T) {
txBody := NewTestTxBody()
senderLen := AddrLen
inputLen := 2*(32/8) + HashLen
outputLen := len(txBody.Outputs) * (64/8 + AddrLen)
txBodyLen := senderLen + inputLen + outputLen

if txBody.Len() != txBodyLen {
t.Fail()
}
}

func TestTransactionLen(t *testing.T) {
tx := NewTestTransaction()
senderLen := AddrLen
inputLen := 2*(32/8) + HashLen
outputLen := len(tx.TxBody.Outputs) * (64/8 + AddrLen)
txBodyLen := senderLen + inputLen + outputLen
txLen := txBodyLen + SigLen

if tx.Len() != txLen {
t.Fail()
}
}
7 changes: 4 additions & 3 deletions blockchain/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ 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 genesis block's time is invalid.
BadGenesisTime
// NilGenesisBlock is returned when the genesis block is equal to nil.
NilGenesisBlock
Expand Down Expand Up @@ -190,6 +190,7 @@ 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
Expand Down Expand Up @@ -234,12 +235,12 @@ 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 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
17 changes: 9 additions & 8 deletions blockchain/validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ 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 +407,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 @@ -446,7 +446,7 @@ 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,8 +484,9 @@ 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 = NewTestHash()

bc := &BlockChain{
Blocks: []*Block{gb},
Head: HashSum(gb),
Expand All @@ -506,7 +507,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, NewTestTransaction())
bc := &BlockChain{
Blocks: []*Block{gb},
Expand All @@ -528,7 +529,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] = NewTestTransaction()
bc := &BlockChain{
Blocks: []*Block{gb},
Expand All @@ -550,7 +551,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 +573,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
2 changes: 1 addition & 1 deletion blockchain/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ type Address struct {

// Marshal converts an Address to a byte slice.
func (a Address) Marshal() []byte {
buf := make([]byte, AddrLen)
buf := make([]byte, 0, AddrLen)
buf = append(buf, a.X.Bytes()...)
buf = append(buf, a.Y.Bytes()...)
return buf
Expand Down

0 comments on commit f4f8b68

Please sign in to comment.