Skip to content

Commit

Permalink
Refactor to enable tests to pass
Browse files Browse the repository at this point in the history
  • Loading branch information
vitsalis committed Sep 19, 2022
1 parent 47a0611 commit 6b56144
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 28 deletions.
33 changes: 22 additions & 11 deletions x/btclightclient/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ type msgServer struct {
k Keeper
}

const BTCDifficultyMultiplier = 5 // TODO: get from config file

func (m msgServer) InsertHeader(ctx context.Context, msg *types.MsgInsertHeader) (*types.MsgInsertHeaderResponse, error) {
func MsgInsertHeaderWrapped(ctx context.Context, k Keeper, msg *types.MsgInsertHeader,
powLimit big.Int, reduceMinDifficulty bool, retargetAdjustmentFactor int64, powCheck bool,
) (*types.MsgInsertHeaderResponse, error) {
// Perform the checks that checkBlockHeaderContext of btcd does
// https://github.com/btcsuite/btcd/blob/master/blockchain/validate.go#L644
// We skip the time, checkpoint, and version checks
Expand All @@ -38,7 +38,7 @@ func (m msgServer) InsertHeader(ctx context.Context, msg *types.MsgInsertHeader)

parentHash := msg.Header.ParentHash()
// Retrieve parent
parent, err := m.k.headersState(sdkCtx).GetHeaderByHash(parentHash)
parent, err := k.headersState(sdkCtx).GetHeaderByHash(parentHash)
// parent does not exist
if err != nil {
return nil, err
Expand Down Expand Up @@ -123,18 +123,22 @@ func (m msgServer) InsertHeader(ctx context.Context, msg *types.MsgInsertHeader)
does BTC mainnet work to add clutter on the BBN chain, then we can tolerate that.
*/

powLimit := bbn.GetGlobalPowLimit()
msgBlock := &wire.MsgBlock{Header: *(msg.Header.ToBlockHeader())}
block := btcutil.NewBlock(msgBlock)
blockchain.CheckProofOfWork(block, &powLimit)
if !bbn.GetGlobalReduceMinDifficulty() {
if powCheck {
msgBlock := &wire.MsgBlock{Header: *(msg.Header.ToBlockHeader())}
block := btcutil.NewBlock(msgBlock)
err = blockchain.CheckProofOfWork(block, &powLimit)
if err != nil {
return nil, err
}
}

if !reduceMinDifficulty {
// The new block will either be the first block of a recalculation event
// which happens every 2,016 blocks or a normal block.
// In the second case, it's difficulty should be exactly the same as it's parent
// while in the second case it should have a maximum difference of a factor of 4 from it
// See: https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch10.asciidoc#retargeting-to-adjust-difficulty
// We consolidate those into a single check.
retargetAdjustmentFactor := bbn.GetGlobalRetargetAdjustmentFactor()
oldDifficulty := blockchain.CompactToBig(parent.Header.Bits())
currentDifficulty := blockchain.CompactToBig(msg.Header.Bits())
maxCurrentDifficulty := new(big.Int).Mul(oldDifficulty, big.NewInt(retargetAdjustmentFactor))
Expand All @@ -145,13 +149,20 @@ func (m msgServer) InsertHeader(ctx context.Context, msg *types.MsgInsertHeader)
}

// All good, insert the header
err = m.k.InsertHeader(sdkCtx, msg.Header)
err = k.InsertHeader(sdkCtx, msg.Header)
if err != nil {
return nil, err
}
return &types.MsgInsertHeaderResponse{}, nil
}

func (m msgServer) InsertHeader(ctx context.Context, msg *types.MsgInsertHeader) (*types.MsgInsertHeaderResponse, error) {
powLimit := bbn.GetGlobalPowLimit()
reduceMinDifficulty := bbn.GetGlobalReduceMinDifficulty()
retargetAdjustmentFactor := bbn.GetGlobalRetargetAdjustmentFactor()
return MsgInsertHeaderWrapped(ctx, m.k, msg, powLimit, reduceMinDifficulty, retargetAdjustmentFactor, true)
}

// NewMsgServerImpl returns an implementation of the MsgServer interface
// for the provided Keeper.
func NewMsgServerImpl(keeper Keeper) types.MsgServer {
Expand Down
45 changes: 28 additions & 17 deletions x/btclightclient/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package keeper_test
import (
"context"
"github.com/babylonchain/babylon/testutil/datagen"
"github.com/btcsuite/btcd/chaincfg"
"math/big"
"math/rand"
"testing"
Expand Down Expand Up @@ -41,11 +42,17 @@ func FuzzMsgServerInsertHeader(f *testing.F) {
datagen.AddRandomSeedsToFuzzer(f, 100)
f.Fuzz(func(t *testing.T, seed int64) {
rand.Seed(seed)
msgServer, blcKeeper, sdkCtx := setupMsgServer(t)
_, blcKeeper, sdkCtx := setupMsgServer(t)

defaultParams := chaincfg.MainNetParams
powLimit := defaultParams.PowLimit
reduceMinDifficulty := defaultParams.ReduceMinDifficulty
retargetAdjustmentFactor := defaultParams.RetargetAdjustmentFactor

// If the input message is nil, (nil, error) is returned
var msg *types.MsgInsertHeader = nil
resp, err := msgServer.InsertHeader(sdkCtx, msg)
resp, err := keeper.MsgInsertHeaderWrapped(sdkCtx, *blcKeeper, msg, *powLimit, reduceMinDifficulty,
retargetAdjustmentFactor, false)
if resp != nil {
t.Errorf("Nil message returned a response")
}
Expand All @@ -55,7 +62,8 @@ func FuzzMsgServerInsertHeader(f *testing.F) {

// If the message does not contain a header, (nil, error) is returned.
msg = &types.MsgInsertHeader{}
resp, err = msgServer.InsertHeader(sdkCtx, msg)
resp, err = keeper.MsgInsertHeaderWrapped(sdkCtx, *blcKeeper, msg, *powLimit, reduceMinDifficulty,
retargetAdjustmentFactor, false)
if resp != nil {
t.Errorf("Message without a header returned a response")
}
Expand All @@ -66,7 +74,8 @@ func FuzzMsgServerInsertHeader(f *testing.F) {
// If the header has a parent that does not exist, (nil, error) is returned
headerParentNotExists := datagen.GenRandomBTCHeaderInfo().Header
msg = &types.MsgInsertHeader{Header: headerParentNotExists}
resp, err = msgServer.InsertHeader(sdkCtx, msg)
resp, err = keeper.MsgInsertHeaderWrapped(sdkCtx, *blcKeeper, msg, *powLimit, reduceMinDifficulty,
retargetAdjustmentFactor, false)
if resp != nil {
t.Errorf("Message with header with non-existent parent returned a response")
}
Expand All @@ -78,41 +87,43 @@ func FuzzMsgServerInsertHeader(f *testing.F) {
// Construct a tree and insert it into storage
tree := genRandomTree(blcKeeper, ctx, uint64(2), 10)
parentHeader := tree.RandomNode()
// Do not work with different cases. Select a random integer between 1-BTCDifficultyMultiplier+1
// 1/BTCDifficultyMultiplier times, the work is going to be invalid
// Do not work with different cases. Select a random integer between 1-retargetAdjustmentFactor+1
// 1/retargetAdjustmentFactor times, the work is going to be invalid
parentHeaderDifficulty := parentHeader.Header.Difficulty()
// Avoid BTCDifficultyMultiplier itself, since the many conversions might lead to inconsistencies
mul := datagen.RandomInt(keeper.BTCDifficultyMultiplier-1) + 1
// Avoid retargetAdjustmentFactor itself, since the many conversions might lead to inconsistencies
mul := datagen.RandomInt(int(retargetAdjustmentFactor-1)) + 1
if datagen.OneInN(10) { // Give an invalid mul sometimes
mul = keeper.BTCDifficultyMultiplier + 1
mul = uint64(retargetAdjustmentFactor + 1)
}
headerDifficultyMul := sdk.NewUintFromBigInt(new(big.Int).Mul(parentHeaderDifficulty, big.NewInt(int64(mul))))
headerDifficultyDiv := sdk.NewUintFromBigInt(new(big.Int).Div(parentHeaderDifficulty, big.NewInt(int64(mul))))

// Do tests
headerMoreWork := datagen.GenRandomBTCHeaderInfoWithParentAndBits(parentHeader, &headerDifficultyMul)
msg = &types.MsgInsertHeader{Header: headerMoreWork.Header}
resp, err = msgServer.InsertHeader(sdkCtx, msg)
if mul > keeper.BTCDifficultyMultiplier && resp != nil {
resp, err = keeper.MsgInsertHeaderWrapped(sdkCtx, *blcKeeper, msg, *powLimit, reduceMinDifficulty,
retargetAdjustmentFactor, false)
if mul > uint64(retargetAdjustmentFactor) && resp != nil {
t.Errorf("Invalid header work led to a response getting returned")
}
if mul > keeper.BTCDifficultyMultiplier && err == nil {
if mul > uint64(retargetAdjustmentFactor) && err == nil {
t.Errorf("Invalid header work did not lead to an error %d %s %s %s", mul, headerDifficultyMul, headerDifficultyDiv, parentHeaderDifficulty)
}
if mul <= keeper.BTCDifficultyMultiplier && err != nil {
if mul <= uint64(retargetAdjustmentFactor) && err != nil {
t.Errorf("Valid header work led to an error")
}

headerLessWork := datagen.GenRandomBTCHeaderInfoWithParentAndBits(parentHeader, &headerDifficultyDiv)
msg = &types.MsgInsertHeader{Header: headerLessWork.Header}
resp, err = msgServer.InsertHeader(sdkCtx, msg)
if mul > keeper.BTCDifficultyMultiplier && resp != nil {
resp, err = keeper.MsgInsertHeaderWrapped(sdkCtx, *blcKeeper, msg, *powLimit, reduceMinDifficulty,
retargetAdjustmentFactor, false)
if mul > uint64(retargetAdjustmentFactor) && resp != nil {
t.Errorf("Invalid header work led to a response getting returned")
}
if mul > keeper.BTCDifficultyMultiplier && err == nil {
if mul > uint64(retargetAdjustmentFactor) && err == nil {
t.Errorf("Invalid header work did not lead to an error")
}
if mul <= keeper.BTCDifficultyMultiplier && err != nil {
if mul <= uint64(retargetAdjustmentFactor) && err != nil {
t.Errorf("Valid header work led to an error %d %s", mul, err)
}
})
Expand Down

0 comments on commit 6b56144

Please sign in to comment.