Skip to content

Commit

Permalink
Merge pull request #68 from bloXroute-Labs/v2.129.47
Browse files Browse the repository at this point in the history
Publish release v2.129.47
  • Loading branch information
bogdanprodanj authored Nov 15, 2024
2 parents 84fa50b + e95d75b commit 58aa7d4
Show file tree
Hide file tree
Showing 12 changed files with 174 additions and 36 deletions.
File renamed without changes.
File renamed without changes.
Empty file.
Empty file.
6 changes: 5 additions & 1 deletion connections/sdnhttp.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ import (

"github.com/bloXroute-Labs/gateway/v2/utils/syncmap"

"github.com/jinzhu/copier"

"github.com/bloXroute-Labs/gateway/v2"
log "github.com/bloXroute-Labs/gateway/v2/logger"
"github.com/bloXroute-Labs/gateway/v2/sdnmessage"
"github.com/bloXroute-Labs/gateway/v2/types"
"github.com/bloXroute-Labs/gateway/v2/utils"
"github.com/jinzhu/copier"
)

//go:generate mockgen -destination ../../bxgateway/test/mock/mock_sdnhttp.go -package mock . SDNHTTP
Expand All @@ -49,6 +50,7 @@ const (
potentialRelaysFileName = "potentialrelays.json"
accountModelsFileName = "accountmodel.json"
relayMapInterval = 2 * time.Minute
httpTimeout = 10 * time.Second
)

// SDNHTTP is the interface for realSDNHTTP type
Expand Down Expand Up @@ -451,7 +453,9 @@ func (s realSDNHTTP) httpClient() (*http.Client, error) {
Transport: &http.Transport{
TLSClientConfig: tlsConfig,
},
Timeout: httpTimeout,
}

return client, nil
}

Expand Down
57 changes: 37 additions & 20 deletions nodes/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,9 @@ type gateway struct {

staticEnodesCount int
startupArgs string
validatorStatusMap *syncmap.SyncMap[string, bool] // validator addr -> online/offline
validatorListMap *syncmap.SyncMap[uint64, []string] // block height -> list of validators
nextValidatorMap *orderedmap.OrderedMap[uint64, string] // next accessible validator
validatorStatusMap *syncmap.SyncMap[string, bool] // validator addr -> online/offline
validatorListMap *syncmap.SyncMap[uint64, validator.List] // block height -> list of validators with turn length
nextValidatorMap *orderedmap.OrderedMap[uint64, string] // next accessible validator
validatorListReady bool
validatorInfoUpdateLock sync.Mutex
latestValidatorInfo []*types.FutureValidatorInfo
Expand Down Expand Up @@ -240,7 +240,7 @@ func NewGateway(parent context.Context,
}

if bxConfig.BlockchainNetwork == bxgateway.BSCMainnet || bxConfig.BlockchainNetwork == bxgateway.BSCTestnet {
g.validatorListMap = syncmap.NewIntegerMapOf[uint64, []string]()
g.validatorListMap = syncmap.NewIntegerMapOf[uint64, validator.List]()
g.bscTxClient = &http.Client{
Transport: &http.Transport{
MaxConnsPerHost: 100,
Expand Down Expand Up @@ -739,9 +739,12 @@ func (g *gateway) queryEpochBlock(height uint64) error {

g.validatorListMap.Delete(height - bscBlocksPerEpoch*2) // remove the validator list that doesn't need anymore
g.validatorListMap.Store(height, validatorList)

return nil
}
}
}

return errors.New("failed to query blockchain node for previous epoch block")
}

Expand Down Expand Up @@ -780,7 +783,7 @@ func (g *gateway) generateBSCValidator(blockHeight uint64) []*types.FutureValida
}
previousEpochValidatorList := prevEpochValidatorList

var currentEpochValidatorList []string
var currentEpochValidatorList validator.List
currEpochValidatorList, exist := g.validatorListMap.Load(currentEpochBlockHeight)
if !exist {
err := g.queryEpochBlock(currentEpochBlockHeight)
Expand All @@ -798,25 +801,24 @@ func (g *gateway) generateBSCValidator(blockHeight uint64) []*types.FutureValida

for i := 1; i <= 2; i++ {
targetingBlockHeight := blockHeight + uint64(i)
listIndex := targetingBlockHeight % uint64(len(currentEpochValidatorList)) // listIndex is the index for the validator list
activationIndex := uint64((len(previousEpochValidatorList) + 1) / 2) // activationIndex = ceiling[ N / 2 ] where N = the length of previous validator list, it marks a watershed. To the leftward we use previous validator list, to the rightward(inclusive) we use current validator list. Reference: https://github.com/bnb-chain/docs-site/blob/master/docs/smart-chain/guides/concepts/consensus.md

// see formula here https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-341.md#421-priority-allocation
listIndex := targetingBlockHeight / uint64(currentEpochValidatorList.TurnLength) % uint64(len(currentEpochValidatorList.Validators))

// see formula here https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-341.md#422-validator-set-switch
activationIndex := uint64(len(previousEpochValidatorList.Validators)/2+1)*uint64(currentEpochValidatorList.TurnLength) - 1

index := targetingBlockHeight - currentEpochBlockHeight
if index >= activationIndex {
validatorAddr := currentEpochValidatorList[listIndex]
validatorAddr := currentEpochValidatorList.Validators[listIndex]
vi[i-1].WalletID = strings.ToLower(validatorAddr)
} else { // use list from previous epoch
validatorAddr := previousEpochValidatorList[listIndex]
validatorAddr := previousEpochValidatorList.Validators[listIndex]
vi[i-1].WalletID = strings.ToLower(validatorAddr)
}

g.nextValidatorMap.Set(targetingBlockHeight, strings.ToLower(vi[i-1].WalletID)) // nextValidatorMap is simulating a queue with height as expiration key. Regardless of the accessible status, next walletID will be appended to the queue

// Deprecated
// accessible, exist := g.validatorStatusMap.Load(strings.ToLower(vi[i-1].WalletID))
// if exist {
// vi[i-1].Accessible = accessible
// }

vi[i-1].Accessible = true
}

Expand Down Expand Up @@ -892,7 +894,7 @@ func (g *gateway) generatePolygonValidator(bxBlock *types.BxBlock, blockInfo *et
return validatorInfo[:]
}

func bscExtractValidatorListFromBlock(b []byte) ([]string, error) {
func bscExtractValidatorListFromBlock(b []byte) (validator.List, error) {
addressLength := 20
bLSPublicKeyLength := 48

Expand All @@ -905,7 +907,7 @@ func bscExtractValidatorListFromBlock(b []byte) ([]string, error) {

// 32 + 65 + 1
if len(b) < 98 {
return nil, errors.New("wrong extra data, too small")
return validator.List{}, errors.New("wrong extra data, too small")
}

data := b[extraVanityLength : len(b)-extraSealLength]
Expand All @@ -918,7 +920,7 @@ func bscExtractValidatorListFromBlock(b []byte) ([]string, error) {
validatorNum := int(data[0])
validatorBytesTotalLength := validatorNumberSize + validatorNum*validatorBytesLength
if dataLength < validatorBytesTotalLength {
return nil, fmt.Errorf("parse validators failed, validator list is not aligned")
return validator.List{}, fmt.Errorf("parse validators failed, validator list is not aligned")
}

validatorList := make([]string, 0, validatorNum)
Expand All @@ -928,18 +930,33 @@ func bscExtractValidatorListFromBlock(b []byte) ([]string, error) {
validatorList = append(validatorList, validatorAddr.String())
}

return validatorList, nil
data = data[validatorBytesTotalLength-validatorNumberSize:]
dataLength = len(data)

turnLength := uint8(1)
// parse TurnLength
if dataLength > 0 {
if data[0] != '\xf8' {
turnLength = data[0]
}
}

return validator.List{
Validators: validatorList,
TurnLength: turnLength,
}, nil
}
}

return nil, nil
return validator.List{}, nil
}

func (g *gateway) generateFutureValidatorInfo(block *types.BxBlock, blockInfo *eth.BlockInfo) []*types.FutureValidatorInfo {
g.validatorInfoUpdateLock.Lock()
defer g.validatorInfoUpdateLock.Unlock()

blockHeight := uint64(block.Number.Int64())

switch g.sdn.NetworkNum() {
case bxgateway.BSCMainnetNum, bxgateway.BSCTestnetNum:
if blockHeight%bscBlocksPerEpoch == 0 {
Expand Down
31 changes: 31 additions & 0 deletions nodes/gateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"time"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -1369,6 +1370,36 @@ func TestGateway_SendStatsOnInterval(t *testing.T) {
}
}

func TestValidatorsList(t *testing.T) {
t.Run("with turn length", func(t *testing.T) {
// |---Extra Vanity---|---Validators Number and Validators Bytes---|---Turn Length---|---Empty---|---Extra Seal---|
extraData := "0xd983010209846765746889676f312e31392e3131856c696e75780000a6bf97c1152465176c461afb316ebc773c61faee85a6515daa8a923564c6ffd37fb2fe9f118ef88092e8762c7addb526ab7eb1e772baef85181f892c731be0c1891a50e6b06262c816295e26495cef6f69dfa69911d9d8e4f3bbadb89b977cf58294f7239d515e15b24cfeb82494056cf691eaf729b165f32c9757c429dba5051155903067e56ebe3698678e912d4c407bbe49438ed859fe965b140dcf1aab71a993c1f7f6929d1fe2a17b4e14614ef9fc5bdc713d6631d675403fbeefac55611bf612700b1b65f4744861b80b0f7d6ab03f349bbafec1551819b8be1efea2fc46ca749aa184248a459464eec1a21e7fc7b71a053d9644e9bb8da4853b8f872cd7c1d6b324bf1922829830646ceadfb658d3de009a61dd481a114a2e761c554b641742c973867899d300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000069c77a677c40c7fbea129d4b171a39b7a8ddabfab2317f59d86abfaf690850223d90e9e7593d91a29331dfc2f84d5adecc75fc39ecab4632c1b4400a3dd1e1298835bcca70f657164e5b75689b64b7fd1fa275f334f28e1896a26afa1295da81418593bd12814463d9f6e45c36a0e47eb4cd3e5b6af29c41e2a3a5636430155a466e216585af3ba772b61c6014342d914470ec7ac2975be345796c2b81db0422a5fd08e40db1fc2368d2245e4b18b1d0b85c921aaaafd2e341760e29fc613edd39f71254614e2055c3287a517ae2f5b9e386cd1b50a4550696d957cb4900f03ab84f83ff2df44193496793b847f64e9d6db1b3953682bb95edd096eb1e69bbd357c200992ca78050d0cbe180cfaa018e8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a8a257074e82b881cfa06ef3eb4efeca060c2531359abd0eab8af1e3edfa2025fca464ac9c3fd123f6c24a0d78869485a6f79b60359f141df90a0c745125b131caaffd12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b218c5d6af1f979ac42bc68d98a5a0d796c6ab01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b4dd66d7c2c7e57f628210187192fb89d4b99dd4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000be807dddb074639cd9fa61b47676c064fc50d62cb1f2c71577def3144fabeb75a8a1c8cb5b51d1d1b4a05eec67988b8685008baa17459ec425dbaebc852f496dc92196cdcc8e6d00c17eb431350c6c50d8b8f05176b90b11b3a3d4feb825ae9702711566df5dbf38e82add4dd1b573b95d2466fa6501ccb81e9d26a352b96150ccbf7b697fd0a419d1d6bf74282782b0b3eb1413c901d6ecf02e8e28000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e2d3a739effcd3a99387d015e260eefac72ebea1956c470ddff48cb49300200b5f83497f3a3ccb3aeb83c5edd9818569038e61d197184f4aa6939ea5e9911e3e98ac6d21e9ae3261a475a27bb1028f140bc2a7c843318afd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ea0a6e3c511bbd10f4519ece37dc24887e11b55db2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c192183ee226379db83cffc681495730c11fdde79ba4c0c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ef0274e31810c9df02f98fafde0f841f4e66a1cd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004e99f701bb14cb7dfb68b90bd3e6d1ca656964630de71beffc7f33f7f08ec99d336ec51ad9fad0ac84ae77ca2e8ad9512acc56e0d7c93f3c2ce7de1b69149a5a400"

data, err := hexutil.Decode(extraData)
require.NoError(t, err)

validatorList, err := bscExtractValidatorListFromBlock(data)
require.NoError(t, err)

require.Equal(t, 21, len(validatorList.Validators))
require.Equal(t, uint8(4), validatorList.TurnLength)
})

t.Run("without turn length", func(t *testing.T) {
// |---Extra Vanity---|---Validators Number and Validators Bytes---|---Empty---|---Extra Seal---|
extraData := "0xd983010209846765746889676f312e31392e3131856c696e75780000a6bf97c1152465176c461afb316ebc773c61faee85a6515daa8a923564c6ffd37fb2fe9f118ef88092e8762c7addb526ab7eb1e772baef85181f892c731be0c1891a50e6b06262c816295e26495cef6f69dfa69911d9d8e4f3bbadb89b977cf58294f7239d515e15b24cfeb82494056cf691eaf729b165f32c9757c429dba5051155903067e56ebe3698678e912d4c407bbe49438ed859fe965b140dcf1aab71a993c1f7f6929d1fe2a17b4e14614ef9fc5bdc713d6631d675403fbeefac55611bf612700b1b65f4744861b80b0f7d6ab03f349bbafec1551819b8be1efea2fc46ca749aa184248a459464eec1a21e7fc7b71a053d9644e9bb8da4853b8f872cd7c1d6b324bf1922829830646ceadfb658d3de009a61dd481a114a2e761c554b641742c973867899d300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000069c77a677c40c7fbea129d4b171a39b7a8ddabfab2317f59d86abfaf690850223d90e9e7593d91a29331dfc2f84d5adecc75fc39ecab4632c1b4400a3dd1e1298835bcca70f657164e5b75689b64b7fd1fa275f334f28e1896a26afa1295da81418593bd12814463d9f6e45c36a0e47eb4cd3e5b6af29c41e2a3a5636430155a466e216585af3ba772b61c6014342d914470ec7ac2975be345796c2b81db0422a5fd08e40db1fc2368d2245e4b18b1d0b85c921aaaafd2e341760e29fc613edd39f71254614e2055c3287a517ae2f5b9e386cd1b50a4550696d957cb4900f03ab84f83ff2df44193496793b847f64e9d6db1b3953682bb95edd096eb1e69bbd357c200992ca78050d0cbe180cfaa018e8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a8a257074e82b881cfa06ef3eb4efeca060c2531359abd0eab8af1e3edfa2025fca464ac9c3fd123f6c24a0d78869485a6f79b60359f141df90a0c745125b131caaffd12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b218c5d6af1f979ac42bc68d98a5a0d796c6ab01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b4dd66d7c2c7e57f628210187192fb89d4b99dd4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000be807dddb074639cd9fa61b47676c064fc50d62cb1f2c71577def3144fabeb75a8a1c8cb5b51d1d1b4a05eec67988b8685008baa17459ec425dbaebc852f496dc92196cdcc8e6d00c17eb431350c6c50d8b8f05176b90b11b3a3d4feb825ae9702711566df5dbf38e82add4dd1b573b95d2466fa6501ccb81e9d26a352b96150ccbf7b697fd0a419d1d6bf74282782b0b3eb1413c901d6ecf02e8e28000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e2d3a739effcd3a99387d015e260eefac72ebea1956c470ddff48cb49300200b5f83497f3a3ccb3aeb83c5edd9818569038e61d197184f4aa6939ea5e9911e3e98ac6d21e9ae3261a475a27bb1028f140bc2a7c843318afd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ea0a6e3c511bbd10f4519ece37dc24887e11b55db2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c192183ee226379db83cffc681495730c11fdde79ba4c0c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ef0274e31810c9df02f98fafde0f841f4e66a1cd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e99f701bb14cb7dfb68b90bd3e6d1ca656964630de71beffc7f33f7f08ec99d336ec51ad9fad0ac84ae77ca2e8ad9512acc56e0d7c93f3c2ce7de1b69149a5a400"

data, err := hexutil.Decode(extraData)
require.NoError(t, err)

validatorList, err := bscExtractValidatorListFromBlock(data)
require.NoError(t, err)

require.Equal(t, 21, len(validatorList.Validators))
require.Equal(t, uint8(1), validatorList.TurnLength)
})
}

func expectNoFeedNotification(t *testing.T, bridge blockchain.Bridge, feedsChan <-chan types.Notification, g *gateway, isBDNBlock bool, blockHeight int, expectedBestBlockHeight int, expectedSkipBlockCount int) {
ethBlock := bxmock.NewEthBlock(uint64(blockHeight), common.Hash{})
bxBlock, _ := bridge.BlockBlockchainToBDN(eth.NewBlockInfo(ethBlock, nil))
Expand Down
2 changes: 1 addition & 1 deletion servers/ws/ws_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ func (s *wsSuite) setupSuit(networkNum types.NetworkNum) {
if networkNum == bxgateway.BSCMainnetNum || networkNum == bxgateway.PolygonMainnetNum {
nextValidatorMap := orderedmap.New[uint64, string]()
validatorStatusMap := syncmap.NewStringMapOf[bool]()
validatorListMap := syncmap.NewIntegerMapOf[uint64, []string]()
validatorListMap := syncmap.NewIntegerMapOf[uint64, validator.List]()

nextValidatorMap.Set(uint64(100), "1234")

Expand Down
3 changes: 2 additions & 1 deletion services/account/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ var (
ErrInvalidHeader = errors.New("wrong value in the authorization header")
)

// Accounter declares the interface of the account service
// Accounter declares the interface of the account service
type Accounter interface {
Authorize(accountID types.AccountID, secretHash string, isWebsocket bool, allowIntroductoryTierAccess bool, remoteAddr string) (sdnmessage.Account, error)
}
Expand Down Expand Up @@ -84,6 +84,7 @@ func (g *Service) Authorize(accountID types.AccountID, secretHash string, allowA
l.Errorf("account %v is not authorized to call this method directly", g.sdn.AccountModel().AccountID)
return connectionAccountModel, ErrMethodNotAllowed
}

accountRes, err := g.cacheMap.Get(accountID)
switch {
case err != nil:
Expand Down
10 changes: 8 additions & 2 deletions services/validator/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,17 @@ import (
type Manager struct {
nextValidatorMap *orderedmap.OrderedMap[uint64, string]
validatorStatusMap *syncmap.SyncMap[string, bool]
validatorListMap *syncmap.SyncMap[uint64, []string]
validatorListMap *syncmap.SyncMap[uint64, List]
pendingBSCNextValidatorTxHashToInfo map[string]PendingNextValidatorTxInfo
lock sync.Mutex
}

// List holds a list of validators and turn length
type List struct {
Validators []string
TurnLength uint8
}

// PendingNextValidatorTxInfo holds info needed to reevaluate next validator tx when next block published
type PendingNextValidatorTxInfo struct {
Tx *bxmessage.Tx
Expand All @@ -32,7 +38,7 @@ type PendingNextValidatorTxInfo struct {
}

// NewManager creates a new Manager
func NewManager(nextValidatorMap *orderedmap.OrderedMap[uint64, string], validatorStatusMap *syncmap.SyncMap[string, bool], validatorListMap *syncmap.SyncMap[uint64, []string]) *Manager {
func NewManager(nextValidatorMap *orderedmap.OrderedMap[uint64, string], validatorStatusMap *syncmap.SyncMap[string, bool], validatorListMap *syncmap.SyncMap[uint64, List]) *Manager {
return &Manager{
nextValidatorMap: nextValidatorMap,
validatorStatusMap: validatorStatusMap,
Expand Down
Loading

0 comments on commit 58aa7d4

Please sign in to comment.