Skip to content

Commit

Permalink
Update blockchain, tests, hash, cmd, app, consensus, message
Browse files Browse the repository at this point in the history
App:
- Add blockchain download then target is specified
- Fix bugs in RequestHandler 
- Fix block decoding bugs in SyncBlockChain 

Blockchain:
- Add DecodeBlockJSON
- Change CopyBlockByBlockHash to GetBlockByBlockHash

Cmd/Conf:
- Change no-miner to miner, so we don't mine by default

Conn:
- Replace TestConn with BufConn

Consensus:
- Fix Cloudbase transaction validation bugs

Message:
- Add BadRequest protocol error
- Update decoding so it handles big numbers
  • Loading branch information
bfbachmann committed Aug 12, 2017
1 parent 8060ab9 commit 7a91b3f
Show file tree
Hide file tree
Showing 13 changed files with 265 additions and 241 deletions.
73 changes: 48 additions & 25 deletions app/app.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package app

import (
"encoding/json"
"errors"
"fmt"
"os"
Expand Down Expand Up @@ -86,7 +87,7 @@ func Run(cfg conf.Config) {
// stream in. Kick off a worker to handle requests and pushes.
go a.HandleWork()

if !config.NoMiner {
if config.Mine {
// Start the miner
go a.Mine()
}
Expand Down Expand Up @@ -132,6 +133,14 @@ func Run(cfg conf.Config) {
if len(config.Target) > 0 {
// Connect to the target and discover its peers.
a.ConnectAndDiscover(cfg.Target)

// Download blockchain
log.Info("Syncronizing blockchain")
_, err := a.SyncBlockChain()
if err != nil {
log.WithError(err).Fatal("Failed to download blockchain")
}
log.Info("Blockchain synchronization complete")
}
}

Expand Down Expand Up @@ -160,28 +169,36 @@ func (a *App) RequestHandler(req *msg.Request) msg.Response {
"Invalid resource type")
notFoundErr := msg.NewProtocolError(msg.ResourceNotFound,
"Resource not found.")
badRequestErr := msg.NewProtocolError(msg.BadRequest,
"Bad request")

switch req.ResourceType {
case msg.ResourcePeerInfo:
res.Resource = a.PeerStore.Addrs()
case msg.ResourceBlock:
log.Debug("Received block request")

// Block is requested by block hash.
blockHash, ok := req.Params["lastBlockHash"].(blockchain.Hash)
if ok {
// If its ok, we make try to a copy of it.
blk, err := a.Chain.CopyBlockByLastBlockHash(blockHash)
if err != nil {
// Bad index parameter.
res.Error = notFoundErr
} else {
res.Resource = blk
}
} else {
// No blockHash parameter.
hashBytes, err := json.Marshal(req.Params["lastBlockHash"])
if err != nil {
res.Error = badRequestErr
break
}

var hash blockchain.Hash
err = json.Unmarshal(hashBytes, &hash)
if err != nil {
res.Error = badRequestErr
break
}

block, err := a.Chain.GetBlockByLastBlockHash(hash)
if err != nil {
res.Error = notFoundErr
} else {
res.Resource = block
}
default:
// Return err by default.
res.Error = typeErr
}

Expand Down Expand Up @@ -223,11 +240,9 @@ func getLocalChain(user *User) *blockchain.BlockChain {
}

genisisBlock := blockchain.Genesis(user.Wallet.Public(),
consensus.CurrentTarget(), consensus.StartingBlockReward,
make([]byte, 0))
consensus.CurrentTarget(), consensus.StartingBlockReward, []byte{})

bc.Blocks = append(bc.Blocks, genisisBlock)
bc.Head = blockchain.HashSum(genisisBlock)
bc.AppendBlock(genisisBlock)
return &bc
}

Expand Down Expand Up @@ -256,9 +271,9 @@ func (a *App) HandleWork() {
func (a *App) HandleTransaction(txn *blockchain.Transaction) {
validTransaction := a.Pool.Push(txn, a.Chain)
if validTransaction {
log.Debug("added transaction to pool from address: " + txn.Sender.Repr())
log.Debug("Added transaction to pool from address: " + txn.Sender.Repr())
} else {
log.Debug("bad transaction rejected from sender: " + txn.Sender.Repr())
log.Debug("Bad transaction rejected from sender: " + txn.Sender.Repr())
}
}

Expand Down Expand Up @@ -341,13 +356,20 @@ func (a *App) SyncBlockChain() (bool, error) {
return
}

block, ok := blockResponse.Resource.(blockchain.Block)
if !ok {
blockBytes, err := json.Marshal(blockResponse.Resource)
if err != nil {
newBlockChan <- nil
return
}

block, err := blockchain.DecodeBlockJSON(blockBytes)
if err != nil {
log.WithError(err).Error("Error decoding block")
newBlockChan <- nil
return
}

newBlockChan <- &block
newBlockChan <- block
}

// Continually request the block after the latest block in our chain until
Expand Down Expand Up @@ -385,19 +407,20 @@ func (a *App) SyncBlockChain() (bool, error) {
if newBlock == nil {
// We received a response with no error but an invalid resource
// Try again
log.Debug("Received block response with invalid resource")
continue
}

valid, validationCode := consensus.VerifyBlock(a.Chain, newBlock)
if !valid {
// There is something wrong with this block. Try again
fields := log.Fields{"validationCode": validationCode}
log.WithFields(fields).Debug(
"SyncBlockchain received invalid block")
log.WithFields(fields).Debug("SyncBlockchain received invalid block")
continue
}

// Valid block. Append it to the chain
log.Debug("Adding block to blockchain")
a.Chain.AppendBlock(newBlock)
changed = true

Expand Down
24 changes: 9 additions & 15 deletions blockchain/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ package blockchain

// BlockHeader contains metadata about a block
import (
"encoding/gob"
"fmt"
"io"
"bytes"
"encoding/json"

"github.com/ubclaunchpad/cumulus/common/util"
)
Expand Down Expand Up @@ -79,19 +78,14 @@ func (b *Block) Marshal() []byte {
return buf
}

// Encode writes the marshalled block to the given io.Writer
func (b *Block) Encode(w io.Writer) {
err := gob.NewEncoder(w).Encode(b)
if err != nil {
fmt.Println(err.Error())
}
}

// DecodeBlock reads the marshalled block from the given io.Reader and populates b
func DecodeBlock(r io.Reader) *Block {
// DecodeBlockJSON returns a block read from the given marshalled block, or an
// error if blockBytes cannot be decoded as JSON.
func DecodeBlockJSON(blockBytes []byte) (*Block, error) {
var b Block
gob.NewDecoder(r).Decode(&b)
return &b
dec := json.NewDecoder(bytes.NewReader(blockBytes))
dec.UseNumber()
err := dec.Decode(&b)
return &b, err
}

// ContainsTransaction returns true and the transaction itself if the Block
Expand Down
15 changes: 7 additions & 8 deletions blockchain/block_test.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
package blockchain

import (
"bytes"
"encoding/json"
"testing"

"github.com/ubclaunchpad/cumulus/common/util"
)

func TestEncodeDecodeBlock(t *testing.T) {
func TestEncodeDecodeBlockJSON(t *testing.T) {
b1 := NewTestBlock()

buf := bytes.NewBuffer(make([]byte, 0, b1.Len()))

b1.Encode(buf)
b2 := DecodeBlock(buf)

b1Bytes, err := json.Marshal(b1)
b2, err := DecodeBlockJSON(b1Bytes)
if err != nil {
t.FailNow()
}
if HashSum(b1) != HashSum(b2) {
t.Fail()
}
Expand Down
11 changes: 3 additions & 8 deletions blockchain/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,6 @@ func DecodeBlockChain(r io.Reader) *BlockChain {

// AppendBlock adds a block to the end of the block chain.
func (bc *BlockChain) AppendBlock(b *Block) {
b.BlockNumber = uint32(len(bc.Blocks))
b.LastBlock = HashSum(bc.Blocks[b.BlockNumber-1])
bc.Blocks = append(bc.Blocks, b)
bc.Head = HashSum(b)
}
Expand Down Expand Up @@ -79,17 +77,14 @@ func (bc *BlockChain) ContainsTransaction(t *Transaction, start, stop uint32) (b
return false, 0, 0
}

// CopyBlockByLastBlockHash returns a copy of the block in the local chain that
// GetBlockByLastBlockHash returns a copy of the block in the local chain that
// comes directly after the block with the given hash. Returns error if no such
// block is found.
func (bc *BlockChain) CopyBlockByLastBlockHash(hash Hash) (*Block, error) {
func (bc *BlockChain) GetBlockByLastBlockHash(hash Hash) (*Block, error) {
// Find the block with the given hash
for _, block := range bc.Blocks {
if block.LastBlock == hash {
newBlock := *block
newBlock.Transactions = make([]*Transaction, len(block.Transactions))
copy(newBlock.Transactions, block.Transactions)
return &newBlock, nil
return block, nil
}
}
return nil, errors.New("No such block")
Expand Down
9 changes: 2 additions & 7 deletions blockchain/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,13 @@ func TestEncodeDecodeBlockChain(t *testing.T) {
}
}

func TestCopyBlock(t *testing.T) {
func TestGetBlock(t *testing.T) {
bc, _ := NewValidTestChainAndBlock()
b, _ := bc.CopyBlockByLastBlockHash(bc.Blocks[1].LastBlock)
b, _ := bc.GetBlockByLastBlockHash(bc.Blocks[1].LastBlock)

if !reflect.DeepEqual(b, bc.Blocks[1]) {
t.FailNow()
}

// Enforce copy.
if b == bc.Blocks[1] {
t.FailNow()
}
}

func TestWalletRepr(t *testing.T) {
Expand Down
6 changes: 3 additions & 3 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ var runCmd = &cobra.Command{
iface, _ := cmd.Flags().GetString("interface")
target, _ := cmd.Flags().GetString("target")
verbose, _ := cmd.Flags().GetBool("verbose")
noMiner, _ := cmd.Flags().GetBool("no-miner")
mine, _ := cmd.Flags().GetBool("mine")
console, _ := cmd.Flags().GetBool("console")
config := conf.Config{
Interface: iface,
Port: uint16(port),
Target: target,
Verbose: verbose,
NoMiner: noMiner,
Mine: mine,
Console: console,
}

Expand Down Expand Up @@ -53,5 +53,5 @@ func init() {
runCmd.Flags().StringP("target", "t", "", "Address of peer to connect to")
runCmd.Flags().BoolP("verbose", "v", false, "Enable verbose logging")
runCmd.Flags().BoolP("console", "c", false, "Start Cumulus console")
runCmd.Flags().BoolP("no-miner", "n", false, "Disable mining on this node")
runCmd.Flags().BoolP("mine", "m", false, "Enable mining on this node")
}
2 changes: 1 addition & 1 deletion conf/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ type Config struct {
// Whether or not to enable verbose logging.
Verbose bool
// Whether or not to participate in mining new blocks.
NoMiner bool
Mine bool
// Whether or not to start the Cumulus console
Console bool
}
Loading

0 comments on commit 7a91b3f

Please sign in to comment.