fix merge conflict

feature/dev-engine_test
static 1 year ago
commit 1b3b181b09
  1. 5
      Makefile
  2. 2
      README.md
  3. 14
      api/service/legacysync/epoch_syncing.go
  4. 5
      api/service/stagedstreamsync/beacon_helper.go
  5. 9
      api/service/stagedstreamsync/sig_verify.go
  6. 20
      api/service/stagedstreamsync/stage_epoch.go
  7. 8
      api/service/stagedstreamsync/staged_stream_sync.go
  8. 2
      api/service/stagedsync/stage_state.go
  9. 7
      api/service/stagedsync/stagedsync.go
  10. 6
      consensus/consensus_v2.go
  11. 3
      consensus/downloader.go
  12. 8
      consensus/engine/consensus_engine.go
  13. 5
      core/blockchain.go
  14. 7
      core/blockchain_impl.go
  15. 9
      core/blockchain_stub.go
  16. 68
      go.mod
  17. 121
      go.sum
  18. 4
      hmy/downloader/adapter_test.go
  19. 212
      internal/chain/engine_test.go
  20. 43
      internal/utils/blockedpeers/manager.go
  21. 27
      internal/utils/blockedpeers/manager_test.go
  22. 18
      internal/utils/lrucache/lrucache.go
  23. 28
      internal/utils/lrucache/lrucache_test.go
  24. 10
      node/node.go
  25. 2
      node/node_explorer.go
  26. 3
      node/node_handler.go
  27. 24
      p2p/host.go
  28. 107
      p2p/security/security.go
  29. 29
      p2p/security/security_test.go
  30. 295
      p2p/stream/protocols/sync/chain.go
  31. 174
      p2p/stream/protocols/sync/chain_test.go
  32. 417
      p2p/stream/protocols/sync/client.go
  33. 326
      p2p/stream/protocols/sync/client_test.go
  34. 33
      p2p/stream/protocols/sync/const.go
  35. 128
      p2p/stream/protocols/sync/message/compose.go
  36. 1802
      p2p/stream/protocols/sync/message/msg.pb.go
  37. 70
      p2p/stream/protocols/sync/message/msg.proto
  38. 64
      p2p/stream/protocols/sync/message/parse.go
  39. 170
      p2p/stream/protocols/sync/stream.go
  40. 108
      p2p/stream/protocols/sync/stream_test.go
  41. 15
      shard/committee/assignment.go
  42. 6
      test/chain/chain/chain_makers.go

@ -179,4 +179,7 @@ debug_external: clean
bash test/debug-external.sh
build_localnet_validator:
bash test/build-localnet-validator.sh
bash test/build-localnet-validator.sh
tt:
go test -v -test.run OnDisconnectCheck ./p2p/security

@ -150,7 +150,7 @@ make debug-kill
To keep things consistent, we have a docker image to run all tests. **These are the same tests ran on the pull request checks**.
Note that all testing docker container binds a couple of ports to the host machine for your convince. The ports are:
Note that all test Docker containers bind several ports to the host machine for your convenience. The ports are:
* `9500` - Shard 0 RPC for a validator
* `9501` - Shard 1 RPC for a validator
* `9599` - Shard 0 RPC for an explorer

@ -199,8 +199,18 @@ func processWithPayload(payload [][]byte, bc core.BlockChain) error {
decoded = append(decoded, block)
}
_, err := bc.InsertChain(decoded, true)
return err
for _, block := range decoded {
_, err := bc.InsertChain([]*types.Block{block}, true)
switch {
case errors.Is(err, core.ErrKnownBlock):
continue
case err != nil:
return err
default:
}
}
return nil
}
// CreateSyncConfig creates SyncConfig for StateSync object.

@ -1,8 +1,10 @@
package stagedstreamsync
import (
"errors"
"time"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/internal/utils"
"github.com/rs/zerolog"
@ -126,7 +128,8 @@ func (bh *beaconHelper) insertLastMileBlocks() (inserted int, bn uint64, err err
}
// TODO: Instruct the beacon helper to verify signatures. This may require some forks
// in pub-sub message (add commit sigs in node.block.sync messages)
if _, err = bh.bc.InsertChain(types.Blocks{b}, true); err != nil {
_, err = bh.bc.InsertChain(types.Blocks{b}, true)
if err != nil && !errors.Is(err, core.ErrKnownBlock) {
bn--
return
}

@ -3,6 +3,7 @@ package stagedstreamsync
import (
"fmt"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/internal/chain"
@ -53,8 +54,14 @@ func verifyAndInsertBlock(bc blockChain, block *types.Block, nextBlocks ...*type
if err := bc.Engine().VerifyHeader(bc, block.Header(), true); err != nil {
return errors.Wrap(err, "[VerifyHeader]")
}
if _, err := bc.InsertChain(types.Blocks{block}, false); err != nil {
_, err = bc.InsertChain(types.Blocks{block}, false)
switch {
case errors.Is(err, core.ErrKnownBlock):
return nil
case err != nil:
return errors.Wrap(err, "[InsertChain]")
default:
}
return nil
}

@ -4,6 +4,7 @@ import (
"context"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/internal/utils"
sttypes "github.com/harmony-one/harmony/p2p/stream/types"
"github.com/harmony-one/harmony/shard"
@ -129,13 +130,20 @@ func (sr *StageEpoch) doShortRangeSyncForEpochSync(ctx context.Context, s *Stage
return 0, nil
}
n, err := s.state.bc.InsertChain(blocks, true)
numBlocksInsertedShortRangeHistogramVec.With(s.state.promLabels()).Observe(float64(n))
if err != nil {
utils.Logger().Info().Err(err).Int("blocks inserted", n).Msg("Insert block failed")
sh.streamsFailed([]sttypes.StreamID{streamID}, "corrupted data")
return n, err
n := 0
for _, block := range blocks {
_, err := s.state.bc.InsertChain([]*types.Block{block}, true)
switch {
case errors.Is(err, core.ErrKnownBlock):
case err != nil:
utils.Logger().Info().Err(err).Int("blocks inserted", n).Msg("Insert block failed")
sh.streamsFailed([]sttypes.StreamID{streamID}, "corrupted data")
return n, err
default:
}
n++
}
numBlocksInsertedShortRangeHistogramVec.With(s.state.promLabels()).Observe(float64(n))
return n, nil
}

@ -636,7 +636,8 @@ func (ss *StagedStreamSync) addConsensusLastMile(bc core.BlockChain, cs *consens
if block == nil {
break
}
if _, err := bc.InsertChain(types.Blocks{block}, true); err != nil {
_, err := bc.InsertChain(types.Blocks{block}, true)
if err != nil && !errors.Is(err, core.ErrKnownBlock) {
return errors.Wrap(err, "failed to InsertChain")
}
hashes = append(hashes, block.Header().Hash())
@ -704,13 +705,16 @@ func (ss *StagedStreamSync) UpdateBlockAndStatus(block *types.Block, bc core.Blo
}
_, err := bc.InsertChain([]*types.Block{block}, false /* verifyHeaders */)
if err != nil {
switch {
case errors.Is(err, core.ErrKnownBlock):
case err != nil:
utils.Logger().Error().
Err(err).
Uint64("block number", block.NumberU64()).
Uint32("shard", block.ShardID()).
Msgf("[STAGED_STREAM_SYNC] UpdateBlockAndStatus: Error adding new block to blockchain")
return err
default:
}
utils.Logger().Info().
Uint64("blockHeight", block.NumberU64()).

@ -178,7 +178,7 @@ func (stg *StageStates) Exec(firstCycle bool, invalidBlockRevert bool, s *StageS
headBeforeNewBlocks := stg.configs.bc.CurrentBlock().NumberU64()
headHashBeforeNewBlocks := stg.configs.bc.CurrentBlock().Hash()
_, err = stg.configs.bc.InsertChain(newBlocks, false) //TODO: verifyHeaders can be done here
if err != nil {
if err != nil && !errors.Is(err, core.ErrKnownBlock) {
// TODO: handle chain rollback because of bad block
utils.Logger().Error().
Err(err).

@ -1091,13 +1091,16 @@ func (ss *StagedSync) UpdateBlockAndStatus(block *types.Block, bc core.BlockChai
}
_, err := bc.InsertChain([]*types.Block{block}, false /* verifyHeaders */)
if err != nil {
switch {
case errors.Is(err, core.ErrKnownBlock):
case err != nil:
utils.Logger().Error().
Err(err).
Uint64("block number", block.NumberU64()).
Uint32("shard", block.ShardID()).
Msgf("[STAGED_SYNC] UpdateBlockAndStatus: Error adding new block to blockchain")
return err
default:
}
utils.Logger().Info().
Uint64("blockHeight", block.NumberU64()).
@ -1218,7 +1221,7 @@ func (ss *StagedSync) addConsensusLastMile(bc core.BlockChain, cs *consensus.Con
if block == nil {
break
}
if _, err := bc.InsertChain(types.Blocks{block}, true); err != nil {
if _, err := bc.InsertChain(types.Blocks{block}, true); err != nil && !errors.Is(err, core.ErrKnownBlock) {
return errors.Wrap(err, "failed to InsertChain")
}
}

@ -14,6 +14,7 @@ import (
"github.com/harmony-one/harmony/core"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
libp2p_peer "github.com/libp2p/go-libp2p/core/peer"
"github.com/rs/zerolog"
msg_pb "github.com/harmony-one/harmony/api/proto/message"
@ -55,7 +56,7 @@ func (consensus *Consensus) isViewChangingMode() bool {
}
// HandleMessageUpdate will update the consensus state according to received message
func (consensus *Consensus) HandleMessageUpdate(ctx context.Context, msg *msg_pb.Message, senderKey *bls.SerializedPublicKey) error {
func (consensus *Consensus) HandleMessageUpdate(ctx context.Context, peer libp2p_peer.ID, msg *msg_pb.Message, senderKey *bls.SerializedPublicKey) error {
consensus.mutex.Lock()
defer consensus.mutex.Unlock()
// when node is in ViewChanging mode, it still accepts normal messages into FBFTLog
@ -661,7 +662,8 @@ func (consensus *Consensus) tryCatchup() error {
func (consensus *Consensus) commitBlock(blk *types.Block, committedMsg *FBFTMessage) error {
if consensus.Blockchain().CurrentBlock().NumberU64() < blk.NumberU64() {
if _, err := consensus.Blockchain().InsertChain([]*types.Block{blk}, !consensus.fBFTLog.IsBlockVerified(blk.Hash())); err != nil {
_, err := consensus.Blockchain().InsertChain([]*types.Block{blk}, !consensus.fBFTLog.IsBlockVerified(blk.Hash()))
if err != nil && !errors.Is(err, core.ErrKnownBlock) {
consensus.getLogger().Error().Err(err).Msg("[commitBlock] Failed to add block to chain")
return err
}

@ -2,6 +2,7 @@ package consensus
import (
"github.com/ethereum/go-ethereum/event"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types"
"github.com/pkg/errors"
)
@ -93,7 +94,7 @@ func (consensus *Consensus) AddConsensusLastMile() error {
if block == nil {
break
}
if _, err := consensus.Blockchain().InsertChain(types.Blocks{block}, true); err != nil {
if _, err := consensus.Blockchain().InsertChain(types.Blocks{block}, true); err != nil && !errors.Is(err, core.ErrKnownBlock) {
return errors.Wrap(err, "failed to InsertChain")
}
}

@ -4,9 +4,11 @@ import (
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/trie"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/consensus/reward"
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/state/snapshot"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/internal/params"
@ -23,6 +25,9 @@ type ChainReader interface {
// Config retrieves the blockchain's chain configuration.
Config() *params.ChainConfig
// TrieDB returns trie database
TrieDB() *trie.Database
// TrieNode retrieves a blob of data associated with a trie node
// either from ephemeral in-memory cache, or from persistent storage.
TrieNode(hash common.Hash) ([]byte, error)
@ -62,6 +67,9 @@ type ChainReader interface {
// GetBlock retrieves a block from the database by hash and number.
GetBlock(hash common.Hash, number uint64) *types.Block
// Snapshots returns the blockchain snapshot tree.
Snapshots() *snapshot.Tree
// ReadShardState retrieves sharding state given the epoch number.
// This api reads the shard state cached or saved on the chaindb.
// Thus, only should be used to read the shard state of the current chain.

@ -6,6 +6,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/trie"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/consensus/engine"
"github.com/harmony-one/harmony/consensus/reward"
@ -62,6 +63,10 @@ type BlockChain interface {
State() (*state.DB, error)
// StateAt returns a new mutable state based on a particular point in time.
StateAt(root common.Hash) (*state.DB, error)
// Snapshots returns the blockchain snapshot tree.
Snapshots() *snapshot.Tree
// TrieDB returns trie database
TrieDB() *trie.Database
// HasBlock checks if a block is fully present in the database or not.
HasBlock(hash common.Hash, number uint64) bool
// HasState checks if state trie is fully present in the database or not.

@ -1122,6 +1122,11 @@ func (bc *BlockChainImpl) GetUnclesInChain(b *types.Block, length int) []*block.
return uncles
}
// TrieDB returns trie database
func (bc *BlockChainImpl) TrieDB() *trie.Database {
return bc.stateCache.TrieDB()
}
// TrieNode retrieves a blob of data associated with a trie node (or code hash)
// either from ephemeral in-memory cache, or from persistent storage.
func (bc *BlockChainImpl) TrieNode(hash common.Hash) ([]byte, error) {
@ -1678,6 +1683,8 @@ func (bc *BlockChainImpl) insertChain(chain types.Blocks, verifyHeaders bool) (i
if len(chain) == 0 {
return 0, nil, nil, ErrEmptyChain
}
first := chain[0]
fmt.Println("insertChain", utils.GetPort(), first.ShardID(), first.Epoch().Uint64(), first.NumberU64())
// Do a sanity check that the provided chain is actually ordered and linked
for i := 1; i < len(chain); i++ {
if chain[i].NumberU64() != chain[i-1].NumberU64()+1 || chain[i].ParentHash() != chain[i-1].Hash() {

@ -8,6 +8,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/trie"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/consensus/engine"
"github.com/harmony-one/harmony/consensus/reward"
@ -64,6 +65,14 @@ func (a Stub) StateAt(common.Hash) (*state.DB, error) {
return nil, errors.Errorf("method StateAt not implemented for %s", a.Name)
}
func (a Stub) Snapshots() *snapshot.Tree {
return nil
}
func (a Stub) TrieDB() *trie.Database {
return nil
}
func (a Stub) TrieNode(hash common.Hash) ([]byte, error) {
return []byte{}, errors.Errorf("method TrieNode not implemented for %s", a.Name)
}

@ -14,7 +14,7 @@ require (
github.com/coinbase/rosetta-sdk-go v0.7.0
github.com/davecgh/go-spew v1.1.1
github.com/deckarep/golang-set v1.8.0
github.com/ethereum/go-ethereum v1.11.2
github.com/ethereum/go-ethereum v1.13.4
github.com/go-redis/redis/v8 v8.11.5
github.com/golang/mock v1.6.0
github.com/golang/protobuf v1.5.3
@ -38,7 +38,7 @@ require (
github.com/pborman/uuid v1.2.0
github.com/pelletier/go-toml v1.9.5
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.14.0
github.com/prometheus/client_golang v1.17.0
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0
github.com/rjeczalik/notify v0.9.2
github.com/rs/cors v1.7.0
@ -52,14 +52,14 @@ require (
github.com/whyrusleeping/timecache v0.0.0-20160911033111-cfcb2f1abfee
go.uber.org/ratelimit v0.1.0
go.uber.org/zap v1.24.0
golang.org/x/crypto v0.9.0
golang.org/x/net v0.10.0 // indirect
golang.org/x/sync v0.2.0
golang.org/x/sys v0.8.0 // indirect
golang.org/x/crypto v0.14.0
golang.org/x/net v0.17.0 // indirect
golang.org/x/sync v0.4.0
golang.org/x/sys v0.13.0 // indirect
golang.org/x/time v0.3.0
golang.org/x/tools v0.9.3 // indirect
golang.org/x/tools v0.14.0 // indirect
google.golang.org/grpc v1.55.0
google.golang.org/protobuf v1.30.0
google.golang.org/protobuf v1.31.0
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6
@ -76,27 +76,27 @@ require (
require (
github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect
github.com/BurntSushi/toml v1.2.0 // indirect
github.com/DataDog/zstd v1.5.2 // indirect
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/DataDog/zstd v1.5.5 // indirect
github.com/OpenPeeDeeP/depguard v1.0.1 // indirect
github.com/VictoriaMetrics/metrics v1.23.1 // indirect
github.com/benbjohnson/clock v1.3.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.5.0 // indirect
github.com/bits-and-blooms/bitset v1.7.0 // indirect
github.com/bombsimon/wsl/v2 v2.0.0 // indirect
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.2 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cockroachdb/errors v1.9.1 // indirect
github.com/cockroachdb/errors v1.11.1 // indirect
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
github.com/cockroachdb/pebble v0.0.0-20230302152029-717cbce0c2e3 // indirect
github.com/cockroachdb/redact v1.1.3 // indirect
github.com/cockroachdb/redact v1.1.5 // indirect
github.com/containerd/cgroups v1.1.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect
github.com/deckarep/golang-set/v2 v2.3.0 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
github.com/deckarep/golang-set/v2 v2.3.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/dgraph-io/badger v1.6.2 // indirect
github.com/dgraph-io/ristretto v0.0.3 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
@ -109,10 +109,10 @@ require (
github.com/francoispqt/gojay v1.2.13 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/gballet/go-libpcsclite v0.0.0-20190607065134-2772fd86a8ff // indirect
github.com/getsentry/sentry-go v0.18.0 // indirect
github.com/getsentry/sentry-go v0.25.0 // indirect
github.com/go-critic/go-critic v0.4.0 // indirect
github.com/go-lintpack/lintpack v0.5.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-ole/go-ole v1.3.0 // indirect
github.com/go-stack/stack v1.8.1 // indirect
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
github.com/go-toolsmith/astcast v1.0.0 // indirect
@ -126,7 +126,7 @@ require (
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/gofrs/flock v0.8.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 // indirect
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a // indirect
github.com/golangci/errcheck v0.0.0-20181223084120-ef45e06d44b6 // indirect
@ -152,8 +152,8 @@ require (
github.com/hashicorp/golang-lru/v2 v2.0.2 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e // indirect
github.com/holiman/uint256 v1.2.2 // indirect
github.com/huin/goupnp v1.1.0 // indirect
github.com/holiman/uint256 v1.2.3 // indirect
github.com/huin/goupnp v1.3.0 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/ipfs/go-cid v0.4.1 // indirect
github.com/ipfs/go-datastore v0.6.0 // indirect
@ -167,7 +167,7 @@ require (
github.com/jbenet/goprocess v0.1.4 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/kisielk/gotool v1.0.0 // indirect
github.com/klauspost/compress v1.16.4 // indirect
github.com/klauspost/compress v1.17.1 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect
github.com/koron/go-ssdp v0.0.4 // indirect
github.com/kr/pretty v0.3.1 // indirect
@ -188,7 +188,7 @@ require (
github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.18 // indirect
github.com/mattn/go-runewidth v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/miekg/dns v1.1.53 // indirect
github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect
@ -220,10 +220,10 @@ require (
github.com/pingcap/log v0.0.0-20211215031037-e024ba4eb0ee // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/polydawn/refmt v0.0.0-20201211092308-30ac6d18308e // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.9.0 // indirect
github.com/prometheus/tsdb v0.10.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/prometheus/tsdb v0.7.1 // indirect
github.com/quic-go/qpack v0.4.0 // indirect
github.com/quic-go/qtls-go1-19 v0.3.3 // indirect
github.com/quic-go/qtls-go1-20 v0.2.3 // indirect
@ -231,7 +231,7 @@ require (
github.com/quic-go/webtransport-go v0.5.2 // indirect
github.com/raulk/go-watchdog v1.3.0 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
github.com/securego/gosec v0.0.0-20191002120514-e680875ea14d // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
@ -245,8 +245,8 @@ require (
github.com/subosito/gotenv v1.4.1 // indirect
github.com/tikv/pd/client v0.0.0-20220216070739-26c668271201 // indirect
github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e // indirect
github.com/tklauser/go-sysconf v0.3.11 // indirect
github.com/tklauser/numcpus v0.6.0 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/tommy-muehle/go-mnd v1.1.1 // indirect
github.com/torquem-ch/mdbx-go v0.27.10 // indirect
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
@ -256,16 +256,16 @@ require (
github.com/valyala/fastrand v1.1.0 // indirect
github.com/valyala/histogram v1.2.0 // indirect
github.com/whyrusleeping/go-keyspace v0.0.0-20160322163242-5b898ac5add1 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
go.uber.org/dig v1.16.1 // indirect
go.uber.org/fx v1.19.2 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/term v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/mod v0.13.0 // indirect
golang.org/x/term v0.13.0 // indirect
golang.org/x/text v0.13.0 // indirect
google.golang.org/genproto v0.0.0-20230306155012-7f2fa6fef1f4 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect

121
go.sum

@ -60,8 +60,9 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v0.8.3/go.mod h1:KLF4gFr6DcKFZwSu
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v0.3.0/go.mod h1:tPaiy8S5bQ+S5sOiDlINkp7+Ef339+Nz5L5XO+cnOHo=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.2.0 h1:Rt8g24XnyGTyglgET/PRUNlrUeu9F5L+7FilkXfZgs0=
github.com/BurntSushi/toml v1.2.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw=
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
@ -71,8 +72,9 @@ github.com/CloudyKit/jet/v6 v6.1.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/DataDog/zstd v1.5.2 h1:vUG4lAyuPCXO0TLbXvPv7EB7cNK1QV/luu55UHLrrn8=
github.com/DataDog/zstd v1.5.2/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ=
github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw=
github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXYg9BVp4O+o5f6V/ehm6Oo=
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM=
@ -138,8 +140,8 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
github.com/bits-and-blooms/bitset v1.5.0 h1:NpE8frKRLGHIcEzkR+gZhiioW1+WbYV6fKwD6ZIpQT8=
github.com/bits-and-blooms/bitset v1.5.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
github.com/bits-and-blooms/bitset v1.7.0 h1:YjAGVd3XmtK9ktAbX8Zg2g2PwLIMjGREZJHlV4j7NEo=
github.com/bits-and-blooms/bitset v1.7.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA=
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c=
@ -204,8 +206,9 @@ github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD9
github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU=
github.com/cockroachdb/errors v1.6.1/go.mod h1:tm6FTP5G81vwJ5lC0SizQo374JNCOPrHyXGitRJoDqM=
github.com/cockroachdb/errors v1.8.1/go.mod h1:qGwQn6JmZ+oMjuLwjWzUNqblqk0xl4CVV3SQbGwK7Ac=
github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8=
github.com/cockroachdb/errors v1.9.1/go.mod h1:2sxOtL2WIc096WSZqZ5h8fa17rdDq9HZOZLBCor4mBk=
github.com/cockroachdb/errors v1.11.1 h1:xSEW75zKaKCWzR3OfxXUxgrk/NtT4G1MiOv5lWZazG8=
github.com/cockroachdb/errors v1.11.1/go.mod h1:8MUxA3Gi6b25tYlFEBGLf+D8aISL+M4MIpiWMSNRfxw=
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
github.com/cockroachdb/logtags v0.0.0-20211118104740-dabe8e521a4f/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs=
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE=
@ -214,8 +217,9 @@ github.com/cockroachdb/pebble v0.0.0-20230209160836-829675f94811/go.mod h1:Nb5lg
github.com/cockroachdb/pebble v0.0.0-20230302152029-717cbce0c2e3 h1:S4re5MXHfznkOlgkgUfh9ptgaG2esdH95IuJWwP0fM0=
github.com/cockroachdb/pebble v0.0.0-20230302152029-717cbce0c2e3/go.mod h1:9lRMC4XN3/BLPtIp6kAKwIaHu369NOf2rMucPzipz50=
github.com/cockroachdb/redact v1.0.8/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
github.com/cockroachdb/redact v1.1.3 h1:AKZds10rFSIj7qADf0g46UixK8NNLwWTNdCIGS5wfSQ=
github.com/cockroachdb/redact v1.1.3/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30=
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
github.com/cockroachdb/sentry-go v0.6.1-cockroachdb.2/go.mod h1:8BT+cPK6xvFOcRlk0R8eg+OTkcqI6baNH4xAkpiYVvQ=
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
github.com/coinbase/rosetta-sdk-go v0.7.0 h1:lmTO/JEpCvZgpbkOITL95rA80CPKb5CtMzLaqF2mCNg=
@ -258,13 +262,13 @@ github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6Uh
github.com/deckarep/golang-set v1.8.0 h1:sk9/l/KqpunDwP7pSjUg0keiOOLEnOBHzykLrsPppp4=
github.com/deckarep/golang-set v1.8.0/go.mod h1:5nI87KwE7wgsBU1F4GKAw2Qod7p5kyS383rP6+o6qqo=
github.com/deckarep/golang-set/v2 v2.1.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
github.com/deckarep/golang-set/v2 v2.3.0 h1:qs18EKUfHm2X9fA50Mr/M5hccg2tNnVqsiBImnyDs0g=
github.com/deckarep/golang-set/v2 v2.3.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0=
github.com/deckarep/golang-set/v2 v2.3.1 h1:vjmkvJt/IV27WXPyYQpAh4bRyWJc5Y435D17XQ9QU5A=
github.com/deckarep/golang-set/v2 v2.3.1/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1owhMVTHFZIlnvd4=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
github.com/deepmap/oapi-codegen v1.6.0/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M=
github.com/deepmap/oapi-codegen v1.8.2/go.mod h1:YLgSKSDv/bZQB7N4ws6luhozi3cEdRktEqrX88CvjIw=
@ -352,8 +356,9 @@ github.com/gballet/go-verkle v0.0.0-20220902153445-097bd83b7732/go.mod h1:o/XfIX
github.com/getkin/kin-openapi v0.53.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=
github.com/getkin/kin-openapi v0.61.0/go.mod h1:7Yn5whZr5kJi6t+kShccXS8ae1APpYTW6yheSwk8Yi4=
github.com/getsentry/sentry-go v0.12.0/go.mod h1:NSap0JBYWzHND8oMbyi0+XZhUalc1TBdRL1M71JZW2c=
github.com/getsentry/sentry-go v0.18.0 h1:MtBW5H9QgdcJabtZcuJG80BMOwaBpkRDZkxRkNC1sN0=
github.com/getsentry/sentry-go v0.18.0/go.mod h1:Kgon4Mby+FJ7ZWHFUAZgVaIa8sxHtnRJRLTXZr51aKQ=
github.com/getsentry/sentry-go v0.25.0 h1:q6Eo+hS+yoJlTO3uu/azhQadsD8V+jQn2D8VvX1eOyI=
github.com/getsentry/sentry-go v0.25.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
github.com/ghemawat/stream v0.0.0-20171120220530-696b145b53b9/go.mod h1:106OIgooyS7OzLDOpUGgm9fA3bQENb/cFSyyBmMoJDs=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
@ -393,8 +398,9 @@ github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KE
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-martini/martini v0.0.0-20170121215854-22fa46961aab/go.mod h1:/P9AEU963A2AYjv4d1V5eVL1CQbEJq6aCNHDDjibzu8=
github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
@ -518,8 +524,9 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8l
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.2-0.20190904063534-ff6b7dc882cf/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb h1:PBC98N2aIaM3XXiurYmW7fx4GZkL8feAMVq7nEjURHk=
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2 h1:23T5iq8rbUYlhpt5DB4XJkc6BU31uODLD1o1gKvZmD0=
github.com/golangci/check v0.0.0-20180506172741-cfe4005ccda2/go.mod h1:k9Qvh+8juN+UKMCS/3jFtGICgW8O96FVaZsaxdzDkR4=
github.com/golangci/dupl v0.0.0-20180902072040-3e9179ac440a h1:w8hkcTqaFpzKqonE9uMCefW1WDie15eSP/4MssdenaM=
@ -682,13 +689,13 @@ github.com/holiman/big v0.0.0-20221017200358-a027dc42d04e/go.mod h1:j9cQbcqHQujT
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
github.com/holiman/uint256 v1.2.2 h1:TXKcSGc2WaxPD2+bmzAsVthL4+pEN0YwXcL5qED83vk=
github.com/holiman/uint256 v1.2.2/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw=
github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o=
github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huin/goupnp v1.0.0/go.mod h1:n9v9KO1tAxYH82qOn+UTIFQDmx5n1Zxd/ClZDMX7Bnc=
github.com/huin/goupnp v1.0.3/go.mod h1:ZxNlw5WqJj6wSsRK5+YfflQGXYfccj5VgQsMNixHM7Y=
github.com/huin/goupnp v1.1.0 h1:gEe0Dp/lZmPZiDFzJJaOfUpOvv2MKUkoBX8lDrn9vKU=
github.com/huin/goupnp v1.1.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8=
github.com/huin/goutil v0.0.0-20170803182201-1ca381bf3150/go.mod h1:PpLOETDnJ0o3iZrZfqZzyLl6l7F3c6L1oWn7OICBi6o=
github.com/hydrogen18/memlistener v0.0.0-20141126152155-54553eb933fb/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
github.com/hydrogen18/memlistener v0.0.0-20200120041712-dcc25e7acd91/go.mod h1:qEIFzExnS6016fRpRfxrExeVn2gbClQA99gQhnIcdhE=
@ -816,8 +823,8 @@ github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47e
github.com/klauspost/compress v1.15.10/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4=
github.com/klauspost/compress v1.16.4 h1:91KN02FnsOYhuunwU4ssRe8lc2JosWmizWa91B5v1PU=
github.com/klauspost/compress v1.16.4/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/compress v1.17.1 h1:NE3C767s2ak2bweCZo3+rdP4U/HoyVXLv/X9f2gPS5g=
github.com/klauspost/compress v1.17.1/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
@ -939,8 +946,8 @@ github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp9
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU=
github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
@ -1147,15 +1154,17 @@ github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
github.com/prometheus/client_golang v1.12.0/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY=
github.com/prometheus/client_golang v1.14.0 h1:nJdhIvne2eSX/XRAFV9PcvFFRbrjbcTUj0VP62TMhnw=
github.com/prometheus/client_golang v1.14.0/go.mod h1:8vpkKitgIVNcqrRBWh1C4TIUQgYNtG/XQE4E/Zae36Y=
github.com/prometheus/client_golang v1.17.0 h1:rl2sfwZMtSthVU752MqfjQozy7blglC+1SOtjMAMh+Q=
github.com/prometheus/client_golang v1.17.0/go.mod h1:VeL+gMmOAxkS2IqfCq0ZmHSL+LjWfWDUmp1mBz9JgUY=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.1-0.20210607210712-147c58e9608a/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
@ -1166,8 +1175,8 @@ github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
github.com/prometheus/common v0.39.0/go.mod h1:6XBZ7lYdLCbkAVhwRsWTZn+IN5AB9F/NXd5w0BbEX0Y=
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
@ -1176,11 +1185,11 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4=
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/prometheus/tsdb v0.7.1 h1:YZcsG11NqnK4czYLrWd9mpEuAJIHVQLwdrleYfszMAA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/prometheus/tsdb v0.10.0 h1:If5rVCMTp6W2SiRAQFlbpJNgVlgMEd+U2GZckwK38ic=
github.com/prometheus/tsdb v0.10.0/go.mod h1:oi49uRhEe9dPUTlS3JRZOwJuVi6tmh10QSgwXEyGCt4=
github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
@ -1209,8 +1218,9 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
@ -1363,12 +1373,12 @@ github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiff
github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE=
github.com/tklauser/go-sysconf v0.3.5/go.mod h1:MkWzOF4RMCshBAMXuhXJs64Rte09mITnppBXY/rYEFI=
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.2.2/go.mod h1:x3qojaO3uyYt0i56EW/VUYs7uBvdl2fkfZFu0T9wgjM=
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tommy-muehle/go-mnd v1.1.1 h1:4D0wuPKjOTiK2garzuPGGvm4zZ/wLYDOH8TJSABC7KU=
github.com/tommy-muehle/go-mnd v1.1.1/go.mod h1:dSUh0FtTP8VhvkL1S+gUR1OKd9ZnSaozuI6r3m6wOig=
@ -1445,8 +1455,9 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw=
github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
@ -1546,8 +1557,8 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -1564,8 +1575,8 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMk
golang.org/x/exp v0.0.0-20200513190911-00229845015e/go.mod h1:4M0jN8W1tt0AVLNr8HDosyJCDCDuyL9N9+3m7wDWgKw=
golang.org/x/exp v0.0.0-20220426173459-3bcf042a4bf5/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE=
golang.org/x/exp v0.0.0-20230206171751-46f607a40771/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@ -1597,8 +1608,8 @@ golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20211013180041-c96bc1413d57/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY=
golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -1673,8 +1684,8 @@ golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfS
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -1707,8 +1718,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ=
golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -1826,15 +1837,17 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -1847,8 +1860,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -1946,8 +1959,8 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
golang.org/x/tools v0.9.3 h1:Gn1I8+64MsuTb/HpH+LmQtNas23LhUVr3rYZ0eKuaMM=
golang.org/x/tools v0.9.3/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc=
golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@ -2093,8 +2106,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

@ -8,11 +8,13 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/trie"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/consensus/engine"
"github.com/harmony-one/harmony/consensus/reward"
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/state/snapshot"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/crypto/bls"
"github.com/harmony-one/harmony/internal/params"
@ -88,7 +90,9 @@ func (bc *testBlockChain) changeBlockNumber(val uint64) {
func (bc *testBlockChain) ShardID() uint32 { return 0 }
func (bc *testBlockChain) ReadShardState(epoch *big.Int) (*shard.State, error) { return nil, nil }
func (bc *testBlockChain) Snapshots() *snapshot.Tree { return nil }
func (bc *testBlockChain) TrieNode(hash common.Hash) ([]byte, error) { return []byte{}, nil }
func (bc *testBlockChain) TrieDB() *trie.Database { return nil }
func (bc *testBlockChain) Config() *params.ChainConfig { return nil }
func (bc *testBlockChain) WriteCommitSig(blockNum uint64, lastCommits []byte) error { return nil }
func (bc *testBlockChain) GetHeader(hash common.Hash, number uint64) *block.Header { return nil }

@ -6,8 +6,9 @@ import (
"math/big"
"testing"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/trie"
bls_core "github.com/harmony-one/bls/ffi/go/bls"
"github.com/harmony-one/harmony/block"
blockfactory "github.com/harmony-one/harmony/block/factory"
"github.com/harmony-one/harmony/common/denominations"
"github.com/harmony-one/harmony/core"
@ -19,7 +20,14 @@ import (
"github.com/harmony-one/harmony/numeric"
"github.com/harmony-one/harmony/staking/effective"
staking "github.com/harmony-one/harmony/staking/types"
staketest "github.com/harmony-one/harmony/staking/types/test"
types2 "github.com/harmony-one/harmony/staking/types"
"github.com/ethereum/go-ethereum/common"
"github.com/harmony-one/harmony/core/rawdb"
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/state/snapshot"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/internal/params"
)
type fakeReader struct {
@ -98,113 +106,95 @@ func sampleWrapper(address common.Address) *staking.ValidatorWrapper {
Description: defaultDesc,
CreationHeight: big.NewInt(100),
}
// ds := staking.Delegations{
// staking.NewDelegation(address, big.NewInt(0)),
// }
w := &staking.ValidatorWrapper{
Validator: v,
BlockReward: big.NewInt(0),
}
w.Counters.NumBlocksSigned = common.Big0
w.Counters.NumBlocksToSign = common.Big0
return w
}
func TestPruneStaleStakingData(t *testing.T) {
blockFactory := blockfactory.ForTest
header := blockFactory.NewHeader(common.Big0) // epoch
chain := fakeReader{core.FakeChainReader{InternalConfig: params.LocalnetChainConfig}}
db := getDatabase()
// now make the two wrappers and store them
wrapper := sampleWrapper(validator1)
wrapper.Status = effective.Inactive
wrapper.Delegations = staking.Delegations{
staking.NewDelegation(wrapper.Address, big.NewInt(0)),
staking.NewDelegation(delegator1, big.NewInt(0)),
staking.NewDelegation(delegator2, big.NewInt(0)),
staking.NewDelegation(delegator3, new(big.Int).Mul(big.NewInt(denominations.One), big.NewInt(100))),
}
if err := wrapper.Delegations[3].Undelegate(
big.NewInt(2), new(big.Int).Mul(big.NewInt(denominations.One), big.NewInt(100)), nil,
); err != nil {
t.Fatalf("Got error %v", err)
}
if wrapper.Delegations[3].Amount.Cmp(common.Big0) != 0 {
t.Fatalf("Expected 0 delegation but got %v", wrapper.Delegations[3].Amount)
}
if err := db.UpdateValidatorWrapper(wrapper.Address, wrapper); err != nil {
t.Fatalf("Got error %v", err)
}
wrapper = sampleWrapper(validator2)
wrapper.Status = effective.Active
wrapper.Delegations = staking.Delegations{
staking.NewDelegation(wrapper.Address, new(big.Int).Mul(big.NewInt(denominations.One), big.NewInt(10000))),
staking.NewDelegation(delegator1, new(big.Int).Mul(big.NewInt(denominations.One), big.NewInt(100))),
staking.NewDelegation(delegator2, big.NewInt(0)),
staking.NewDelegation(delegator3, big.NewInt(0)),
staking.NewDelegation(validator1, big.NewInt(0)),
}
wrapper.Delegations[3].Reward = common.Big257
if err := db.UpdateValidatorWrapper(wrapper.Address, wrapper); err != nil {
t.Fatalf("Got error %v", err)
}
// we expect
// (1) validator1 to show up with validator2 only (and not validator1 where the delegation is 0)
// (2) delegator1 to show up with validator1 only (validator2 has amount)
// (3) delegator2 to show up with both validator1 and validator2
// (4) delegator3 to show up with neither validator1 (undelegation) nor validator2 (reward)
delegationsToRemove := make(map[common.Address][]common.Address, 0)
if err := pruneStaleStakingData(&chain, header, db, delegationsToRemove); err != nil {
t.Fatalf("Got error %v", err)
}
if toRemove, ok := delegationsToRemove[validator1]; ok {
if len(toRemove) != 1 {
t.Errorf("Unexpected # of removals for validator1 %d", len(toRemove))
}
if len(toRemove) > 0 {
for _, validatorAddress := range toRemove {
if bytes.Equal(validatorAddress.Bytes(), validator1.Bytes()) {
t.Errorf("Found validator1 being removed from validator1's delegations")
}
}
}
}
if toRemove, ok := delegationsToRemove[delegator1]; ok {
if len(toRemove) != 1 {
t.Errorf("Unexpected # of removals for delegator1 %d", len(toRemove))
}
if len(toRemove) > 0 {
for _, validatorAddress := range toRemove {
if !bytes.Equal(validatorAddress.Bytes(), validator1.Bytes()) {
t.Errorf("Unexpected removal for delegator1; validator1 %s, validator2 %s, validatorAddress %s",
validator1.Hex(),
validator2.Hex(),
validatorAddress.Hex(),
)
}
}
}
}
if toRemove, ok := delegationsToRemove[delegator2]; ok {
if len(toRemove) != 2 {
t.Errorf("Unexpected # of removals for delegator2 %d", len(toRemove))
}
if len(toRemove) > 0 {
for _, validatorAddress := range toRemove {
if !(bytes.Equal(validatorAddress.Bytes(), validator1.Bytes()) ||
bytes.Equal(validatorAddress.Bytes(), validator2.Bytes())) {
t.Errorf("Unexpected removal for delegator2; validator1 %s, validator2 %s, validatorAddress %s",
validator1.Hex(),
validator2.Hex(),
validatorAddress.Hex(),
)
}
}
}
}
if toRemove, ok := delegationsToRemove[delegator3]; ok {
if len(toRemove) != 0 {
t.Errorf("Unexpected # of removals for delegator3 %d", len(toRemove))
}
}
func makeBlockForTest(epoch int64, index int) *types.Block {
h := blockfactory.NewTestHeader()
h.SetEpoch(big.NewInt(epoch))
h.SetNumber(big.NewInt(doubleSignBlockNumber))
h.SetViewID(big.NewInt(doubleSignViewID))
h.SetRoot(common.BigToHash(big.NewInt(int64(index))))
return types.NewBlockWithHeader(h)
}
func (bc *fakeBlockChain) CurrentBlock() *types.Block {
return &bc.currentBlock
}
func (bc *fakeBlockChain) CurrentHeader() *block.Header {
return bc.currentBlock.Header()
}
func (bc *fakeBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { return nil }
func (bc *fakeBlockChain) GetHeader(hash common.Hash, number uint64) *block.Header { return nil }
func (bc *fakeBlockChain) GetHeaderByHash(hash common.Hash) *block.Header { return nil }
func (bc *fakeBlockChain) GetReceiptsByHash(hash common.Hash) types.Receipts { return nil }
func (bc *fakeBlockChain) ContractCode(hash common.Hash) ([]byte, error) { return []byte{}, nil }
func (bc *fakeBlockChain) ValidatorCode(hash common.Hash) ([]byte, error) { return []byte{}, nil }
func (bc *fakeBlockChain) ShardID() uint32 { return 0 }
func (bc *fakeBlockChain) ReadShardState(epoch *big.Int) (*shard.State, error) { return nil, nil }
func (bc *fakeBlockChain) TrieDB() *trie.Database { return nil }
func (bc *fakeBlockChain) TrieNode(hash common.Hash) ([]byte, error) { return []byte{}, nil }
func (bc *fakeBlockChain) WriteCommitSig(blockNum uint64, lastCommits []byte) error { return nil }
func (bc *fakeBlockChain) GetHeaderByNumber(number uint64) *block.Header { return nil }
func (bc *fakeBlockChain) ReadValidatorList() ([]common.Address, error) { return nil, nil }
func (bc *fakeBlockChain) ReadCommitSig(blockNum uint64) ([]byte, error) { return nil, nil }
func (bc *fakeBlockChain) ReadBlockRewardAccumulator(uint64) (*big.Int, error) { return nil, nil }
func (bc *fakeBlockChain) ValidatorCandidates() []common.Address { return nil }
func (cr *fakeBlockChain) ReadValidatorInformationAtState(addr common.Address, state *state.DB) (*staking.ValidatorWrapper, error) {
return nil, nil
}
func (bc *fakeBlockChain) ReadValidatorSnapshotAtEpoch(epoch *big.Int, offender common.Address) (*types2.ValidatorSnapshot, error) {
return &types2.ValidatorSnapshot{
Validator: makeDefaultValidatorWrapper(),
Epoch: epoch,
}, nil
}
func (bc *fakeBlockChain) ReadValidatorInformation(addr common.Address) (*staking.ValidatorWrapper, error) {
return nil, nil
}
func (bc *fakeBlockChain) Config() *params.ChainConfig {
return params.LocalnetChainConfig
}
func (cr *fakeBlockChain) StateAt(root common.Hash) (*state.DB, error) {
return nil, nil
}
func (cr *fakeBlockChain) Snapshots() *snapshot.Tree {
return nil
}
func (bc *fakeBlockChain) ReadValidatorSnapshot(addr common.Address) (*staking.ValidatorSnapshot, error) {
return nil, nil
}
func (bc *fakeBlockChain) ReadValidatorStats(addr common.Address) (*staking.ValidatorStats, error) {
return nil, nil
}
func (bc *fakeBlockChain) SuperCommitteeForNextEpoch(beacon engine.ChainReader, header *block.Header, isVerify bool) (*shard.State, error) {
return nil, nil
}
//
// Fake header for testing
//
func makeFakeHeader() *block.Header {
h := blockfactory.NewTestHeader()
h.SetCoinbase(leaderAddr)
return h
}
//
// Utilities for testing
//
func makeTestAddress(item interface{}) common.Address {
s := fmt.Sprintf("harmony.one.%v", item)
return common.BytesToAddress([]byte(s))
}
func makeVoteData(kp blsKeyPair, block *types.Block) slash.Vote {
return slash.Vote{
SignerPubKeys: []bls.SerializedPublicKey{kp.Pub()},
BlockHeaderHash: block.Hash(),
Signature: kp.Sign(block),
}
}

@ -0,0 +1,43 @@
package blockedpeers
import (
"time"
"github.com/harmony-one/harmony/internal/utils/lrucache"
"github.com/libp2p/go-libp2p/core/peer"
)
type Manager struct {
internal *lrucache.Cache[peer.ID, time.Time]
}
func NewManager(size int) *Manager {
return &Manager{
internal: lrucache.NewCache[peer.ID, time.Time](size),
}
}
func (m *Manager) IsBanned(key peer.ID, now time.Time) bool {
future, ok := m.internal.Get(key)
if ok {
return future.After(now) // future > now
}
return ok
}
func (m *Manager) Ban(key peer.ID, future time.Time) {
m.internal.Set(key, future)
}
func (m *Manager) Contains(key peer.ID) bool {
return m.internal.Contains(key)
}
func (m *Manager) Len() int {
return m.internal.Len()
}
func (m *Manager) Keys() []peer.ID {
return m.internal.Keys()
}

@ -0,0 +1,27 @@
package blockedpeers
import (
"testing"
"time"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/stretchr/testify/require"
)
func TestNewManager(t *testing.T) {
var (
peer1 peer.ID = "peer1"
now = time.Now()
m = NewManager(4)
)
t.Run("check_empty", func(t *testing.T) {
require.False(t, m.IsBanned(peer1, now), "peer1 should not be banned")
})
t.Run("ban_peer1", func(t *testing.T) {
m.Ban(peer1, now.Add(2*time.Second))
require.True(t, m.IsBanned(peer1, now), "peer1 should be banned")
require.False(t, m.IsBanned(peer1, now.Add(3*time.Second)), "peer1 should not be banned after 3 seconds")
})
}

@ -25,3 +25,21 @@ func (c *Cache[K, V]) Get(key K) (V, bool) {
func (c *Cache[K, V]) Set(key K, value V) {
c.cache.Add(key, value)
}
// Contains checks if a key is in the cache, without updating the
// recent-ness or deleting it for being stale.
func (c *Cache[K, V]) Contains(key K) bool {
return c.cache.Contains(key)
}
func (c *Cache[K, V]) Len() int {
return c.cache.Len()
}
func (c *Cache[K, V]) Keys() []K {
out := make([]K, 0, c.cache.Len())
for _, v := range c.cache.Keys() {
out = append(out, v.(K))
}
return out
}

@ -0,0 +1,28 @@
package lrucache
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestKeys(t *testing.T) {
c := NewCache[int, int](10)
for i := 0; i < 3; i++ {
c.Set(i, i)
}
m := map[int]int{
0: 0,
1: 1,
2: 2,
}
keys := c.Keys()
m2 := map[int]int{}
for _, k := range keys {
m2[k] = k
}
require.Equal(t, m, m2)
}

@ -555,7 +555,7 @@ func (node *Node) validateNodeMessage(ctx context.Context, payload []byte) (
// validate shardID
// validate public key size
// verify message signature
func validateShardBoundMessage(consensus *consensus.Consensus, nodeConfig *nodeconfig.ConfigType, payload []byte,
func validateShardBoundMessage(consensus *consensus.Consensus, peer libp2p_peer.ID, nodeConfig *nodeconfig.ConfigType, payload []byte,
) (*msg_pb.Message, *bls.SerializedPublicKey, bool, error) {
var (
m msg_pb.Message
@ -736,6 +736,7 @@ func (node *Node) StartPubSub() error {
// p2p consensus message handler function
type p2pHandlerConsensus func(
ctx context.Context,
peer libp2p_peer.ID,
msg *msg_pb.Message,
key *bls.SerializedPublicKey,
) error
@ -749,6 +750,7 @@ func (node *Node) StartPubSub() error {
// interface pass to p2p message validator
type validated struct {
peerID libp2p_peer.ID
consensusBound bool
handleC p2pHandlerConsensus
handleCArg *msg_pb.Message
@ -806,7 +808,7 @@ func (node *Node) StartPubSub() error {
// validate consensus message
validMsg, senderPubKey, ignore, err := validateShardBoundMessage(
node.Consensus, node.NodeConfig, openBox[proto.MessageCategoryBytes:],
node.Consensus, peer, node.NodeConfig, openBox[proto.MessageCategoryBytes:],
)
if err != nil {
@ -820,6 +822,7 @@ func (node *Node) StartPubSub() error {
}
msg.ValidatorData = validated{
peerID: peer,
consensusBound: true,
handleC: node.Consensus.HandleMessageUpdate,
handleCArg: validMsg,
@ -850,6 +853,7 @@ func (node *Node) StartPubSub() error {
}
}
msg.ValidatorData = validated{
peerID: peer,
consensusBound: false,
handleE: node.HandleNodeMessage,
handleEArg: validMsg,
@ -901,7 +905,7 @@ func (node *Node) StartPubSub() error {
errChan <- withError{err, nil}
}
} else {
if err := msg.handleC(ctx, msg.handleCArg, msg.senderPubKey); err != nil {
if err := msg.handleC(ctx, msg.peerID, msg.handleCArg, msg.senderPubKey); err != nil {
errChan <- withError{err, msg.senderPubKey}
}
}

@ -154,7 +154,7 @@ func (node *Node) AddNewBlockForExplorer(block *types.Block) {
utils.Logger().Info().Uint64("blockHeight", block.NumberU64()).Msg("[Explorer] Adding new block for explorer node")
if _, err := node.Blockchain().InsertChain([]*types.Block{block}, false); err == nil {
if _, err := node.Blockchain().InsertChain([]*types.Block{block}, false); err == nil || errors.Is(err, core.ErrKnownBlock) {
if block.IsLastBlockInEpoch() {
node.Consensus.UpdateConsensusInformation()
}

@ -350,6 +350,9 @@ func (node *Node) PostConsensusProcessing(newBlock *types.Block) error {
Int("numStakingTxns", len(newBlock.StakingTransactions())).
Uint32("numSignatures", numSignatures).
Msg("BINGO !!! Reached Consensus")
if node.Consensus.Mode() == consensus.Syncing {
node.Consensus.SetMode(node.Consensus.UpdateConsensusInformation())
}
node.Consensus.UpdateValidatorMetrics(float64(numSignatures), float64(newBlock.NumberU64()))

@ -11,6 +11,13 @@ import (
"sync"
"time"
"github.com/harmony-one/bls/ffi/go/bls"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/internal/utils/blockedpeers"
"github.com/harmony-one/harmony/p2p/discovery"
"github.com/harmony-one/harmony/p2p/security"
sttypes "github.com/harmony-one/harmony/p2p/stream/types"
"github.com/libp2p/go-libp2p"
dht "github.com/libp2p/go-libp2p-kad-dht"
libp2p_pubsub "github.com/libp2p/go-libp2p-pubsub"
@ -24,19 +31,11 @@ import (
"github.com/libp2p/go-libp2p/core/protocol"
"github.com/libp2p/go-libp2p/core/routing"
"github.com/libp2p/go-libp2p/p2p/net/connmgr"
"github.com/libp2p/go-libp2p/p2p/security/noise"
libp2ptls "github.com/libp2p/go-libp2p/p2p/security/tls"
ma "github.com/multiformats/go-multiaddr"
"github.com/pkg/errors"
"github.com/rs/zerolog"
"github.com/harmony-one/bls/ffi/go/bls"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/p2p/discovery"
"github.com/harmony-one/harmony/p2p/security"
sttypes "github.com/harmony-one/harmony/p2p/stream/types"
)
type ConnectCallback func(net libp2p_network.Network, conn libp2p_network.Conn) error
@ -254,7 +253,8 @@ func NewHost(cfg HostConfig) (Host, error) {
self.PeerID = p2pHost.ID()
subLogger := utils.Logger().With().Str("hostID", p2pHost.ID().Pretty()).Logger()
security := security.NewManager(cfg.MaxConnPerIP, cfg.MaxPeers)
banned := blockedpeers.NewManager(1024)
security := security.NewManager(cfg.MaxConnPerIP, int(cfg.MaxPeers), banned)
// has to save the private key for host
h := &HostV2{
h: p2pHost,
@ -269,6 +269,7 @@ func NewHost(cfg HostConfig) (Host, error) {
logger: &subLogger,
ctx: ctx,
cancel: cancel,
banned: banned,
}
utils.Logger().Info().
@ -323,6 +324,7 @@ type HostV2 struct {
onDisconnects DisconnectCallbacks
ctx context.Context
cancel func()
banned *blockedpeers.Manager
}
// PubSub ..
@ -492,9 +494,7 @@ func (host *HostV2) ListPeer(topic string) []libp2p_peer.ID {
// ListBlockedPeer returns list of blocked peer
func (host *HostV2) ListBlockedPeer() []libp2p_peer.ID {
// TODO: this is a place holder for now
peers := make([]libp2p_peer.ID, 0)
return peers
return host.banned.Keys()
}
// GetPeerCount ...

@ -3,9 +3,10 @@ package security
import (
"fmt"
"sync"
"sync/atomic"
"time"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/internal/utils/blockedpeers"
libp2p_network "github.com/libp2p/go-libp2p/core/network"
ma "github.com/multiformats/go-multiaddr"
"github.com/pkg/errors"
@ -16,58 +17,56 @@ type Security interface {
OnDisconnectCheck(conn libp2p_network.Conn) error
}
type Manager struct {
maxConnPerIP int
maxPeers int64
type peerMap struct {
peers map[string][]string
}
mutex sync.Mutex
peers peerMap // All the connected nodes, key is the Peer's IP, value is the peer's ID array
func newPeersMap() *peerMap {
return &peerMap{
peers: make(map[string][]string),
}
}
type peerMap struct {
count int64
peers sync.Map
func (peerMap *peerMap) Len() int {
return len(peerMap.peers)
}
func (peerMap *peerMap) Len() int64 {
return atomic.LoadInt64(&peerMap.count)
func (peerMap *peerMap) Store(key string, value []string) {
peerMap.peers[key] = value
}
func (peerMap *peerMap) Store(key, value interface{}) {
// only increment if you didn't have this key
hasKey := peerMap.HasKey(key)
peerMap.peers.Store(key, value)
if !hasKey {
atomic.AddInt64(&peerMap.count, 1)
}
func (peerMap *peerMap) HasKey(key string) bool {
_, ok := peerMap.peers[key]
return ok
}
func (peerMap *peerMap) HasKey(key interface{}) bool {
hasKey := false
peerMap.peers.Range(func(k, v interface{}) bool {
if k == key {
hasKey = true
return false
}
return true
})
return hasKey
func (peerMap *peerMap) Delete(key string) {
delete(peerMap.peers, key)
}
func (peerMap *peerMap) Delete(key interface{}) {
peerMap.peers.Delete(key)
atomic.AddInt64(&peerMap.count, -1)
func (peerMap *peerMap) Load(key string) (value []string, ok bool) {
value, ok = peerMap.peers[key]
return value, ok
}
func (peerMap *peerMap) Load(key interface{}) (value interface{}, ok bool) {
return peerMap.peers.Load(key)
func (peerMap *peerMap) Range(f func(key string, value []string) bool) {
for key, value := range peerMap.peers {
if !f(key, value) {
break
}
}
}
func (peerMap *peerMap) Range(f func(key, value any) bool) {
peerMap.peers.Range(f)
type Manager struct {
maxConnPerIP int
maxPeers int
mutex sync.Mutex
peers *peerMap // All the connected nodes, key is the Peer's IP, value is the peer's ID array
banned *blockedpeers.Manager
}
func NewManager(maxConnPerIP int, maxPeers int64) *Manager {
func NewManager(maxConnPerIP int, maxPeers int, banned *blockedpeers.Manager) *Manager {
if maxConnPerIP < 0 {
panic("maximum connections per IP must not be negative")
}
@ -77,9 +76,17 @@ func NewManager(maxConnPerIP int, maxPeers int64) *Manager {
return &Manager{
maxConnPerIP: maxConnPerIP,
maxPeers: maxPeers,
peers: newPeersMap(),
banned: banned,
}
}
func (m *Manager) RangePeers(f func(key string, value []string) bool) {
m.mutex.Lock()
defer m.mutex.Unlock()
m.peers.Range(f)
}
func (m *Manager) OnConnectCheck(net libp2p_network.Network, conn libp2p_network.Conn) error {
m.mutex.Lock()
defer m.mutex.Unlock()
@ -89,19 +96,11 @@ func (m *Manager) OnConnectCheck(net libp2p_network.Network, conn libp2p_network
return errors.Wrap(err, "failed on get remote ip")
}
value, ok := m.peers.Load(remoteIp)
if !ok {
value = []string{}
}
peers, ok := value.([]string)
if !ok {
return errors.New("peers info type err")
}
peers, _ := m.peers.Load(remoteIp)
// avoid add repeatedly
peerID := conn.RemotePeer().String()
_, ok = find(peers, peerID)
_, ok := find(peers, peerID)
if !ok {
peers = append(peers, peerID)
}
@ -118,11 +117,18 @@ func (m *Manager) OnConnectCheck(net libp2p_network.Network, conn libp2p_network
// only limit addition if it's a new peer and not an existing peer with new connection
if m.maxPeers > 0 && currentPeerCount >= m.maxPeers && !m.peers.HasKey(remoteIp) {
utils.Logger().Warn().
Int64("connected peers", currentPeerCount).
Int("connected peers", currentPeerCount).
Str("new peer", remoteIp).
Msg("too many peers, closing")
return net.ClosePeer(conn.RemotePeer())
}
if m.banned.IsBanned(conn.RemotePeer(), time.Now()) {
utils.Logger().Warn().
Str("new peer", remoteIp).
Msg("peer is banned, closing")
return net.ClosePeer(conn.RemotePeer())
}
m.peers.Store(remoteIp, peers)
return nil
}
@ -136,16 +142,11 @@ func (m *Manager) OnDisconnectCheck(conn libp2p_network.Conn) error {
return errors.Wrap(err, "failed on get ip")
}
value, ok := m.peers.Load(ip)
peers, ok := m.peers.Load(ip)
if !ok {
return nil
}
peers, ok := value.([]string)
if !ok {
return errors.New("peers info type err")
}
peerID := conn.RemotePeer().String()
index, ok := find(peers, peerID)
if ok {

@ -6,6 +6,7 @@ import (
"testing"
"time"
"github.com/harmony-one/harmony/internal/utils/blockedpeers"
"github.com/libp2p/go-libp2p"
ic "github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/host"
@ -13,6 +14,7 @@ import (
"github.com/libp2p/go-libp2p/core/peer"
ma "github.com/multiformats/go-multiaddr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type ConnectCallback func(net libp2p_network.Network, conn libp2p_network.Conn) error
@ -53,11 +55,11 @@ func (mh *fakeHost) SetDisconnectCallback(callback DisconnectCallback) {
func TestManager_OnConnectCheck(t *testing.T) {
h1, err := newPeer(50550)
assert.Nil(t, err)
require.NoError(t, err)
defer h1.Close()
fakeHost := &fakeHost{}
security := NewManager(2, 1)
security := NewManager(2, 1, blockedpeers.NewManager(4))
h1.Network().Notify(fakeHost)
fakeHost.SetConnectCallback(security.OnConnectCheck)
fakeHost.SetDisconnectCallback(security.OnDisconnectCheck)
@ -65,10 +67,9 @@ func TestManager_OnConnectCheck(t *testing.T) {
assert.Nil(t, err)
defer h2.Close()
err = h2.Connect(context.Background(), peer.AddrInfo{ID: h1.ID(), Addrs: h1.Network().ListenAddresses()})
assert.Nil(t, err)
require.NoError(t, err)
security.peers.Range(func(k, v interface{}) bool {
peers := v.([]string)
security.RangePeers(func(k string, peers []string) bool {
assert.Equal(t, 1, len(peers))
return true
})
@ -78,9 +79,8 @@ func TestManager_OnConnectCheck(t *testing.T) {
defer h3.Close()
err = h3.Connect(context.Background(), peer.AddrInfo{ID: h1.ID(), Addrs: h1.Network().ListenAddresses()})
assert.Nil(t, err)
security.peers.Range(func(k, v interface{}) bool {
peers := v.([]string)
assert.Equal(t, 2, len(peers))
security.RangePeers(func(k string, peers []string) bool {
require.Equal(t, 2, len(peers))
return true
})
@ -89,9 +89,8 @@ func TestManager_OnConnectCheck(t *testing.T) {
defer h4.Close()
err = h4.Connect(context.Background(), peer.AddrInfo{ID: h1.ID(), Addrs: h1.Network().ListenAddresses()})
assert.Nil(t, err)
security.peers.Range(func(k, v interface{}) bool {
peers := v.([]string)
assert.Equal(t, 2, len(peers))
security.RangePeers(func(k string, peers []string) bool {
require.Equal(t, 2, len(peers))
return true
})
}
@ -102,7 +101,7 @@ func TestManager_OnDisconnectCheck(t *testing.T) {
defer h1.Close()
fakeHost := &fakeHost{}
security := NewManager(2, 0)
security := NewManager(2, 0, blockedpeers.NewManager(4))
h1.Network().Notify(fakeHost)
fakeHost.SetConnectCallback(security.OnConnectCheck)
fakeHost.SetDisconnectCallback(security.OnDisconnectCheck)
@ -112,8 +111,7 @@ func TestManager_OnDisconnectCheck(t *testing.T) {
err = h2.Connect(context.Background(), peer.AddrInfo{ID: h1.ID(), Addrs: h1.Network().ListenAddresses()})
assert.Nil(t, err)
security.peers.Range(func(k, v interface{}) bool {
peers := v.([]string)
security.RangePeers(func(k string, peers []string) bool {
assert.Equal(t, 1, len(peers))
return true
})
@ -121,8 +119,7 @@ func TestManager_OnDisconnectCheck(t *testing.T) {
err = h2.Network().ClosePeer(h1.ID())
assert.Nil(t, err)
time.Sleep(200 * time.Millisecond)
security.peers.Range(func(k, v interface{}) bool {
peers := v.([]string)
security.RangePeers(func(k string, peers []string) bool {
assert.Equal(t, 0, len(peers))
return true
})

@ -1,12 +1,21 @@
package sync
import (
Bytes "bytes"
"fmt"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/light"
"github.com/ethereum/go-ethereum/trie"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/consensus/engine"
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/types"
shardingconfig "github.com/harmony-one/harmony/internal/configs/sharding"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/internal/utils/keylocker"
"github.com/harmony-one/harmony/p2p/stream/protocols/sync/message"
"github.com/pkg/errors"
)
@ -18,6 +27,10 @@ type chainHelper interface {
getBlocksByHashes(hs []common.Hash) ([]*types.Block, error)
getNodeData(hs []common.Hash) ([][]byte, error)
getReceipts(hs []common.Hash) ([]types.Receipts, error)
getAccountRange(root common.Hash, origin common.Hash, limit common.Hash, bytes uint64) ([]*message.AccountData, [][]byte, error)
getStorageRanges(root common.Hash, accounts []common.Hash, origin common.Hash, limit common.Hash, bytes uint64) ([]*message.StoragesData, [][]byte, error)
getByteCodes(hs []common.Hash, bytes uint64) ([][]byte, error)
getTrieNodes(root common.Hash, paths []*message.TrieNodePathSet, bytes uint64, start time.Time) ([][]byte, error)
}
type chainHelperImpl struct {
@ -182,3 +195,285 @@ func (ch *chainHelperImpl) getReceipts(hs []common.Hash) ([]types.Receipts, erro
}
return receipts, nil
}
// getAccountRangeRequest
func (ch *chainHelperImpl) getAccountRange(root common.Hash, origin common.Hash, limit common.Hash, bytes uint64) ([]*message.AccountData, [][]byte, error) {
if bytes > softResponseLimit {
bytes = softResponseLimit
}
// Retrieve the requested state and bail out if non existent
tr, err := trie.New(trie.StateTrieID(root), ch.chain.TrieDB())
if err != nil {
return nil, nil, err
}
it, err := ch.chain.Snapshots().AccountIterator(root, origin)
if err != nil {
return nil, nil, err
}
// Iterate over the requested range and pile accounts up
var (
accounts []*message.AccountData
size uint64
last common.Hash
)
for it.Next() {
hash, account := it.Hash(), common.CopyBytes(it.Account())
// Track the returned interval for the Merkle proofs
last = hash
// Assemble the reply item
size += uint64(common.HashLength + len(account))
accounts = append(accounts, &message.AccountData{
Hash: hash[:],
Body: account,
})
// If we've exceeded the request threshold, abort
if Bytes.Compare(hash[:], limit[:]) >= 0 {
break
}
if size > bytes {
break
}
}
it.Release()
// Generate the Merkle proofs for the first and last account
proof := light.NewNodeSet()
if err := tr.Prove(origin[:], 0, proof); err != nil {
utils.Logger().Warn().Err(err).Interface("origin", origin).Msg("Failed to prove account range")
return nil, nil, err
}
if last != (common.Hash{}) {
if err := tr.Prove(last[:], 0, proof); err != nil {
utils.Logger().Warn().Err(err).Interface("last", last).Msg("Failed to prove account range")
return nil, nil, err
}
}
var proofs [][]byte
for _, blob := range proof.NodeList() {
proofs = append(proofs, blob)
}
return accounts, proofs, nil
}
// getStorageRangesRequest
func (ch *chainHelperImpl) getStorageRanges(root common.Hash, accounts []common.Hash, origin common.Hash, limit common.Hash, bytes uint64) ([]*message.StoragesData, [][]byte, error) {
if bytes > softResponseLimit {
bytes = softResponseLimit
}
// Calculate the hard limit at which to abort, even if mid storage trie
hardLimit := uint64(float64(bytes) * (1 + stateLookupSlack))
// Retrieve storage ranges until the packet limit is reached
var (
slots []*message.StoragesData
proofs [][]byte
size uint64
)
for _, account := range accounts {
// If we've exceeded the requested data limit, abort without opening
// a new storage range (that we'd need to prove due to exceeded size)
if size >= bytes {
break
}
// The first account might start from a different origin and end sooner
// origin==nil or limit ==nil
// Retrieve the requested state and bail out if non existent
it, err := ch.chain.Snapshots().StorageIterator(root, account, origin)
if err != nil {
return nil, nil, err
}
// Iterate over the requested range and pile slots up
var (
storage []*message.StorageData
last common.Hash
abort bool
)
for it.Next() {
if size >= hardLimit {
abort = true
break
}
hash, slot := it.Hash(), common.CopyBytes(it.Slot())
// Track the returned interval for the Merkle proofs
last = hash
// Assemble the reply item
size += uint64(common.HashLength + len(slot))
storage = append(storage, &message.StorageData{
Hash: hash[:],
Body: slot,
})
// If we've exceeded the request threshold, abort
if Bytes.Compare(hash[:], limit[:]) >= 0 {
break
}
}
if len(storage) > 0 {
storages := &message.StoragesData{
Data: storage,
}
slots = append(slots, storages)
}
it.Release()
// Generate the Merkle proofs for the first and last storage slot, but
// only if the response was capped. If the entire storage trie included
// in the response, no need for any proofs.
if origin != (common.Hash{}) || (abort && len(storage) > 0) {
// Request started at a non-zero hash or was capped prematurely, add
// the endpoint Merkle proofs
accTrie, err := trie.NewStateTrie(trie.StateTrieID(root), ch.chain.TrieDB())
if err != nil {
return nil, nil, err
}
acc, err := accTrie.TryGetAccountByHash(account)
if err != nil || acc == nil {
return nil, nil, err
}
id := trie.StorageTrieID(root, account, acc.Root)
stTrie, err := trie.NewStateTrie(id, ch.chain.TrieDB())
if err != nil {
return nil, nil, err
}
proof := light.NewNodeSet()
if err := stTrie.Prove(origin[:], 0, proof); err != nil {
utils.Logger().Warn().Interface("origin", origin).Msg("Failed to prove storage range")
return nil, nil, err
}
if last != (common.Hash{}) {
if err := stTrie.Prove(last[:], 0, proof); err != nil {
utils.Logger().Warn().Interface("last", last).Msg("Failed to prove storage range")
return nil, nil, err
}
}
for _, blob := range proof.NodeList() {
proofs = append(proofs, blob)
}
// Proof terminates the reply as proofs are only added if a node
// refuses to serve more data (exception when a contract fetch is
// finishing, but that's that).
break
}
}
return slots, proofs, nil
}
// getByteCodesRequest
func (ch *chainHelperImpl) getByteCodes(hashes []common.Hash, bytes uint64) ([][]byte, error) {
if bytes > softResponseLimit {
bytes = softResponseLimit
}
if len(hashes) > maxCodeLookups {
hashes = hashes[:maxCodeLookups]
}
// Retrieve bytecodes until the packet size limit is reached
var (
codes [][]byte
totalBytes uint64
)
for _, hash := range hashes {
if hash == state.EmptyCodeHash {
// Peers should not request the empty code, but if they do, at
// least sent them back a correct response without db lookups
codes = append(codes, []byte{})
} else if blob, err := ch.chain.ContractCode(hash); err == nil { // Double Check: ContractCodeWithPrefix
codes = append(codes, blob)
totalBytes += uint64(len(blob))
}
if totalBytes > bytes {
break
}
}
return codes, nil
}
// getTrieNodesRequest
func (ch *chainHelperImpl) getTrieNodes(root common.Hash, paths []*message.TrieNodePathSet, bytes uint64, start time.Time) ([][]byte, error) {
if bytes > softResponseLimit {
bytes = softResponseLimit
}
// Make sure we have the state associated with the request
triedb := ch.chain.TrieDB()
accTrie, err := trie.NewStateTrie(trie.StateTrieID(root), triedb)
if err != nil {
// We don't have the requested state available, bail out
return nil, nil
}
// The 'snap' might be nil, in which case we cannot serve storage slots.
snap := ch.chain.Snapshots().Snapshot(root)
// Retrieve trie nodes until the packet size limit is reached
var (
nodes [][]byte
TotalBytes uint64
loads int // Trie hash expansions to count database reads
)
for _, p := range paths {
switch len(p.Pathset) {
case 0:
// Ensure we penalize invalid requests
return nil, fmt.Errorf("zero-item pathset requested")
case 1:
// If we're only retrieving an account trie node, fetch it directly
blob, resolved, err := accTrie.TryGetNode(p.Pathset[0])
loads += resolved // always account database reads, even for failures
if err != nil {
break
}
nodes = append(nodes, blob)
TotalBytes += uint64(len(blob))
default:
var stRoot common.Hash
// Storage slots requested, open the storage trie and retrieve from there
if snap == nil {
// We don't have the requested state snapshotted yet (or it is stale),
// but can look up the account via the trie instead.
account, err := accTrie.TryGetAccountByHash(common.BytesToHash(p.Pathset[0]))
loads += 8 // We don't know the exact cost of lookup, this is an estimate
if err != nil || account == nil {
break
}
stRoot = account.Root
} else {
account, err := snap.Account(common.BytesToHash(p.Pathset[0]))
loads++ // always account database reads, even for failures
if err != nil || account == nil {
break
}
stRoot = common.BytesToHash(account.Root)
}
id := trie.StorageTrieID(root, common.BytesToHash(p.Pathset[0]), stRoot)
stTrie, err := trie.NewStateTrie(id, triedb)
loads++ // always account database reads, even for failures
if err != nil {
break
}
for _, path := range p.Pathset[1:] {
blob, resolved, err := stTrie.TryGetNode(path)
loads += resolved // always account database reads, even for failures
if err != nil {
break
}
nodes = append(nodes, blob)
TotalBytes += uint64(len(blob))
// Sanity check limits to avoid DoS on the store trie loads
if TotalBytes > bytes || loads > maxTrieNodeLookups || time.Since(start) > maxTrieNodeTimeSpent {
break
}
}
}
// Abort request processing if we've exceeded our limits
if TotalBytes > bytes || loads > maxTrieNodeLookups || time.Since(start) > maxTrieNodeTimeSpent {
break
}
}
return nodes, nil
}

@ -6,12 +6,15 @@ import (
"errors"
"fmt"
"math/big"
"time"
"unsafe"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rlp"
protobuf "github.com/golang/protobuf/proto"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/p2p/stream/protocols/sync/message"
syncpb "github.com/harmony-one/harmony/p2p/stream/protocols/sync/message"
)
@ -60,6 +63,26 @@ func (tch *testChainHelper) getReceipts(hs []common.Hash) ([]types.Receipts, err
return receipts, nil
}
func (ch *testChainHelper) getAccountRange(root common.Hash, origin common.Hash, limit common.Hash, bytes uint64) ([]*message.AccountData, [][]byte, error) {
testAccountRanges, testProofs := makeTestAccountRanges(2)
return testAccountRanges, testProofs, nil
}
func (ch *testChainHelper) getStorageRanges(root common.Hash, accounts []common.Hash, origin common.Hash, limit common.Hash, bytes uint64) ([]*message.StoragesData, [][]byte, error) {
testSlots, testProofs := makeTestStorageRanges(2)
return testSlots, testProofs, nil
}
func (ch *testChainHelper) getByteCodes(hs []common.Hash, bytes uint64) ([][]byte, error) {
testByteCodes := makeTestByteCodes(2)
return testByteCodes, nil
}
func (ch *testChainHelper) getTrieNodes(root common.Hash, paths []*message.TrieNodePathSet, bytes uint64, start time.Time) ([][]byte, error) {
testTrieNodes := makeTestTrieNodes(2)
return testTrieNodes, nil
}
func checkGetReceiptsResult(b []byte, hs []common.Hash) error {
var msg = &syncpb.Message{}
if err := protobuf.Unmarshal(b, msg); err != nil {
@ -156,6 +179,57 @@ func makeTestReceipts(n int, nPerBlock int) []*types.Receipt {
return receipts
}
func makeTestAccountRanges(n int) ([]*message.AccountData, [][]byte) {
accounts := make([]*message.AccountData, n)
proofs := make([][]byte, n)
for i := 0; i < n; i++ {
accounts[i] = &message.AccountData{
Hash: numberToHash(uint64(i * 2)).Bytes(),
Body: numberToHash(uint64(i*2 + 1)).Bytes(),
}
}
for i := 0; i < n; i++ {
proofs[i] = numberToHash(uint64(i)).Bytes()
}
return accounts, proofs
}
func makeTestStorageRanges(n int) ([]*message.StoragesData, [][]byte) {
slots := make([]*message.StoragesData, n)
proofs := make([][]byte, n)
for i := 0; i < n; i++ {
slots[i] = &message.StoragesData{
Data: make([]*syncpb.StorageData, 2),
}
for j := 0; j < 2; j++ {
slots[i].Data[j] = &message.StorageData{
Hash: numberToHash(uint64(i * 2)).Bytes(),
Body: numberToHash(uint64(i*2 + 1)).Bytes(),
}
}
}
for i := 0; i < n; i++ {
proofs[i] = numberToHash(uint64(i)).Bytes()
}
return slots, proofs
}
func makeTestByteCodes(n int) [][]byte {
byteCodes := make([][]byte, n)
for i := 0; i < n; i++ {
byteCodes[i] = numberToHash(uint64(i)).Bytes()
}
return byteCodes
}
func makeTestTrieNodes(n int) [][]byte {
trieNodes := make([][]byte, n)
for i := 0; i < n; i++ {
trieNodes[i] = numberToHash(uint64(i)).Bytes()
}
return trieNodes
}
func decodeBlocksBytes(bbs [][]byte) ([]*types.Block, error) {
blocks := make([]*types.Block, 0, len(bbs))
@ -169,6 +243,19 @@ func decodeBlocksBytes(bbs [][]byte) ([]*types.Block, error) {
return blocks, nil
}
func decodeHashBytes(hs [][]byte) ([]common.Hash, error) {
hashes := make([]common.Hash, 0)
for _, h := range hs {
var hash common.Hash
if err := rlp.DecodeBytes(h, &hash); err != nil {
return nil, err
}
hashes = append(hashes, hash)
}
return hashes, nil
}
func checkBlockNumberResult(b []byte) error {
var msg = &syncpb.Message{}
if err := protobuf.Unmarshal(b, msg); err != nil {
@ -230,3 +317,90 @@ func checkBlocksByHashesResult(b []byte, hs []common.Hash) error {
}
return nil
}
func checkAccountRangeResult(bytes uint64, b []byte) error {
var msg = &syncpb.Message{}
if err := protobuf.Unmarshal(b, msg); err != nil {
return err
}
gbResp, err := msg.GetAccountRangesResponse()
if err != nil {
return err
}
if len(gbResp.Accounts) == 0 {
return errors.New("nil response from GetAccountRanges")
}
if len(gbResp.Proof) != len(gbResp.Accounts) {
return errors.New("unexpected proofs")
}
if len(b) > int(bytes) {
return errors.New("unexpected data bytes")
}
return nil
}
func checkStorageRangesResult(accounts []common.Hash, bytes uint64, b []byte) error {
var msg = &syncpb.Message{}
if err := protobuf.Unmarshal(b, msg); err != nil {
return err
}
gbResp, err := msg.GetStorageRangesResponse()
if err != nil {
return err
}
if len(gbResp.Slots) == 0 {
return errors.New("nil response from GetStorageRanges")
}
if len(gbResp.Slots) != len(gbResp.Proof) {
return errors.New("unexpected proofs")
}
sz := unsafe.Sizeof(gbResp.Slots)
if sz > uintptr(bytes) {
return errors.New("unexpected slot bytes")
}
return nil
}
func checkByteCodesResult(hs []common.Hash, bytes uint64, b []byte) error {
var msg = &syncpb.Message{}
if err := protobuf.Unmarshal(b, msg); err != nil {
return err
}
gbResp, err := msg.GetByteCodesResponse()
if err != nil {
return err
}
if len(gbResp.Codes) == 0 {
return errors.New("nil response from GetByteCodes")
}
if len(gbResp.Codes) != len(hs) {
return errors.New("unexpected byte codes")
}
sz := len(hs) * common.HashLength
if sz > int(bytes) {
return errors.New("unexpected data bytes")
}
return nil
}
func checkTrieNodesResult(hs []common.Hash, bytes uint64, b []byte) error {
var msg = &syncpb.Message{}
if err := protobuf.Unmarshal(b, msg); err != nil {
return err
}
gbResp, err := msg.GetTrieNodesResponse()
if err != nil {
return err
}
if len(gbResp.Nodes) == 0 {
return errors.New("nil response from checkGetTrieNodes")
}
if len(gbResp.Nodes) != len(hs) {
return errors.New("unexpected byte codes")
}
sz := len(hs) * common.HashLength
if sz > int(bytes) {
return errors.New("unexpected data bytes")
}
return nil
}

@ -10,6 +10,7 @@ import (
"github.com/ethereum/go-ethereum/rlp"
protobuf "github.com/golang/protobuf/proto"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/p2p/stream/protocols/sync/message"
syncpb "github.com/harmony-one/harmony/p2p/stream/protocols/sync/message"
sttypes "github.com/harmony-one/harmony/p2p/stream/types"
"github.com/pkg/errors"
@ -181,6 +182,120 @@ func (p *Protocol) GetNodeData(ctx context.Context, hs []common.Hash, opts ...Op
return
}
// GetAccountRange do getAccountRange through sync stream protocol.
// returns the accounts along with proofs as result, target stream id, and error
func (p *Protocol) GetAccountRange(ctx context.Context, root common.Hash, origin common.Hash, limit common.Hash, bytes uint64, opts ...Option) (accounts []*message.AccountData, proof []common.Hash, stid sttypes.StreamID, err error) {
timer := p.doMetricClientRequest("getAccountRange")
defer p.doMetricPostClientRequest("getAccountRange", err, timer)
if bytes == 0 {
err = fmt.Errorf("zero account ranges bytes requested")
return
}
if bytes > softResponseLimit {
err = fmt.Errorf("requested bytes exceed limit")
return
}
req := newGetAccountRangeRequest(root, origin, limit, bytes)
resp, stid, err := p.rm.DoRequest(ctx, req, opts...)
if err != nil {
return
}
accounts, proof, err = req.getAccountRangeFromResponse(resp)
return
}
// GetStorageRanges do getStorageRanges through sync stream protocol.
// returns the slots along with proofs as result, target stream id, and error
func (p *Protocol) GetStorageRanges(ctx context.Context, root common.Hash, accounts []common.Hash, origin common.Hash, limit common.Hash, bytes uint64, opts ...Option) (slots []*message.StorageData, proof []common.Hash, stid sttypes.StreamID, err error) {
timer := p.doMetricClientRequest("getStorageRanges")
defer p.doMetricPostClientRequest("getStorageRanges", err, timer)
if bytes == 0 {
err = fmt.Errorf("zero storage ranges bytes requested")
return
}
if bytes > softResponseLimit {
err = fmt.Errorf("requested bytes exceed limit")
return
}
if len(accounts) > GetStorageRangesRequestCap {
err = fmt.Errorf("number of requested accounts exceed limit")
return
}
req := newGetStorageRangesRequest(root, accounts, origin, limit, bytes)
resp, stid, err := p.rm.DoRequest(ctx, req, opts...)
if err != nil {
return
}
var storages []*message.StoragesData
storages, proof, err = req.getStorageRangesFromResponse(resp)
if err != nil {
return
}
slots = make([]*message.StorageData, 0)
for _, storage := range storages {
for _, data := range storage.Data {
slots = append(slots, data)
}
}
return
}
// GetByteCodes do getByteCodes through sync stream protocol.
// returns the codes as result, target stream id, and error
func (p *Protocol) GetByteCodes(ctx context.Context, hs []common.Hash, bytes uint64, opts ...Option) (codes [][]byte, stid sttypes.StreamID, err error) {
timer := p.doMetricClientRequest("getByteCodes")
defer p.doMetricPostClientRequest("getByteCodes", err, timer)
if bytes == 0 {
err = fmt.Errorf("zero bytecode bytes requested")
return
}
if bytes > softResponseLimit {
err = fmt.Errorf("requested bytes exceed limit")
return
}
if len(hs) > GetByteCodesRequestCap {
err = fmt.Errorf("number of requested hashes exceed limit")
return
}
req := newGetByteCodesRequest(hs, bytes)
resp, stid, err := p.rm.DoRequest(ctx, req, opts...)
if err != nil {
return
}
codes, err = req.getByteCodesFromResponse(resp)
return
}
// GetTrieNodes do getTrieNodes through sync stream protocol.
// returns the nodes as result, target stream id, and error
func (p *Protocol) GetTrieNodes(ctx context.Context, root common.Hash, paths []*message.TrieNodePathSet, bytes uint64, opts ...Option) (nodes [][]byte, stid sttypes.StreamID, err error) {
timer := p.doMetricClientRequest("getTrieNodes")
defer p.doMetricPostClientRequest("getTrieNodes", err, timer)
if bytes == 0 {
err = fmt.Errorf("zero trie nodes bytes requested")
return
}
if bytes > softResponseLimit {
err = fmt.Errorf("requested bytes exceed limit")
return
}
if len(paths) > GetTrieNodesRequestCap {
err = fmt.Errorf("number of requested paths exceed limit")
return
}
req := newGetTrieNodesRequest(root, paths, bytes)
resp, stid, err := p.rm.DoRequest(ctx, req, opts...)
if err != nil {
return
}
nodes, err = req.getTrieNodesFromResponse(resp)
return
}
// getBlocksByNumberRequest is the request for get block by numbers which implements
// sttypes.Request interface
type getBlocksByNumberRequest struct {
@ -571,3 +686,305 @@ func (req *getReceiptsRequest) parseGetReceiptsBytes(resp *syncResponse) ([]type
}
return receipts, nil
}
// getAccountRangeRequest is the request for get account ranges which implements
// sttypes.Request interface
type getAccountRangeRequest struct {
root common.Hash
origin common.Hash
limit common.Hash
bytes uint64
pbReq *syncpb.Request
}
func newGetAccountRangeRequest(root common.Hash, origin common.Hash, limit common.Hash, bytes uint64) *getAccountRangeRequest {
pbReq := syncpb.MakeGetAccountRangeRequest(root, origin, limit, bytes)
return &getAccountRangeRequest{
root: root,
origin: origin,
limit: limit,
bytes: bytes,
pbReq: pbReq,
}
}
func (req *getAccountRangeRequest) ReqID() uint64 {
return req.pbReq.GetReqId()
}
func (req *getAccountRangeRequest) SetReqID(val uint64) {
req.pbReq.ReqId = val
}
func (req *getAccountRangeRequest) String() string {
ss := make([]string, 0, 4)
ss = append(ss, req.root.String())
ss = append(ss, req.origin.String())
ss = append(ss, req.limit.String())
ss = append(ss, fmt.Sprint(req.bytes))
rqStr := strings.Join(ss, ",")
return fmt.Sprintf("REQUEST [GetAccountRange: %s]", rqStr)
}
func (req *getAccountRangeRequest) IsSupportedByProto(target sttypes.ProtoSpec) bool {
return target.Version.GreaterThanOrEqual(MinVersion)
}
func (req *getAccountRangeRequest) Encode() ([]byte, error) {
msg := syncpb.MakeMessageFromRequest(req.pbReq)
return protobuf.Marshal(msg)
}
// []*message.AccountData, []common.Hash
func (req *getAccountRangeRequest) getAccountRangeFromResponse(resp sttypes.Response) ([]*message.AccountData, []common.Hash, error) {
sResp, ok := resp.(*syncResponse)
if !ok || sResp == nil {
return nil, nil, errors.New("not sync response")
}
return req.parseGetAccountRangeResponse(sResp)
}
func (req *getAccountRangeRequest) parseGetAccountRangeResponse(resp *syncResponse) ([]*message.AccountData, []common.Hash, error) {
if errResp := resp.pb.GetErrorResponse(); errResp != nil {
return nil, nil, errors.New(errResp.Error)
}
grResp := resp.pb.GetGetAccountRangeResponse()
if grResp == nil {
return nil, nil, errors.New("response not GetAccountRange")
}
proofs := make([]common.Hash, 0)
for _, proofBytes := range grResp.Proof {
var proof common.Hash
if err := rlp.DecodeBytes(proofBytes, &proof); err != nil {
return nil, nil, errors.Wrap(err, "[GetAccountRangeResponse]")
}
proofs = append(proofs, proof)
}
return grResp.Accounts, proofs, nil
}
// getStorageRangesRequest is the request for get storage ranges which implements
// sttypes.Request interface
type getStorageRangesRequest struct {
root common.Hash
accounts []common.Hash
origin common.Hash
limit common.Hash
bytes uint64
pbReq *syncpb.Request
}
func newGetStorageRangesRequest(root common.Hash, accounts []common.Hash, origin common.Hash, limit common.Hash, bytes uint64) *getStorageRangesRequest {
pbReq := syncpb.MakeGetStorageRangesRequest(root, accounts, origin, limit, bytes)
return &getStorageRangesRequest{
root: root,
accounts: accounts,
origin: origin,
limit: limit,
bytes: bytes,
pbReq: pbReq,
}
}
func (req *getStorageRangesRequest) ReqID() uint64 {
return req.pbReq.GetReqId()
}
func (req *getStorageRangesRequest) SetReqID(val uint64) {
req.pbReq.ReqId = val
}
func (req *getStorageRangesRequest) String() string {
ss := make([]string, 0, 4)
ss = append(ss, req.root.String())
for _, acc := range req.accounts {
ss = append(ss, acc.String())
}
ss = append(ss, req.origin.String())
ss = append(ss, req.limit.String())
ss = append(ss, fmt.Sprint(req.bytes))
rqStr := strings.Join(ss, ",")
return fmt.Sprintf("REQUEST [GetStorageRanges: %s]", rqStr)
}
func (req *getStorageRangesRequest) IsSupportedByProto(target sttypes.ProtoSpec) bool {
return target.Version.GreaterThanOrEqual(MinVersion)
}
func (req *getStorageRangesRequest) Encode() ([]byte, error) {
msg := syncpb.MakeMessageFromRequest(req.pbReq)
return protobuf.Marshal(msg)
}
// []*message.AccountData, []common.Hash
func (req *getStorageRangesRequest) getStorageRangesFromResponse(resp sttypes.Response) ([]*message.StoragesData, []common.Hash, error) {
sResp, ok := resp.(*syncResponse)
if !ok || sResp == nil {
return nil, nil, errors.New("not sync response")
}
return req.parseGetStorageRangesResponse(sResp)
}
func (req *getStorageRangesRequest) parseGetStorageRangesResponse(resp *syncResponse) ([]*message.StoragesData, []common.Hash, error) {
if errResp := resp.pb.GetErrorResponse(); errResp != nil {
return nil, nil, errors.New(errResp.Error)
}
grResp := resp.pb.GetGetStorageRangesResponse()
if grResp == nil {
return nil, nil, errors.New("response not GetStorageRanges")
}
proofs := make([]common.Hash, 0)
for _, proofBytes := range grResp.Proof {
var proof common.Hash
if err := rlp.DecodeBytes(proofBytes, &proof); err != nil {
return nil, nil, errors.Wrap(err, "[GetStorageRangesResponse]")
}
proofs = append(proofs, proof)
}
return grResp.Slots, proofs, nil
}
// getByteCodesRequest is the request for get code bytes which implements
// sttypes.Request interface
type getByteCodesRequest struct {
hashes []common.Hash
bytes uint64
pbReq *syncpb.Request
}
func newGetByteCodesRequest(hashes []common.Hash, bytes uint64) *getByteCodesRequest {
pbReq := syncpb.MakeGetByteCodesRequest(hashes, bytes)
return &getByteCodesRequest{
hashes: hashes,
bytes: bytes,
pbReq: pbReq,
}
}
func (req *getByteCodesRequest) ReqID() uint64 {
return req.pbReq.GetReqId()
}
func (req *getByteCodesRequest) SetReqID(val uint64) {
req.pbReq.ReqId = val
}
func (req *getByteCodesRequest) String() string {
ss := make([]string, 0, 4)
for _, h := range req.hashes {
ss = append(ss, h.String())
}
ss = append(ss, fmt.Sprint(req.bytes))
rqStr := strings.Join(ss, ",")
return fmt.Sprintf("REQUEST [GetByteCodes: %s]", rqStr)
}
func (req *getByteCodesRequest) IsSupportedByProto(target sttypes.ProtoSpec) bool {
return target.Version.GreaterThanOrEqual(MinVersion)
}
func (req *getByteCodesRequest) Encode() ([]byte, error) {
msg := syncpb.MakeMessageFromRequest(req.pbReq)
return protobuf.Marshal(msg)
}
func (req *getByteCodesRequest) getByteCodesFromResponse(resp sttypes.Response) ([][]byte, error) {
sResp, ok := resp.(*syncResponse)
if !ok || sResp == nil {
return nil, errors.New("not sync response")
}
return req.parseGetByteCodesResponse(sResp)
}
func (req *getByteCodesRequest) parseGetByteCodesResponse(resp *syncResponse) ([][]byte, error) {
if errResp := resp.pb.GetErrorResponse(); errResp != nil {
return nil, errors.New(errResp.Error)
}
grResp := resp.pb.GetGetByteCodesResponse()
if grResp == nil {
return nil, errors.New("response not GetByteCodes")
}
codes := make([][]byte, 0)
for _, codeBytes := range grResp.Codes {
var code []byte
if err := rlp.DecodeBytes(codeBytes, &code); err != nil {
return nil, errors.Wrap(err, "[GetByteCodesResponse]")
}
codes = append(codes, code)
}
return codes, nil
}
// getTrieNodesRequest is the request for get trie nodes which implements
// sttypes.Request interface
type getTrieNodesRequest struct {
root common.Hash
paths []*message.TrieNodePathSet
bytes uint64
pbReq *syncpb.Request
}
func newGetTrieNodesRequest(root common.Hash, paths []*message.TrieNodePathSet, bytes uint64) *getTrieNodesRequest {
pbReq := syncpb.MakeGetTrieNodesRequest(root, paths, bytes)
return &getTrieNodesRequest{
root: root,
paths: paths,
bytes: bytes,
pbReq: pbReq,
}
}
func (req *getTrieNodesRequest) ReqID() uint64 {
return req.pbReq.GetReqId()
}
func (req *getTrieNodesRequest) SetReqID(val uint64) {
req.pbReq.ReqId = val
}
func (req *getTrieNodesRequest) String() string {
ss := make([]string, 0, 4)
ss = append(ss, req.root.String())
for _, p := range req.paths {
ss = append(ss, p.String())
}
ss = append(ss, fmt.Sprint(req.bytes))
rqStr := strings.Join(ss, ",")
return fmt.Sprintf("REQUEST [GetTrieNodes: %s]", rqStr)
}
func (req *getTrieNodesRequest) IsSupportedByProto(target sttypes.ProtoSpec) bool {
return target.Version.GreaterThanOrEqual(MinVersion)
}
func (req *getTrieNodesRequest) Encode() ([]byte, error) {
msg := syncpb.MakeMessageFromRequest(req.pbReq)
return protobuf.Marshal(msg)
}
func (req *getTrieNodesRequest) getTrieNodesFromResponse(resp sttypes.Response) ([][]byte, error) {
sResp, ok := resp.(*syncResponse)
if !ok || sResp == nil {
return nil, errors.New("not sync response")
}
return req.parseGetTrieNodesResponse(sResp)
}
func (req *getTrieNodesRequest) parseGetTrieNodesResponse(resp *syncResponse) ([][]byte, error) {
if errResp := resp.pb.GetErrorResponse(); errResp != nil {
return nil, errors.New(errResp.Error)
}
grResp := resp.pb.GetGetTrieNodesResponse()
if grResp == nil {
return nil, errors.New("response not GetTrieNodes")
}
nodes := make([][]byte, 0)
for _, codeBytes := range grResp.Nodes {
var code []byte
if err := rlp.DecodeBytes(codeBytes, &code); err != nil {
return nil, errors.Wrap(err, "[GetTrieNodesResponse]")
}
nodes = append(nodes, code)
}
return nodes, nil
}

@ -25,6 +25,8 @@ var (
_ sttypes.Request = &getBlockNumberRequest{}
_ sttypes.Request = &getReceiptsRequest{}
_ sttypes.Response = &syncResponse{&syncpb.Response{}}
// MaxHash represents the maximum possible hash value.
MaxHash = common.HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")
)
var (
@ -67,6 +69,69 @@ var (
testNodeDataResponse = syncpb.MakeGetNodeDataResponse(0, [][]byte{testNodeDataBytes})
account1 = common.HexToHash("0xf493f79c43bd747129a226ad42529885a4b108aba6046b2d12071695a6627844")
account2 = common.HexToHash("0xf493f79c43bd747129a226ad42529885a4b108aba6046b2d12071695a6627844")
resAccounts = []common.Hash{account1, account2}
accountsData = []*message.AccountData{
&syncpb.AccountData{
Hash: account1[:],
Body: common.HexToHash("0x00bf100000000000000000000000000000000000000000000000000000000000").Bytes(),
},
&syncpb.AccountData{
Hash: account2[:],
Body: common.HexToHash("0x00bf100000000000000000000000000000000000000000000000000000000000").Bytes(),
},
}
slots = []*syncpb.StoragesData{
&syncpb.StoragesData{
Data: []*syncpb.StorageData{
&syncpb.StorageData{
Hash: account1[:],
Body: common.HexToHash("0x00bf100000000000000000000000000000000000000000000000000000000000").Bytes(),
},
},
},
&syncpb.StoragesData{
Data: []*syncpb.StorageData{
&syncpb.StorageData{
Hash: account2[:],
Body: common.HexToHash("0x00bf100000000000000000000000000000000000000000000000000000000000").Bytes(),
},
},
},
}
proofBytes1, _ = rlp.EncodeToBytes(account1)
proofBytes2, _ = rlp.EncodeToBytes(account2)
proof = [][]byte{proofBytes1, proofBytes2}
codeBytes1, _ = rlp.EncodeToBytes(account1)
codeBytes2, _ = rlp.EncodeToBytes(account2)
testByteCodes = [][]byte{codeBytes1, codeBytes2}
dataNodeBytes1, _ = rlp.EncodeToBytes(numberToHash(1).Bytes())
dataNodeBytes2, _ = rlp.EncodeToBytes(numberToHash(2).Bytes())
testTrieNodes = [][]byte{dataNodeBytes1, dataNodeBytes2}
testPathSet = [][]byte{numberToHash(19850928).Bytes(), numberToHash(13640607).Bytes()}
testPaths = []*syncpb.TrieNodePathSet{
&syncpb.TrieNodePathSet{
Pathset: testPathSet,
},
&syncpb.TrieNodePathSet{
Pathset: testPathSet,
},
}
testAccountRangeResponse = syncpb.MakeGetAccountRangeResponse(0, accountsData, proof)
testStorageRangesResponse = syncpb.MakeGetStorageRangesResponse(0, slots, proof)
testByteCodesResponse = syncpb.MakeGetByteCodesResponse(0, testByteCodes)
testTrieNodesResponse = syncpb.MakeGetTrieNodesResponse(0, testTrieNodes)
testErrorResponse = syncpb.MakeErrorResponse(0, errors.New("test error"))
)
@ -428,6 +493,267 @@ func TestProtocol_GetNodeData(t *testing.T) {
}
}
func TestProtocol_GetAccountRange(t *testing.T) {
var (
root = numberToHash(1985082913640607)
ffHash = MaxHash
zero = common.Hash{}
)
tests := []struct {
getResponse getResponseFn
expErr error
expStID sttypes.StreamID
}{
{
getResponse: func(request sttypes.Request) (sttypes.Response, sttypes.StreamID) {
return &syncResponse{
pb: testAccountRangeResponse,
}, makeTestStreamID(0)
},
expErr: nil,
expStID: makeTestStreamID(0),
},
{
getResponse: func(request sttypes.Request) (sttypes.Response, sttypes.StreamID) {
return &syncResponse{
pb: testBlockResponse,
}, makeTestStreamID(0)
},
expErr: errors.New("response not GetAccountRange"),
expStID: makeTestStreamID(0),
},
{
getResponse: nil,
expErr: errors.New("get response error"),
expStID: "",
},
{
getResponse: func(request sttypes.Request) (sttypes.Response, sttypes.StreamID) {
return &syncResponse{
pb: testErrorResponse,
}, makeTestStreamID(0)
},
expErr: errors.New("test error"),
expStID: makeTestStreamID(0),
},
}
for i, test := range tests {
protocol := makeTestProtocol(test.getResponse)
accounts, proof, stid, err := protocol.GetAccountRange(context.Background(), root, zero, ffHash, uint64(100))
if assErr := assertError(err, test.expErr); assErr != nil {
t.Errorf("Test %v: %v", i, assErr)
continue
}
if stid != test.expStID {
t.Errorf("Test %v: unexpected st id: %v / %v", i, stid, test.expStID)
}
if test.expErr == nil {
if len(accounts) != len(proof) {
t.Errorf("accounts: %v", test.getResponse)
t.Errorf("accounts: %v", accounts)
t.Errorf("proof: %v", proof)
t.Errorf("Test %v: accounts size (%d) not equal to proof size (%d)", i, len(accounts), len(proof))
}
}
}
}
func TestProtocol_GetStorageRanges(t *testing.T) {
var (
root = numberToHash(1985082913640607)
firstKey = common.HexToHash("0x00bf49f440a1cd0527e4d06e2765654c0f56452257516d793a9b8d604dcfdf2a")
secondKey = common.HexToHash("0x09e47cd5056a689e708f22fe1f932709a320518e444f5f7d8d46a3da523d6606")
testAccounts = []common.Hash{secondKey, firstKey}
ffHash = MaxHash
zero = common.Hash{}
)
tests := []struct {
getResponse getResponseFn
expErr error
expStID sttypes.StreamID
}{
{
getResponse: func(request sttypes.Request) (sttypes.Response, sttypes.StreamID) {
return &syncResponse{
pb: testStorageRangesResponse,
}, makeTestStreamID(0)
},
expErr: nil,
expStID: makeTestStreamID(0),
},
{
getResponse: func(request sttypes.Request) (sttypes.Response, sttypes.StreamID) {
return &syncResponse{
pb: testBlockResponse,
}, makeTestStreamID(0)
},
expErr: errors.New("response not GetStorageRanges"),
expStID: makeTestStreamID(0),
},
{
getResponse: nil,
expErr: errors.New("get response error"),
expStID: "",
},
{
getResponse: func(request sttypes.Request) (sttypes.Response, sttypes.StreamID) {
return &syncResponse{
pb: testErrorResponse,
}, makeTestStreamID(0)
},
expErr: errors.New("test error"),
expStID: makeTestStreamID(0),
},
}
for i, test := range tests {
protocol := makeTestProtocol(test.getResponse)
slots, proof, stid, err := protocol.GetStorageRanges(context.Background(), root, testAccounts, zero, ffHash, uint64(100))
if assErr := assertError(err, test.expErr); assErr != nil {
t.Errorf("Test %v: %v", i, assErr)
continue
}
if stid != test.expStID {
t.Errorf("Test %v: unexpected st id: %v / %v", i, stid, test.expStID)
}
if test.expErr == nil {
if len(slots) != len(testAccounts) {
t.Errorf("Test %v: slots size not equal to accounts size", i)
}
if len(slots) != len(proof) {
t.Errorf("Test %v: account size not equal to proof", i)
}
}
}
}
func TestProtocol_GetByteCodes(t *testing.T) {
tests := []struct {
getResponse getResponseFn
expErr error
expStID sttypes.StreamID
}{
{
getResponse: func(request sttypes.Request) (sttypes.Response, sttypes.StreamID) {
return &syncResponse{
pb: testByteCodesResponse,
}, makeTestStreamID(0)
},
expErr: nil,
expStID: makeTestStreamID(0),
},
{
getResponse: func(request sttypes.Request) (sttypes.Response, sttypes.StreamID) {
return &syncResponse{
pb: testBlockResponse,
}, makeTestStreamID(0)
},
expErr: errors.New("response not GetByteCodes"),
expStID: makeTestStreamID(0),
},
{
getResponse: nil,
expErr: errors.New("get response error"),
expStID: "",
},
{
getResponse: func(request sttypes.Request) (sttypes.Response, sttypes.StreamID) {
return &syncResponse{
pb: testErrorResponse,
}, makeTestStreamID(0)
},
expErr: errors.New("test error"),
expStID: makeTestStreamID(0),
},
}
for i, test := range tests {
protocol := makeTestProtocol(test.getResponse)
codes, stid, err := protocol.GetByteCodes(context.Background(), []common.Hash{numberToHash(19850829)}, uint64(500))
if assErr := assertError(err, test.expErr); assErr != nil {
t.Errorf("Test %v: %v", i, assErr)
continue
}
if stid != test.expStID {
t.Errorf("Test %v: unexpected st id: %v / %v", i, stid, test.expStID)
}
if test.expErr == nil {
if len(codes) != 2 {
t.Errorf("Test %v: size not 2", i)
}
}
}
}
func TestProtocol_GetTrieNodes(t *testing.T) {
var (
root = numberToHash(1985082913640607)
)
tests := []struct {
getResponse getResponseFn
expErr error
expStID sttypes.StreamID
}{
{
getResponse: func(request sttypes.Request) (sttypes.Response, sttypes.StreamID) {
return &syncResponse{
pb: testTrieNodesResponse,
}, makeTestStreamID(0)
},
expErr: nil,
expStID: makeTestStreamID(0),
},
{
getResponse: func(request sttypes.Request) (sttypes.Response, sttypes.StreamID) {
return &syncResponse{
pb: testBlockResponse,
}, makeTestStreamID(0)
},
expErr: errors.New("response not GetTrieNodes"),
expStID: makeTestStreamID(0),
},
{
getResponse: nil,
expErr: errors.New("get response error"),
expStID: "",
},
{
getResponse: func(request sttypes.Request) (sttypes.Response, sttypes.StreamID) {
return &syncResponse{
pb: testErrorResponse,
}, makeTestStreamID(0)
},
expErr: errors.New("test error"),
expStID: makeTestStreamID(0),
},
}
for i, test := range tests {
protocol := makeTestProtocol(test.getResponse)
nodes, stid, err := protocol.GetTrieNodes(context.Background(), root, testPaths, uint64(500))
if assErr := assertError(err, test.expErr); assErr != nil {
t.Errorf("Test %v: %v", i, assErr)
continue
}
if stid != test.expStID {
t.Errorf("Test %v: unexpected st id: %v / %v", i, stid, test.expStID)
}
if test.expErr == nil {
if len(nodes) != 2 {
t.Errorf("Test %v: size not 2", i)
}
}
}
}
type getResponseFn func(request sttypes.Request) (sttypes.Response, sttypes.StreamID)
type testHostRequestManager struct {

@ -25,6 +25,39 @@ const (
// This number has an effect on maxMsgBytes as 20MB defined in github.com/harmony-one/harmony/p2p/stream/types.
GetReceiptsCap = 128
// GetStorageRangesRequestCap is the cap of request of single GetStorageRanges request
// This number has an effect on maxMsgBytes as 20MB defined in github.com/harmony-one/harmony/p2p/stream/types.
GetStorageRangesRequestCap = 256
// GetByteCodesRequestCap is the cap of request of single GetByteCodes request
// This number has an effect on maxMsgBytes as 20MB defined in github.com/harmony-one/harmony/p2p/stream/types.
GetByteCodesRequestCap = 128
// GetTrieNodesRequestCap is the cap of request of single GetTrieNodes request
// This number has an effect on maxMsgBytes as 20MB defined in github.com/harmony-one/harmony/p2p/stream/types.
GetTrieNodesRequestCap = 128
// stateLookupSlack defines the ratio by how much a state response can exceed
// the requested limit in order to try and avoid breaking up contracts into
// multiple packages and proving them.
stateLookupSlack = 0.1
// softResponseLimit is the target maximum size of replies to data retrievals.
softResponseLimit = 2 * 1024 * 1024
// maxCodeLookups is the maximum number of bytecodes to serve. This number is
// there to limit the number of disk lookups.
maxCodeLookups = 1024
// maxTrieNodeLookups is the maximum number of state trie nodes to serve. This
// number is there to limit the number of disk lookups.
maxTrieNodeLookups = 1024
// maxTrieNodeTimeSpent is the maximum time we should spend on looking up trie nodes.
// If we spend too much time, then it's a fairly high chance of timing out
// at the remote side, which means all the work is in vain.
maxTrieNodeTimeSpent = 5 * time.Second
// MaxStreamFailures is the maximum allowed failures before stream gets removed
MaxStreamFailures = 5

@ -68,6 +68,60 @@ func MakeGetReceiptsRequest(hashes []common.Hash) *Request {
}
}
// MakeGetAccountRangeRequest makes the GetAccountRange request
func MakeGetAccountRangeRequest(root common.Hash, origin common.Hash, limit common.Hash, bytes uint64) *Request {
return &Request{
Request: &Request_GetAccountRangeRequest{
GetAccountRangeRequest: &GetAccountRangeRequest{
Root: root[:],
Origin: origin[:],
Limit: limit[:],
Bytes: bytes,
},
},
}
}
// MakeGetStorageRangesRequest makes the GetStorageRanges request
func MakeGetStorageRangesRequest(root common.Hash, accounts []common.Hash, origin common.Hash, limit common.Hash, bytes uint64) *Request {
return &Request{
Request: &Request_GetStorageRangesRequest{
GetStorageRangesRequest: &GetStorageRangesRequest{
Root: root[:],
Accounts: hashesToBytes(accounts),
Origin: origin[:],
Limit: limit[:],
Bytes: bytes,
},
},
}
}
// MakeGetByteCodesRequest makes the GetByteCodes request
func MakeGetByteCodesRequest(hashes []common.Hash, bytes uint64) *Request {
return &Request{
Request: &Request_GetByteCodesRequest{
GetByteCodesRequest: &GetByteCodesRequest{
Hashes: hashesToBytes(hashes),
Bytes: bytes,
},
},
}
}
// MakeGetTrieNodesRequest makes the GetTrieNodes request
func MakeGetTrieNodesRequest(root common.Hash, paths []*TrieNodePathSet, bytes uint64) *Request {
return &Request{
Request: &Request_GetTrieNodesRequest{
GetTrieNodesRequest: &GetTrieNodesRequest{
Root: root[:],
Paths: paths,
Bytes: bytes,
},
},
}
}
// MakeErrorResponse makes the error response
func MakeErrorResponseMessage(rid uint64, err error) *Message {
resp := MakeErrorResponse(rid, err)
@ -196,6 +250,80 @@ func MakeGetReceiptsResponse(rid uint64, receipts map[uint64]*Receipts) *Respons
}
}
// MakeGetAccountRangeResponseMessage makes the GetAccountRangeResponse of Message type
func MakeGetAccountRangeResponseMessage(rid uint64, accounts []*AccountData, proof [][]byte) *Message {
resp := MakeGetAccountRangeResponse(rid, accounts, proof)
return makeMessageFromResponse(resp)
}
// MakeGetAccountRangeResponse make the GetAccountRangeResponse of Response type
func MakeGetAccountRangeResponse(rid uint64, accounts []*AccountData, proof [][]byte) *Response {
return &Response{
ReqId: rid,
Response: &Response_GetAccountRangeResponse{
GetAccountRangeResponse: &GetAccountRangeResponse{
Accounts: accounts,
Proof: proof,
},
},
}
}
// MakeGetStorageRangesResponseMessage makes the GetStorageRangesResponse of Message type
func MakeGetStorageRangesResponseMessage(rid uint64, slots []*StoragesData, proof [][]byte) *Message {
resp := MakeGetStorageRangesResponse(rid, slots, proof)
return makeMessageFromResponse(resp)
}
// MakeGetStorageRangesResponse make the GetStorageRangesResponse of Response type
func MakeGetStorageRangesResponse(rid uint64, slots []*StoragesData, proof [][]byte) *Response {
return &Response{
ReqId: rid,
Response: &Response_GetStorageRangesResponse{
GetStorageRangesResponse: &GetStorageRangesResponse{
Slots: slots,
Proof: proof,
},
},
}
}
// MakeGetByteCodesResponseMessage makes the GetByteCodesResponse of Message type
func MakeGetByteCodesResponseMessage(rid uint64, codes [][]byte) *Message {
resp := MakeGetByteCodesResponse(rid, codes)
return makeMessageFromResponse(resp)
}
// MakeGetByteCodesResponse make the GetByteCodesResponse of Response type
func MakeGetByteCodesResponse(rid uint64, codes [][]byte) *Response {
return &Response{
ReqId: rid,
Response: &Response_GetByteCodesResponse{
GetByteCodesResponse: &GetByteCodesResponse{
Codes: codes,
},
},
}
}
// MakeGetTrieNodesResponseMessage makes the GetTrieNodesResponse of Message type
func MakeGetTrieNodesResponseMessage(rid uint64, nodes [][]byte) *Message {
resp := MakeGetTrieNodesResponse(rid, nodes)
return makeMessageFromResponse(resp)
}
// MakeGetTrieNodesResponse make the GetTrieNodesResponse of Response type
func MakeGetTrieNodesResponse(rid uint64, nodes [][]byte) *Response {
return &Response{
ReqId: rid,
Response: &Response_GetTrieNodesResponse{
GetTrieNodesResponse: &GetTrieNodesResponse{
Nodes: nodes,
},
},
}
}
// MakeMessageFromRequest makes a message from the request
func MakeMessageFromRequest(req *Request) *Message {
return &Message{

File diff suppressed because it is too large Load Diff

@ -19,6 +19,10 @@ message Request {
GetBlocksByHashesRequest get_blocks_by_hashes_request = 5;
GetNodeDataRequest get_node_data_request = 6;
GetReceiptsRequest get_receipts_request = 7;
GetAccountRangeRequest get_account_range_request = 8;
GetStorageRangesRequest get_storage_ranges_request = 9;
GetByteCodesRequest get_byte_codes_request = 10;
GetTrieNodesRequest get_trie_nodes_request = 11;
}
}
@ -44,6 +48,36 @@ message GetReceiptsRequest {
repeated bytes block_hashes = 1;
}
message GetAccountRangeRequest {
bytes root = 1;
bytes origin = 2;
bytes limit = 3;
uint64 bytes = 4;
}
message GetStorageRangesRequest {
bytes root = 1;
repeated bytes accounts = 2;
bytes origin = 3;
bytes limit = 4;
uint64 bytes = 5;
}
message GetByteCodesRequest {
repeated bytes hashes = 1;
uint64 bytes = 2;
}
message TrieNodePathSet {
repeated bytes pathset = 1;
}
message GetTrieNodesRequest {
bytes root = 1;
repeated TrieNodePathSet paths = 2;
uint64 bytes = 3;
}
message Response {
uint64 req_id = 1;
oneof response {
@ -54,6 +88,10 @@ message Response {
GetBlocksByHashesResponse get_blocks_by_hashes_response = 6;
GetNodeDataResponse get_node_data_response = 7;
GetReceiptsResponse get_receipts_response = 8;
GetAccountRangeResponse get_account_range_response = 9;
GetStorageRangesResponse get_storage_ranges_response = 10;
GetByteCodesResponse get_byte_codes_response = 11;
GetTrieNodesResponse get_trie_nodes_response = 12;
}
}
@ -90,3 +128,35 @@ message Receipts {
message GetReceiptsResponse {
map<uint64, Receipts> receipts = 1;
}
message AccountData {
bytes hash = 1;
bytes body = 2;
}
message GetAccountRangeResponse {
repeated AccountData accounts = 1;
repeated bytes proof = 2;
}
message StorageData {
bytes hash = 1;
bytes body = 2;
}
message StoragesData {
repeated StorageData data = 1;
}
message GetStorageRangesResponse {
repeated StoragesData slots = 1;
repeated bytes proof = 2;
}
message GetByteCodesResponse {
repeated bytes codes = 1;
}
message GetTrieNodesResponse {
repeated bytes nodes = 1;
}

@ -111,3 +111,67 @@ func (msg *Message) GetNodeDataResponse() (*GetNodeDataResponse, error) {
}
return gnResp, nil
}
// GetAccountRangesResponse parse the message to GetAccountRangesResponse
func (msg *Message) GetAccountRangesResponse() (*GetAccountRangeResponse, error) {
resp := msg.GetResp()
if resp == nil {
return nil, errors.New("not response message")
}
if errResp := resp.GetErrorResponse(); errResp != nil {
return nil, &ResponseError{errResp.Error}
}
gnResp := resp.GetGetAccountRangeResponse()
if gnResp == nil {
return nil, errors.New("not GetGetAccountRangeResponse")
}
return gnResp, nil
}
// GetStorageRangesResponse parse the message to GetStorageRangesResponse
func (msg *Message) GetStorageRangesResponse() (*GetStorageRangesResponse, error) {
resp := msg.GetResp()
if resp == nil {
return nil, errors.New("not response message")
}
if errResp := resp.GetErrorResponse(); errResp != nil {
return nil, &ResponseError{errResp.Error}
}
gnResp := resp.GetGetStorageRangesResponse()
if gnResp == nil {
return nil, errors.New("not GetGetStorageRangesResponse")
}
return gnResp, nil
}
// GetByteCodesResponse parse the message to GetByteCodesResponse
func (msg *Message) GetByteCodesResponse() (*GetByteCodesResponse, error) {
resp := msg.GetResp()
if resp == nil {
return nil, errors.New("not response message")
}
if errResp := resp.GetErrorResponse(); errResp != nil {
return nil, &ResponseError{errResp.Error}
}
gnResp := resp.GetGetByteCodesResponse()
if gnResp == nil {
return nil, errors.New("not GetByteCodesResponse")
}
return gnResp, nil
}
// GetTrieNodesResponse parse the message to GetTrieNodesResponse
func (msg *Message) GetTrieNodesResponse() (*GetTrieNodesResponse, error) {
resp := msg.GetResp()
if resp == nil {
return nil, errors.New("not response message")
}
if errResp := resp.GetErrorResponse(); errResp != nil {
return nil, &ResponseError{errResp.Error}
}
gnResp := resp.GetGetTrieNodesResponse()
if gnResp == nil {
return nil, errors.New("not GetTrieNodesResponse")
}
return gnResp, nil
}

@ -10,6 +10,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rlp"
protobuf "github.com/golang/protobuf/proto"
"github.com/harmony-one/harmony/p2p/stream/protocols/sync/message"
syncpb "github.com/harmony-one/harmony/p2p/stream/protocols/sync/message"
sttypes "github.com/harmony-one/harmony/p2p/stream/types"
libp2p_network "github.com/libp2p/go-libp2p/core/network"
@ -188,6 +189,18 @@ func (st *syncStream) handleReq(req *syncpb.Request) error {
if rReq := req.GetGetReceiptsRequest(); rReq != nil {
return st.handleGetReceiptsRequest(req.ReqId, rReq)
}
if ndReq := req.GetGetAccountRangeRequest(); ndReq != nil {
return st.handleGetAccountRangeRequest(req.ReqId, ndReq)
}
if ndReq := req.GetGetStorageRangesRequest(); ndReq != nil {
return st.handleGetStorageRangesRequest(req.ReqId, ndReq)
}
if ndReq := req.GetGetByteCodesRequest(); ndReq != nil {
return st.handleGetByteCodesRequest(req.ReqId, ndReq)
}
if ndReq := req.GetGetTrieNodesRequest(); ndReq != nil {
return st.handleGetTrieNodesRequest(req.ReqId, ndReq)
}
// unsupported request type
return st.handleUnknownRequest(req.ReqId)
}
@ -308,6 +321,95 @@ func (st *syncStream) handleGetReceiptsRequest(rid uint64, req *syncpb.GetReceip
return errors.Wrap(err, "[GetReceipts]")
}
func (st *syncStream) handleGetAccountRangeRequest(rid uint64, req *syncpb.GetAccountRangeRequest) error {
serverRequestCounterVec.With(prometheus.Labels{
"topic": string(st.ProtoID()),
"request_type": "getAccountRangeRequest",
}).Inc()
root := common.BytesToHash(req.Root)
origin := common.BytesToHash(req.Origin)
limit := common.BytesToHash(req.Limit)
resp, err := st.computeGetAccountRangeRequest(rid, root, origin, limit, req.Bytes)
if resp == nil && err != nil {
resp = syncpb.MakeErrorResponseMessage(rid, err)
}
if writeErr := st.writeMsg(resp); writeErr != nil {
if err == nil {
err = writeErr
} else {
err = fmt.Errorf("%v; [writeMsg] %v", err.Error(), writeErr)
}
}
return errors.Wrap(err, "[GetAccountRange]")
}
func (st *syncStream) handleGetStorageRangesRequest(rid uint64, req *syncpb.GetStorageRangesRequest) error {
serverRequestCounterVec.With(prometheus.Labels{
"topic": string(st.ProtoID()),
"request_type": "getStorageRangesRequest",
}).Inc()
root := common.BytesToHash(req.Root)
accounts := bytesToHashes(req.Accounts)
origin := common.BytesToHash(req.Origin)
limit := common.BytesToHash(req.Limit)
resp, err := st.computeGetStorageRangesRequest(rid, root, accounts, origin, limit, req.Bytes)
if resp == nil && err != nil {
resp = syncpb.MakeErrorResponseMessage(rid, err)
}
if writeErr := st.writeMsg(resp); writeErr != nil {
if err == nil {
err = writeErr
} else {
err = fmt.Errorf("%v; [writeMsg] %v", err.Error(), writeErr)
}
}
return errors.Wrap(err, "[GetStorageRanges]")
}
func (st *syncStream) handleGetByteCodesRequest(rid uint64, req *syncpb.GetByteCodesRequest) error {
serverRequestCounterVec.With(prometheus.Labels{
"topic": string(st.ProtoID()),
"request_type": "getByteCodesRequest",
}).Inc()
hashes := bytesToHashes(req.Hashes)
resp, err := st.computeGetByteCodesRequest(rid, hashes, req.Bytes)
if resp == nil && err != nil {
resp = syncpb.MakeErrorResponseMessage(rid, err)
}
if writeErr := st.writeMsg(resp); writeErr != nil {
if err == nil {
err = writeErr
} else {
err = fmt.Errorf("%v; [writeMsg] %v", err.Error(), writeErr)
}
}
return errors.Wrap(err, "[GetByteCodes]")
}
func (st *syncStream) handleGetTrieNodesRequest(rid uint64, req *syncpb.GetTrieNodesRequest) error {
serverRequestCounterVec.With(prometheus.Labels{
"topic": string(st.ProtoID()),
"request_type": "getTrieNodesRequest",
}).Inc()
root := common.BytesToHash(req.Root)
resp, err := st.computeGetTrieNodesRequest(rid, root, req.Paths, req.Bytes)
if resp == nil && err != nil {
resp = syncpb.MakeErrorResponseMessage(rid, err)
}
if writeErr := st.writeMsg(resp); writeErr != nil {
if err == nil {
err = writeErr
} else {
err = fmt.Errorf("%v; [writeMsg] %v", err.Error(), writeErr)
}
}
return errors.Wrap(err, "[GetTrieNodes]")
}
func (st *syncStream) handleUnknownRequest(rid uint64) error {
serverRequestCounterVec.With(prometheus.Labels{
"topic": string(st.ProtoID()),
@ -453,6 +555,74 @@ func (st *syncStream) computeGetReceipts(rid uint64, hs []common.Hash) (*syncpb.
return syncpb.MakeGetReceiptsResponseMessage(rid, normalizedReceipts), nil
}
func (st *syncStream) computeGetAccountRangeRequest(rid uint64, root common.Hash, origin common.Hash, limit common.Hash, bytes uint64) (*syncpb.Message, error) {
if bytes == 0 {
return nil, fmt.Errorf("zero account ranges bytes requested")
}
if bytes > softResponseLimit {
return nil, fmt.Errorf("requested bytes exceed limit")
}
accounts, proof, err := st.chain.getAccountRange(root, origin, limit, bytes)
if err != nil {
return nil, err
}
return syncpb.MakeGetAccountRangeResponseMessage(rid, accounts, proof), nil
}
func (st *syncStream) computeGetStorageRangesRequest(rid uint64, root common.Hash, accounts []common.Hash, origin common.Hash, limit common.Hash, bytes uint64) (*syncpb.Message, error) {
if bytes == 0 {
return nil, fmt.Errorf("zero storage ranges bytes requested")
}
if bytes > softResponseLimit {
return nil, fmt.Errorf("requested bytes exceed limit")
}
if len(accounts) > GetStorageRangesRequestCap {
err := fmt.Errorf("GetStorageRangesRequest amount exceed cap: %v > %v", len(accounts), GetStorageRangesRequestCap)
return nil, err
}
slots, proofs, err := st.chain.getStorageRanges(root, accounts, origin, limit, bytes)
if err != nil {
return nil, err
}
return syncpb.MakeGetStorageRangesResponseMessage(rid, slots, proofs), nil
}
func (st *syncStream) computeGetByteCodesRequest(rid uint64, hs []common.Hash, bytes uint64) (*syncpb.Message, error) {
if bytes == 0 {
return nil, fmt.Errorf("zero byte code bytes requested")
}
if bytes > softResponseLimit {
return nil, fmt.Errorf("requested bytes exceed limit")
}
if len(hs) > GetByteCodesRequestCap {
err := fmt.Errorf("GetByteCodesRequest amount exceed cap: %v > %v", len(hs), GetByteCodesRequestCap)
return nil, err
}
codes, err := st.chain.getByteCodes(hs, bytes)
if err != nil {
return nil, err
}
return syncpb.MakeGetByteCodesResponseMessage(rid, codes), nil
}
func (st *syncStream) computeGetTrieNodesRequest(rid uint64, root common.Hash, paths []*message.TrieNodePathSet, bytes uint64) (*syncpb.Message, error) {
if bytes == 0 {
return nil, fmt.Errorf("zero trie node bytes requested")
}
if bytes > softResponseLimit {
return nil, fmt.Errorf("requested bytes exceed limit")
}
if len(paths) > GetTrieNodesRequestCap {
err := fmt.Errorf("GetTrieNodesRequest amount exceed cap: %v > %v", len(paths), GetTrieNodesRequestCap)
return nil, err
}
nodes, err := st.chain.getTrieNodes(root, paths, bytes, time.Now())
if err != nil {
return nil, err
}
return syncpb.MakeGetTrieNodesResponseMessage(rid, nodes), nil
}
func bytesToHashes(bs [][]byte) []common.Hash {
hs := make([]common.Hash, 0, len(bs))
for _, b := range bs {

@ -60,6 +60,30 @@ var (
}
testGetNodeDataRequest = syncpb.MakeGetNodeDataRequest(testGetNodeData)
testGetNodeDataRequestMsg = syncpb.MakeMessageFromRequest(testGetNodeDataRequest)
maxBytes = uint64(500)
root = numberToHash(1)
origin = numberToHash(2)
limit = numberToHash(3)
testHashes = []common.Hash{
numberToHash(1),
numberToHash(2),
}
testAccounts = []common.Hash{account1, account2}
testGetAccountRangesRequest = syncpb.MakeGetAccountRangeRequest(root, origin, limit, maxBytes)
testGetAccountRangesRequestMsg = syncpb.MakeMessageFromRequest(testGetAccountRangesRequest)
testGetStorageRangesRequest = syncpb.MakeGetStorageRangesRequest(root, testAccounts, origin, limit, maxBytes)
testGetStorageRangesRequestMsg = syncpb.MakeMessageFromRequest(testGetStorageRangesRequest)
testGetByteCodesRequest = syncpb.MakeGetByteCodesRequest(testHashes, maxBytes)
testGetByteCodesRequestMsg = syncpb.MakeMessageFromRequest(testGetByteCodesRequest)
testGetTrieNodesRequest = syncpb.MakeGetTrieNodesRequest(root, testPaths, maxBytes)
testGetTrieNodesRequestMsg = syncpb.MakeMessageFromRequest(testGetTrieNodesRequest)
)
func TestSyncStream_HandleGetBlocksByRequest(t *testing.T) {
@ -188,6 +212,90 @@ func TestSyncStream_HandleGetNodeData(t *testing.T) {
}
}
func TestSyncStream_HandleGetAccountRanges(t *testing.T) {
st, remoteSt := makeTestSyncStream()
go st.run()
defer close(st.closeC)
req := testGetAccountRangesRequestMsg
b, _ := protobuf.Marshal(req)
err := remoteSt.WriteBytes(b)
if err != nil {
t.Fatal(err)
}
time.Sleep(200 * time.Millisecond)
receivedBytes, _ := remoteSt.ReadBytes()
if err := checkAccountRangeResult(maxBytes, receivedBytes); err != nil {
t.Fatal(err)
}
}
func TestSyncStream_HandleGetStorageRanges(t *testing.T) {
st, remoteSt := makeTestSyncStream()
go st.run()
defer close(st.closeC)
req := testGetStorageRangesRequestMsg
b, _ := protobuf.Marshal(req)
err := remoteSt.WriteBytes(b)
if err != nil {
t.Fatal(err)
}
time.Sleep(200 * time.Millisecond)
receivedBytes, _ := remoteSt.ReadBytes()
if err := checkStorageRangesResult(testAccounts, maxBytes, receivedBytes); err != nil {
t.Fatal(err)
}
}
func TestSyncStream_HandleGetByteCodesResult(t *testing.T) {
st, remoteSt := makeTestSyncStream()
go st.run()
defer close(st.closeC)
req := testGetByteCodesRequestMsg
b, _ := protobuf.Marshal(req)
err := remoteSt.WriteBytes(b)
if err != nil {
t.Fatal(err)
}
time.Sleep(200 * time.Millisecond)
receivedBytes, _ := remoteSt.ReadBytes()
if err := checkByteCodesResult(testHashes, maxBytes, receivedBytes); err != nil {
t.Fatal(err)
}
}
func TestSyncStream_HandleGetTrieNodes(t *testing.T) {
st, remoteSt := makeTestSyncStream()
go st.run()
defer close(st.closeC)
req := testGetTrieNodesRequestMsg
b, _ := protobuf.Marshal(req)
err := remoteSt.WriteBytes(b)
if err != nil {
t.Fatal(err)
}
time.Sleep(200 * time.Millisecond)
receivedBytes, _ := remoteSt.ReadBytes()
if err := checkTrieNodesResult(testHashes, maxBytes, receivedBytes); err != nil {
t.Fatal(err)
}
}
func makeTestSyncStream() (*syncStream, *testRemoteBaseStream) {
localRaw, remoteRaw := makePairP2PStreams()
remote := newTestRemoteBaseStream(remoteRaw)

@ -25,19 +25,6 @@ import (
"github.com/pkg/errors"
)
// ValidatorListProvider ..
type ValidatorListProvider interface {
Compute(
epoch *big.Int, reader DataProvider,
) (*shard.State, error)
ReadFromDB(epoch *big.Int, reader DataProvider) (*shard.State, error)
}
// Reader is committee.Reader and it is the API that committee membership assignment needs
type Reader interface {
ValidatorListProvider
}
// StakingCandidatesReader ..
type StakingCandidatesReader interface {
CurrentBlock() *types.Block
@ -272,7 +259,7 @@ type partialStakingEnabled struct{}
var (
// WithStakingEnabled ..
WithStakingEnabled Reader = partialStakingEnabled{}
WithStakingEnabled = partialStakingEnabled{}
// ErrComputeForEpochInPast ..
ErrComputeForEpochInPast = errors.New("cannot compute for epoch in past")
)

@ -22,12 +22,14 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/trie"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/block"
blockfactory "github.com/harmony-one/harmony/block/factory"
consensus_engine "github.com/harmony-one/harmony/consensus/engine"
"github.com/harmony-one/harmony/core/state"
"github.com/harmony-one/harmony/core/state/snapshot"
"github.com/harmony-one/harmony/core/types"
"github.com/harmony-one/harmony/core/vm"
"github.com/harmony-one/harmony/internal/params"
@ -252,6 +254,7 @@ func (cr *fakeChainReader) GetReceiptsByHash(hash common.Hash) types.Receipts
func (cr *fakeChainReader) ContractCode(hash common.Hash) ([]byte, error) { return []byte{}, nil }
func (cr *fakeChainReader) ValidatorCode(hash common.Hash) ([]byte, error) { return []byte{}, nil }
func (cr *fakeChainReader) ReadShardState(epoch *big.Int) (*shard.State, error) { return nil, nil }
func (cr *fakeChainReader) TrieDB() *trie.Database { return nil }
func (cr *fakeChainReader) TrieNode(hash common.Hash) ([]byte, error) { return []byte{}, nil }
func (cr *fakeChainReader) ReadValidatorList() ([]common.Address, error) { return nil, nil }
func (cr *fakeChainReader) ValidatorCandidates() []common.Address { return nil }
@ -273,6 +276,9 @@ func (cr *fakeChainReader) ReadValidatorInformationAtState(
func (cr *fakeChainReader) StateAt(root common.Hash) (*state.DB, error) {
return nil, nil
}
func (cr *fakeChainReader) Snapshots() *snapshot.Tree {
return nil
}
func (cr *fakeChainReader) ReadValidatorSnapshot(
addr common.Address,
) (*staking.ValidatorSnapshot, error) {

Loading…
Cancel
Save