Skip to content

Fix spine blocksmith process #587

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 12, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion common/schema
6 changes: 3 additions & 3 deletions core/service/blockSpinePublickeyService.go
Original file line number Diff line number Diff line change
@@ -67,14 +67,14 @@ func (bsf *BlockSpinePublicKeyService) BuildSpinePublicKeysFromNodeRegistry(
}
spinePublicKeys = make([]*model.SpinePublicKey, 0)
for _, nr := range nodeRegistrations {
bsfpk := &model.SpinePublicKey{
spinePublicKey := &model.SpinePublicKey{
NodePublicKey: nr.NodePublicKey,
PublicKeyAction: util.GetAddRemoveSpineKeyAction(nr.RegistrationStatus),
MainBlockHeight: nr.Height,
MainBlockHeight: nr.Height, // (node registration) transaction's height
Height: spineHeight,
Latest: true,
}
spinePublicKeys = append(spinePublicKeys, bsfpk)
spinePublicKeys = append(spinePublicKeys, spinePublicKey)
}
return spinePublicKeys, nil
}
27 changes: 26 additions & 1 deletion core/smith/strategy/blocksmithStrategySpine.go
Original file line number Diff line number Diff line change
@@ -25,19 +25,22 @@ type (
LastSortedBlockID int64
SortedBlocksmithsLock sync.RWMutex
SortedBlocksmithsMap map[string]*int64
SpineBlockQuery query.BlockQueryInterface
}
)

func NewBlocksmithStrategySpine(
queryExecutor query.ExecutorInterface,
spinePublicKeyQuery query.SpinePublicKeyQueryInterface,
logger *log.Logger,
spineBlockQuery query.BlockQueryInterface,
) *BlocksmithStrategySpine {
return &BlocksmithStrategySpine{
QueryExecutor: queryExecutor,
SpinePublicKeyQuery: spinePublicKeyQuery,
Logger: logger,
SortedBlocksmithsMap: make(map[string]*int64),
SpineBlockQuery: spineBlockQuery,
}
}

@@ -107,9 +110,31 @@ func (bss *BlocksmithStrategySpine) SortBlocksmiths(block *model.Block, withLock
if block.ID == bss.LastSortedBlockID && block.ID != constant.SpinechainGenesisBlockID {
return
}

var (
prevHeight = block.Height
prevBlock model.Block
err error
)

// always calculate sorted blocksmiths from previous block, otherwise when downloading the spine blocks it could happen
// that the node is unable to validate a block if it is smithed by a newly registered node that has his public key included in the same
// block the node is trying to validate (in that scenario the node's public key isn't in the db yet because the block hasn't been
// pushed yet)
if block.Height > 0 {
prevHeight = block.Height - 1
}
blockAtHeightQ := bss.SpineBlockQuery.GetBlockByHeight(prevHeight)
blockAtHeightRow, _ := bss.QueryExecutor.ExecuteSelectRow(blockAtHeightQ, false)
err = bss.SpineBlockQuery.Scan(&prevBlock, blockAtHeightRow)
if err != nil {
bss.Logger.Errorf("SortBlocksmith (Spine):GetBlockByHeight fail: %s", err)
return
}

// fetch valid blocksmiths
var blocksmiths []*model.Blocksmith
nextBlocksmiths, err := bss.GetBlocksmiths(block)
nextBlocksmiths, err := bss.GetBlocksmiths(&prevBlock)
if err != nil {
bss.Logger.Errorf("SortBlocksmith (Spine):GetBlocksmiths fail: %s", err)
return
86 changes: 84 additions & 2 deletions core/smith/strategy/blocksmithStrategySpine_test.go
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ import (
"database/sql"
"errors"
"fmt"
"github.com/zoobc/zoobc-core/common/chaintype"
"math/big"
"reflect"
"regexp"
@@ -40,6 +41,30 @@ func (*mockQueryGetBlocksmithsSpineFail) ExecuteSelect(
return nil, errors.New("mockError")
}

func (*mockQueryGetBlocksmithsSpineFail) ExecuteSelectRow(qStr string, tx bool, args ...interface{}) (*sql.Row, error) {
db, mock, _ := sqlmock.New()
defer db.Close()
mock.ExpectQuery(regexp.QuoteMeta(qStr)).
WillReturnRows(sqlmock.NewRows(query.NewBlockQuery(&chaintype.SpineChain{}).Fields).AddRow(
mockBlock.GetID(),
mockBlock.GetBlockHash(),
mockBlock.GetPreviousBlockHash(),
mockBlock.GetHeight(),
mockBlock.GetTimestamp(),
mockBlock.GetBlockSeed(),
mockBlock.GetBlockSignature(),
mockBlock.GetCumulativeDifficulty(),
mockBlock.GetPayloadLength(),
mockBlock.GetPayloadHash(),
mockBlock.GetBlocksmithPublicKey(),
mockBlock.GetTotalAmount(),
mockBlock.GetTotalFee(),
mockBlock.GetTotalCoinBase(),
mockBlock.GetVersion(),
))
return db.QueryRow(qStr), nil
}

func (*mockQueryGetBlocksmithsSpineSuccessWithBlocksmith) ExecuteSelect(
qStr string, tx bool, args ...interface{},
) (*sql.Rows, error) {
@@ -114,6 +139,30 @@ func (*mockQuerySortBlocksmithSpineSuccessWithBlocksmiths) ExecuteSelect(
return rows, nil
}

func (*mockQuerySortBlocksmithSpineSuccessWithBlocksmiths) ExecuteSelectRow(qStr string, tx bool, args ...interface{}) (*sql.Row, error) {
db, mock, _ := sqlmock.New()
defer db.Close()
mock.ExpectQuery(regexp.QuoteMeta(qStr)).
WillReturnRows(sqlmock.NewRows(query.NewBlockQuery(&chaintype.SpineChain{}).Fields).AddRow(
mockBlock.GetID(),
mockBlock.GetBlockHash(),
mockBlock.GetPreviousBlockHash(),
mockBlock.GetHeight(),
mockBlock.GetTimestamp(),
mockBlock.GetBlockSeed(),
mockBlock.GetBlockSignature(),
mockBlock.GetCumulativeDifficulty(),
mockBlock.GetPayloadLength(),
mockBlock.GetPayloadHash(),
mockBlock.GetBlocksmithPublicKey(),
mockBlock.GetTotalAmount(),
mockBlock.GetTotalFee(),
mockBlock.GetTotalCoinBase(),
mockBlock.GetVersion(),
))
return db.QueryRow(qStr), nil
}

func (*mockQueryGetBlocksmithsSpineSuccessNoBlocksmith) ExecuteSelect(
qStr string, tx bool, args ...interface{},
) (*sql.Rows, error) {
@@ -131,6 +180,30 @@ func (*mockQueryGetBlocksmithsSpineSuccessNoBlocksmith) ExecuteSelect(
return rows, nil
}

func (*mockQueryGetBlocksmithsSpineSuccessNoBlocksmith) ExecuteSelectRow(qStr string, tx bool, args ...interface{}) (*sql.Row, error) {
db, mock, _ := sqlmock.New()
defer db.Close()
mock.ExpectQuery(regexp.QuoteMeta(qStr)).
WillReturnRows(sqlmock.NewRows(query.NewBlockQuery(&chaintype.SpineChain{}).Fields).AddRow(
mockBlock.GetID(),
mockBlock.GetBlockHash(),
mockBlock.GetPreviousBlockHash(),
mockBlock.GetHeight(),
mockBlock.GetTimestamp(),
mockBlock.GetBlockSeed(),
mockBlock.GetBlockSignature(),
mockBlock.GetCumulativeDifficulty(),
mockBlock.GetPayloadLength(),
mockBlock.GetPayloadHash(),
mockBlock.GetBlocksmithPublicKey(),
mockBlock.GetTotalAmount(),
mockBlock.GetTotalFee(),
mockBlock.GetTotalCoinBase(),
mockBlock.GetVersion(),
))
return db.QueryRow(qStr), nil
}

func TestBlocksmithStrategySpine_GetSmithTime(t *testing.T) {
type fields struct {
QueryExecutor query.ExecutorInterface
@@ -300,6 +373,7 @@ func TestBlocksmithStrategySpine_SortBlocksmiths(t *testing.T) {
SortedBlocksmiths []*model.Blocksmith
LastSortedBlockID int64
SortedBlocksmithsMap map[string]*int64
SpineBlockQuery query.BlockQueryInterface
}
type args struct {
block *model.Block
@@ -318,6 +392,7 @@ func TestBlocksmithStrategySpine_SortBlocksmiths(t *testing.T) {
SortedBlocksmiths: nil,
SortedBlocksmithsMap: make(map[string]*int64),
LastSortedBlockID: 1,
SpineBlockQuery: query.NewBlockQuery(&chaintype.SpineChain{}),
},
args: args{
block: mockBlock,
@@ -332,6 +407,7 @@ func TestBlocksmithStrategySpine_SortBlocksmiths(t *testing.T) {
SortedBlocksmiths: nil,
SortedBlocksmithsMap: make(map[string]*int64),
LastSortedBlockID: 1,
SpineBlockQuery: query.NewBlockQuery(&chaintype.SpineChain{}),
},
args: args{mockBlock},
},
@@ -345,6 +421,7 @@ func TestBlocksmithStrategySpine_SortBlocksmiths(t *testing.T) {
SortedBlocksmiths: tt.fields.SortedBlocksmiths,
LastSortedBlockID: tt.fields.LastSortedBlockID,
SortedBlocksmithsMap: tt.fields.SortedBlocksmithsMap,
SpineBlockQuery: tt.fields.SpineBlockQuery,
}
bss.SortedBlocksmiths = make([]*model.Blocksmith, 0)
bss.SortBlocksmiths(tt.args.block, true)
@@ -371,6 +448,7 @@ func TestBlocksmithStrategySpine_GetSortedBlocksmithsMap(t *testing.T) {
LastSortedBlockID int64
SortedBlocksmithsLock sync.RWMutex
SortedBlocksmithsMap map[string]*int64
SpineBlockQuery query.BlockQueryInterface
}
type args struct {
block *model.Block
@@ -392,6 +470,7 @@ func TestBlocksmithStrategySpine_GetSortedBlocksmithsMap(t *testing.T) {
Logger: log.New(),
SortedBlocksmiths: bssMockBlocksmiths,
SortedBlocksmithsMap: mockBlocksmithMap,
SpineBlockQuery: query.NewBlockQuery(&chaintype.SpineChain{}),
},
want: mockBlocksmithMap,
},
@@ -406,6 +485,7 @@ func TestBlocksmithStrategySpine_GetSortedBlocksmithsMap(t *testing.T) {
Logger: log.New(),
SortedBlocksmiths: bssMockBlocksmiths,
SortedBlocksmithsMap: mockBlocksmithMap,
SpineBlockQuery: query.NewBlockQuery(&chaintype.SpineChain{}),
},
want: mockBlocksmithMap,
},
@@ -420,6 +500,7 @@ func TestBlocksmithStrategySpine_GetSortedBlocksmithsMap(t *testing.T) {
LastSortedBlockID: tt.fields.LastSortedBlockID,
SortedBlocksmithsLock: tt.fields.SortedBlocksmithsLock,
SortedBlocksmithsMap: tt.fields.SortedBlocksmithsMap,
SpineBlockQuery: tt.fields.SpineBlockQuery,
}
if got := bss.GetSortedBlocksmithsMap(tt.args.block); !reflect.DeepEqual(got, tt.want) {
t.Errorf("BlocksmithStrategySpine.GetSortedBlocksmithsMap() = %v, want %v", got, tt.want)
@@ -550,6 +631,7 @@ func TestNewBlocksmithStrategySpine(t *testing.T) {
queryExecutor query.ExecutorInterface
spinePublicKeyQuery query.SpinePublicKeyQueryInterface
logger *log.Logger
spineBlockQuery query.BlockQueryInterface
}
tests := []struct {
name string
@@ -561,13 +643,13 @@ func TestNewBlocksmithStrategySpine(t *testing.T) {
args: args{
logger: nil,
},
want: NewBlocksmithStrategySpine(nil, nil, nil),
want: NewBlocksmithStrategySpine(nil, nil, nil, nil),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := NewBlocksmithStrategySpine(tt.args.queryExecutor, tt.args.spinePublicKeyQuery,
tt.args.logger); !reflect.DeepEqual(got, tt.want) {
tt.args.logger, tt.args.spineBlockQuery); !reflect.DeepEqual(got, tt.want) {
t.Errorf("NewBlocksmithStrategySpine() = %v, want %v", got, tt.want)
}
})
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -525,6 +525,7 @@ func startSpinechain() {
queryExecutor,
query.NewSpinePublicKeyQuery(),
loggerCoreService,
query.NewBlockQuery(spinechain),
)
spinechainBlockService = service.NewBlockSpineService(
spinechain,