Skip to content

Commit

Permalink
fix(node): requesting last blocks corrupts the blockchain (#192)
Browse files Browse the repository at this point in the history
  • Loading branch information
JeremyPansier authored Jan 31, 2023
1 parent f7d0ce3 commit f5e8f49
Show file tree
Hide file tree
Showing 7 changed files with 212 additions and 244 deletions.
2 changes: 1 addition & 1 deletion src/node/network/last_bocks_request.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package network

type LastBlocksRequest struct {
StartingBlockHash *[32]byte
StartingBlockNonce *int
}
2 changes: 1 addition & 1 deletion src/node/network/p2p/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func (host *Host) handle(_ context.Context, req gp2p.Data) (res gp2p.Data, err e
}

func (host *Host) getLastBlocks(request *network.LastBlocksRequest) (res gp2p.Data) {
blockResponses := host.blockchain.LastBlocks(*request.StartingBlockHash)
blockResponses := host.blockchain.LastBlocks(*request.StartingBlockNonce)
err := res.SetGob(blockResponses)
if err != nil {
host.logger.Error(fmt.Errorf("failed to get blocks: %w", err).Error())
Expand Down
3 changes: 1 addition & 2 deletions src/node/protocol/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,5 @@ type Blockchain interface {
Blocks() []*network.BlockResponse
CalculateTotalAmount(currentTimestamp int64, blockchainAddress string) uint64
Copy() Blockchain
LastBlocks(startingBlockHash [32]byte) []*network.BlockResponse
Update(timestamp int64)
LastBlocks(startingBlockNonce int) []*network.BlockResponse
}
323 changes: 169 additions & 154 deletions src/node/protocol/verification/blockchain.go

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion test/node/network/p2p/host_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ func Test_Run_NoError_ServerStarted(t *testing.T) {
serverMock.SetHandleFunc = func(topic string, handler gp2p.Handler) {}
synchronizerMock := new(networktest.SynchronizerMock)
blockchainMock := new(protocoltest.BlockchainMock)
blockchainMock.UpdateFunc = func(int64) {}
transactionsPoolMock := new(protocoltest.TransactionsPoolMock)
engineMock := new(clocktest.EngineMock)
engineMock.StartFunc = func() {}
Expand Down
64 changes: 10 additions & 54 deletions test/node/protocol/protocoltest/blockchain_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

61 changes: 30 additions & 31 deletions test/node/protocol/verification/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@ import (
"github.com/my-cloud/ruthenium/src/ui/server"
"github.com/my-cloud/ruthenium/test"
"github.com/my-cloud/ruthenium/test/log/logtest"
"github.com/my-cloud/ruthenium/test/node/clock/clocktest"
"github.com/my-cloud/ruthenium/test/node/network/networktest"
"github.com/my-cloud/ruthenium/test/node/protocol/protocoltest"
"strings"
"testing"
"time"
)

const (
Expand Down Expand Up @@ -71,17 +69,8 @@ func Test_Update_NeighborBlockchainIsBetter_IsReplaced(t *testing.T) {
// Arrange
registry := new(protocoltest.RegistryMock)
registry.IsRegisteredFunc = func(address string) (bool, error) { return true, nil }
watchMock := new(clocktest.WatchMock)
watchMock.NowFunc = func() time.Time { return time.Unix(0, 1) }
logger := logtest.NewLoggerMock()
neighborMock := new(networktest.NeighborMock)
neighborMock.GetBlocksFunc = func() ([]*network.BlockResponse, error) {
blockResponse1 := protocoltest.NewRewardedBlockResponse([32]byte{}, 0)
block1, _ := verification.NewBlockFromResponse(blockResponse1)
hash, _ := block1.Hash()
blockResponse2 := protocoltest.NewRewardedBlockResponse(hash, 1)
return []*network.BlockResponse{blockResponse1, blockResponse2}, nil
}
neighborMock.TargetFunc = func() string {
return "neighbor"
}
Expand All @@ -91,9 +80,26 @@ func Test_Update_NeighborBlockchainIsBetter_IsReplaced(t *testing.T) {
}
genesisTransaction := validation.NewRewardTransaction("", 0, 0)
blockchain := verification.NewBlockchain(genesisTransaction, 0, registry, 1, synchronizer, logger)
blockchain.AddBlock(1, nil, nil)
blockchain.AddBlock(2, nil, nil)
blockchain.AddBlock(3, nil, nil)
blockchain.AddBlock(4, nil, nil)
neighborMock.GetLastBlocksFunc = func(network.LastBlocksRequest) ([]*network.BlockResponse, error) {
blockResponse1 := protocoltest.NewRewardedBlockResponse(blockchain.LastBlocks(2)[0].PreviousHash, 2)
block1, _ := verification.NewBlockFromResponse(blockResponse1)
hash1, _ := block1.Hash()
blockResponse2 := protocoltest.NewRewardedBlockResponse(hash1, 3)
block2, _ := verification.NewBlockFromResponse(blockResponse2)
hash2, _ := block2.Hash()
blockResponse3 := protocoltest.NewRewardedBlockResponse(hash2, 4)
block3, _ := verification.NewBlockFromResponse(blockResponse3)
hash3, _ := block3.Hash()
blockResponse4 := protocoltest.NewRewardedBlockResponse(hash3, 5)
return []*network.BlockResponse{blockResponse1, blockResponse2, blockResponse3, blockResponse4}, nil
}

// Act
blockchain.Update(watchMock.Now().UnixNano())
blockchain.Update(5)

// Assert
var isReplaced bool
Expand All @@ -109,8 +115,6 @@ func Test_Update_NeighborNewBlockTimestampIsInvalid_IsNotReplaced(t *testing.T)
// Arrange
registry := new(protocoltest.RegistryMock)
registry.IsRegisteredFunc = func(address string) (bool, error) { return true, nil }
watchMock := new(clocktest.WatchMock)
watchMock.NowFunc = func() time.Time { return time.Unix(0, 2) }
logger := logtest.NewLoggerMock()
neighborMock := new(networktest.NeighborMock)
neighborMock.TargetFunc = func() string {
Expand Down Expand Up @@ -172,7 +176,7 @@ func Test_Update_NeighborNewBlockTimestampIsInvalid_IsNotReplaced(t *testing.T)
}

// Act
blockchain.Update(watchMock.Now().UnixNano())
blockchain.Update(1)

// Assert
var isKept bool
Expand All @@ -195,8 +199,6 @@ func Test_Update_NeighborNewBlockTimestampIsInTheFuture_IsNotReplaced(t *testing
// Arrange
registry := new(protocoltest.RegistryMock)
registry.IsRegisteredFunc = func(address string) (bool, error) { return true, nil }
watchMock := new(clocktest.WatchMock)
watchMock.NowFunc = func() time.Time { return time.Unix(0, 1) }
logger := logtest.NewLoggerMock()
neighborMock := new(networktest.NeighborMock)
neighborMock.GetBlocksFunc = func() ([]*network.BlockResponse, error) {
Expand All @@ -217,7 +219,7 @@ func Test_Update_NeighborNewBlockTimestampIsInTheFuture_IsNotReplaced(t *testing
blockchain := verification.NewBlockchain(genesisTransaction, 0, registry, 1, synchronizer, logger)

// Act
blockchain.Update(watchMock.Now().UnixNano())
blockchain.Update(1)

// Assert
var isKept bool
Expand All @@ -238,8 +240,6 @@ func Test_Update_NeighborNewBlockTransactionFeeIsTooLow_IsNotReplaced(t *testing
// Arrange
registry := new(protocoltest.RegistryMock)
registry.IsRegisteredFunc = func(address string) (bool, error) { return true, nil }
watchMock := new(clocktest.WatchMock)
watchMock.NowFunc = func() time.Time { return time.Unix(0, 1) }
logger := logtest.NewLoggerMock()
neighborMock := new(networktest.NeighborMock)
wallet, _ := encryption.DecodeWallet(test.Mnemonic1, test.DerivationPath, "", "")
Expand Down Expand Up @@ -276,7 +276,7 @@ func Test_Update_NeighborNewBlockTransactionFeeIsTooLow_IsNotReplaced(t *testing
blockchain := verification.NewBlockchain(genesisTransaction, minimalTransactionFee, registry, 1, synchronizer, logger)

// Act
blockchain.Update(watchMock.Now().UnixNano())
blockchain.Update(1)

// Assert
var isKept bool
Expand All @@ -297,8 +297,6 @@ func Test_Update_NeighborNewBlockTransactionTimestampIsTooFarInTheFuture_IsNotRe
// Arrange
registry := new(protocoltest.RegistryMock)
registry.IsRegisteredFunc = func(address string) (bool, error) { return true, nil }
watchMock := new(clocktest.WatchMock)
watchMock.NowFunc = func() time.Time { return time.Unix(0, 1) }
logger := logtest.NewLoggerMock()
neighborMock := new(networktest.NeighborMock)
wallet, _ := encryption.DecodeWallet(test.Mnemonic1, test.DerivationPath, "", "")
Expand Down Expand Up @@ -334,7 +332,7 @@ func Test_Update_NeighborNewBlockTransactionTimestampIsTooFarInTheFuture_IsNotRe
blockchain := verification.NewBlockchain(genesisTransaction, transactionFee, registry, 1, synchronizer, logger)

// Act
blockchain.Update(watchMock.Now().UnixNano())
blockchain.Update(1)

// Assert
var isKept bool
Expand All @@ -355,8 +353,6 @@ func Test_Update_NeighborNewBlockTransactionTimestampIsTooOld_IsNotReplaced(t *t
// Arrange
registry := new(protocoltest.RegistryMock)
registry.IsRegisteredFunc = func(address string) (bool, error) { return true, nil }
watchMock := new(clocktest.WatchMock)
watchMock.NowFunc = func() time.Time { return time.Unix(0, 2) }
logger := logtest.NewLoggerMock()
neighborMock := new(networktest.NeighborMock)
wallet, _ := encryption.DecodeWallet(test.Mnemonic1, test.DerivationPath, "", "")
Expand All @@ -371,15 +367,18 @@ func Test_Update_NeighborNewBlockTransactionTimestampIsTooOld_IsNotReplaced(t *t
blockResponse1 := protocoltest.NewGenesisBlockResponse(address)
block1, _ := verification.NewBlockFromResponse(blockResponse1)
hash1, _ := block1.Hash()
var block2Timestamp int64 = 1
blockResponse2 := protocoltest.NewRewardedBlockResponse(hash1, 1)
block2, _ := verification.NewBlockFromResponse(blockResponse2)
hash2, _ := block2.Hash()
var block3Timestamp int64 = 2
transactions := []*network.TransactionResponse{
transactionResponse,
validation.NewRewardTransaction(address, block2Timestamp, 0),
validation.NewRewardTransaction(address, block3Timestamp, 0),
}
var registeredAddresses []string
registeredAddresses = append(registeredAddresses, address)
blockResponse2 := verification.NewBlockResponse(block2Timestamp, hash1, transactions, registeredAddresses)
return []*network.BlockResponse{blockResponse1, blockResponse2}, nil
blockResponse3 := verification.NewBlockResponse(block3Timestamp, hash2, transactions, registeredAddresses)
return []*network.BlockResponse{blockResponse1, blockResponse2, blockResponse3}, nil
}
neighborMock.TargetFunc = func() string {
return "neighbor"
Expand All @@ -392,7 +391,7 @@ func Test_Update_NeighborNewBlockTransactionTimestampIsTooOld_IsNotReplaced(t *t
blockchain := verification.NewBlockchain(genesisTransaction, transactionFee, registry, 1, synchronizer, logger)

// Act
blockchain.Update(watchMock.Now().UnixNano())
blockchain.Update(2)

// Assert
var isKept bool
Expand Down

0 comments on commit f5e8f49

Please sign in to comment.