From 4fc353b4889bde2eb6fb6f28dd1f2ef8ddf0cd7a Mon Sep 17 00:00:00 2001 From: Bruno Bachmann Date: Sat, 12 Aug 2017 17:56:21 -0700 Subject: [PATCH] Update getLocalChain, update tests, add UpToDate for blockchain sync --- app/app.go | 28 ++++++++++++++-------------- app/app_test.go | 25 ++++++++++++------------- app/test_utils.go | 4 ++-- msg/message.go | 10 +++++++--- peer/peer.go | 2 +- 5 files changed, 36 insertions(+), 33 deletions(-) diff --git a/app/app.go b/app/app.go index 6e25ebf..4854102 100644 --- a/app/app.go +++ b/app/app.go @@ -53,7 +53,7 @@ func Run(cfg conf.Config) { a := App{ PeerStore: peer.NewPeerStore(addr), CurrentUser: user, - Chain: getLocalChain(user), + Chain: createBlockchain(user), Pool: getLocalPool(), blockQueue: make(chan *blockchain.Block, blockQueueSize), transactionQueue: make(chan *blockchain.Transaction, transactionQueueSize), @@ -171,6 +171,8 @@ func (a *App) RequestHandler(req *msg.Request) msg.Response { "Resource not found.") badRequestErr := msg.NewProtocolError(msg.BadRequest, "Bad request") + upToDateErr := msg.NewProtocolError(msg.UpToDate, + "The requested block has not yet been mined") switch req.ResourceType { case msg.ResourcePeerInfo: @@ -190,6 +192,9 @@ func (a *App) RequestHandler(req *msg.Request) msg.Response { if err != nil { res.Error = badRequestErr break + } else if len(a.Chain.Blocks) > 0 && hash == blockchain.HashSum(a.Chain.LastBlock()) { + res.Error = upToDateErr + break } block, err := a.Chain.GetBlockByLastBlockHash(hash) @@ -230,19 +235,19 @@ func (a *App) PushHandler(push *msg.Push) { } } -// getLocalChain returns an instance of the blockchain. -func getLocalChain(user *User) *blockchain.BlockChain { - // TODO: Look for local chain on disk. If doesn't exist, go rummaging +// createBlockchain returns a new instance of a blockchain with only a genesis +// block. +func createBlockchain(user *User) *blockchain.BlockChain { // around on the internets for one. bc := blockchain.BlockChain{ Blocks: make([]*blockchain.Block, 0), Head: blockchain.NilHash, } - genisisBlock := blockchain.Genesis(user.Wallet.Public(), + genesisBlock := blockchain.Genesis(user.Wallet.Public(), consensus.CurrentTarget(), consensus.StartingBlockReward, []byte{}) - bc.AppendBlock(genisisBlock) + bc.AppendBlock(genesisBlock) return &bc } @@ -344,7 +349,6 @@ func (a *App) Mine() { // to any peers. func (a *App) SyncBlockChain() (bool, error) { var currentHeadHash blockchain.Hash - prevHead := a.Chain.LastBlock() newBlockChan := make(chan *blockchain.Block) errChan := make(chan *msg.ProtocolError) changed := false @@ -364,7 +368,6 @@ func (a *App) SyncBlockChain() (bool, error) { block, err := blockchain.DecodeBlockJSON(blockBytes) if err != nil { - log.WithError(err).Error("Error decoding block") newBlockChan <- nil return } @@ -424,17 +427,14 @@ func (a *App) SyncBlockChain() (bool, error) { a.Chain.AppendBlock(newBlock) changed = true - if (&newBlock.BlockHeader).Equal(&prevHead.BlockHeader) { - // Our blockchain is up to date - return changed, nil - } - case err := <-errChan: if err.Code == msg.ResourceNotFound { // Our chain might be out of sync, roll it back by one block // and request the next block - prevHead = a.Chain.RollBack() + a.Chain.RollBack() changed = true + } else if err.Code == msg.UpToDate { + return changed, nil } // Some other protocol error occurred. Try again diff --git a/app/app_test.go b/app/app_test.go index 969590c..481527a 100644 --- a/app/app_test.go +++ b/app/app_test.go @@ -48,18 +48,17 @@ func TestPushHandlerNewTestTransaction(t *testing.T) { } } -// TODO: Enable once block request by hash implemented. -// func TestRequestHandlerNewBlockOK(t *testing.T) { -// // Request a new block by hash and verify we get the right one. -// a := createNewTestApp() +func TestRequestHandlerNewBlockOK(t *testing.T) { + // Request a new block by hash and verify we get the right one. + a := createNewTestApp() -// req := createNewTestBlockRequest(a.Chain.Blocks[1].LastBlock) -// resp := a.RequestHandler(req) -// block, ok := resp.Resource.(*blockchain.Block) + req := createNewTestBlockRequest(a.Chain.Blocks[1].LastBlock) + resp := a.RequestHandler(req) + block, ok := resp.Resource.(*blockchain.Block) -// assert.True(t, ok, "resource should contain block") -// assert.Equal(t, block, a.Chain.Blocks[1]) -// } + assert.True(t, ok, "resource should contain block") + assert.Equal(t, block, a.Chain.Blocks[1]) +} func TestRequestHandlerNewBlockBadParams(t *testing.T) { a := createNewTestApp() @@ -73,7 +72,7 @@ func TestRequestHandlerNewBlockBadParams(t *testing.T) { // Make sure request failed. assert.False(t, ok, "resource should not contain block") - assert.Equal(t, msg.ResourceNotFound, int(resp.Error.Code), resp.Error.Message) + assert.Equal(t, msg.BadRequest, int(resp.Error.Code), resp.Error.Message) } func TestRequestHandlerNewBlockBadType(t *testing.T) { @@ -161,8 +160,8 @@ func TestGetLocalPool(t *testing.T) { assert.NotNil(t, getLocalPool()) } -func TestGetLocalChain(t *testing.T) { - assert.NotNil(t, getLocalChain(NewUser())) +func TestCreateBlockchain(t *testing.T) { + assert.NotNil(t, createBlockchain(NewUser())) } func TestHandleBlock(t *testing.T) { diff --git a/app/test_utils.go b/app/test_utils.go index 4a9b5c0..a4976c7 100644 --- a/app/test_utils.go +++ b/app/test_utils.go @@ -7,9 +7,9 @@ import ( "github.com/ubclaunchpad/cumulus/pool" ) -func createNewTestBlockRequest(lastBlock interface{}) *msg.Request { +func createNewTestBlockRequest(lastBlockHash interface{}) *msg.Request { params := make(map[string]interface{}, 1) - params["lastBlock"] = lastBlock + params["lastBlockHash"] = lastBlockHash return &msg.Request{ ResourceType: msg.ResourceBlock, Params: params, diff --git a/msg/message.go b/msg/message.go index 5cde787..5ffc150 100644 --- a/msg/message.go +++ b/msg/message.go @@ -33,16 +33,20 @@ const ( ) const ( - // BadRequest occurs when a malformatted request is received + // BadRequest occurs when a malformatted request is received. BadRequest = 400 // InvalidResourceType occurs when a request is received with an unknown // ResourceType value. InvalidResourceType = 401 + // ResourceNotFound occurs when a node reports the requested resource missing. + ResourceNotFound = 404 // RequestTimeout occurs when a peer does not respond to a request within // some predefined period of time (see peer.DefaultRequestTimeout) RequestTimeout = 408 - // ResourceNotFound occurs when a node reports the requested resource missing. - ResourceNotFound = 404 + // UpToDate occurs when a block request is received for a block that has + // not yet been mined (i.e. the lastBlockHash param in the request is the + // hash of the latest block in the blockchain). + UpToDate = 416 // NotImplemented occurs when a message or request is received whos response // requires functionality that does not yet exist. NotImplemented = 501 diff --git a/peer/peer.go b/peer/peer.go index 9c6563d..22b4006 100644 --- a/peer/peer.go +++ b/peer/peer.go @@ -142,7 +142,7 @@ func (p *Peer) Dispatch() { res := message.(*msg.Response) rh := p.getResponseHandler(res.ID) if rh == nil { - log.Error("Dispatcher could not find response handler for response on peer", + log.Errorf("Dispatcher could not find response handler for response on peer %s", p.ListenAddr) } else { rh(res)