Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

X-chain SDK gossip #2490

Merged
merged 116 commits into from
Dec 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
116 commits
Select commit Hold shift + click to select a range
972daa9
push gossiper implementation
joshua-kim Dec 12, 2023
085e8aa
Update network/p2p/gossip/gossipable.go
joshua-kim Dec 13, 2023
7204679
nit
joshua-kim Dec 13, 2023
3bbe6cc
debug -> error
joshua-kim Dec 13, 2023
636ec5a
tidy
joshua-kim Dec 13, 2023
1699673
use vector for metrics
joshua-kim Dec 13, 2023
d2b146b
limit outbound size
joshua-kim Dec 13, 2023
5a9171d
nit
joshua-kim Dec 13, 2023
0249064
nit
joshua-kim Dec 13, 2023
9b7e5bb
nit
joshua-kim Dec 13, 2023
027155a
nit
joshua-kim Dec 13, 2023
b046fab
Update network/p2p/gossip/handler.go
joshua-kim Dec 13, 2023
0500c5c
Update network/p2p/gossip/gossip.go
joshua-kim Dec 13, 2023
2d3ad42
nit
joshua-kim Dec 13, 2023
23f8072
nit
joshua-kim Dec 13, 2023
2b4b8eb
nit
joshua-kim Dec 13, 2023
b43118f
nit
joshua-kim Dec 13, 2023
1ff0bdd
nit
joshua-kim Dec 13, 2023
0e89bd4
Update network/p2p/gossip/gossip.go
StephenButtolph Dec 13, 2023
7a70bac
nit
joshua-kim Dec 13, 2023
2290f87
nit
joshua-kim Dec 13, 2023
a283199
nit
joshua-kim Dec 14, 2023
93df057
Update network/p2p/gossip/gossip.go
joshua-kim Dec 14, 2023
f38ef7e
nit
joshua-kim Dec 14, 2023
ac685a0
xchain gossip
joshua-kim Dec 14, 2023
9e3ec8f
refactor marshalling
joshua-kim Dec 19, 2023
a68b26d
nit
joshua-kim Dec 19, 2023
2f369ec
lint
joshua-kim Dec 19, 2023
d8ebd0f
Merge branch 'dev' into xchain-gossip
StephenButtolph Dec 19, 2023
158292d
Update network/p2p/gossip/gossipable.go
joshua-kim Dec 19, 2023
42d5d6a
Merge branch 'gossip-parser' into xchain-gossip
StephenButtolph Dec 19, 2023
aafcde5
nit
joshua-kim Dec 19, 2023
00389df
Update network/p2p/gossip/handler.go
joshua-kim Dec 19, 2023
4db166d
Update network/p2p/gossip/gossip.go
joshua-kim Dec 19, 2023
f7fc9f8
nit
joshua-kim Dec 19, 2023
22f27f1
nit
joshua-kim Dec 19, 2023
9d423da
wip
StephenButtolph Dec 19, 2023
bc0f912
Merge branch 'gossip-parser' into xchain-gossip
StephenButtolph Dec 19, 2023
1be49a4
nit
joshua-kim Dec 19, 2023
1cf29c3
nti
joshua-kim Dec 19, 2023
20a2e28
Update network/p2p/gossip/gossipable.go
joshua-kim Dec 19, 2023
f7b9a67
nit
joshua-kim Dec 19, 2023
6a6438a
nit
joshua-kim Dec 19, 2023
b717fe6
nit
joshua-kim Dec 19, 2023
eeb1bc7
nit
joshua-kim Dec 19, 2023
59d3a6b
Merge branch 'gossip-parser' into xchain-gossip
StephenButtolph Dec 19, 2023
fc9c89c
wip
StephenButtolph Dec 19, 2023
250ae11
Merge branch 'dev' into gossip-parser
StephenButtolph Dec 19, 2023
b94cc99
Merge branch 'gossip-parser' into xchain-gossip
StephenButtolph Dec 19, 2023
8cc874c
wip
StephenButtolph Dec 20, 2023
e7beb7d
Merge branch 'xchain-gossip' of github.com:ava-labs/avalanchego into …
StephenButtolph Dec 20, 2023
fd71f2f
Merge branch 'dev' into xchain-gossip
StephenButtolph Dec 20, 2023
ff304c1
Initialize transactions once
StephenButtolph Dec 20, 2023
be3a7f0
Merge branch 'dev' into initialize-txs-once
StephenButtolph Dec 20, 2023
e71f642
wip
StephenButtolph Dec 20, 2023
68d2ffa
wip
StephenButtolph Dec 20, 2023
0fbf797
wip
StephenButtolph Dec 20, 2023
95d0331
Move context lock into issueTx
StephenButtolph Dec 20, 2023
cc97faa
Rework X-chain locking in tests
StephenButtolph Dec 20, 2023
9bfa50d
ok
StephenButtolph Dec 20, 2023
cedb056
merged
StephenButtolph Dec 20, 2023
da814b3
merged
StephenButtolph Dec 20, 2023
a1f0b37
merged
StephenButtolph Dec 20, 2023
c258873
nit
StephenButtolph Dec 20, 2023
b24b89f
nit
StephenButtolph Dec 20, 2023
11c50d3
nit
StephenButtolph Dec 20, 2023
5cf5b96
nit
StephenButtolph Dec 20, 2023
0811be2
nit
StephenButtolph Dec 20, 2023
4cd2eae
nit
StephenButtolph Dec 20, 2023
8e78fac
nit
StephenButtolph Dec 20, 2023
d41f3bc
nit
StephenButtolph Dec 20, 2023
e442f52
nit
StephenButtolph Dec 20, 2023
7486b63
nit
StephenButtolph Dec 21, 2023
0516dde
wip
StephenButtolph Dec 21, 2023
4284e86
nit
StephenButtolph Dec 21, 2023
3ccf17b
nit
StephenButtolph Dec 21, 2023
e5ec365
nit
StephenButtolph Dec 21, 2023
7addc7c
fix test
StephenButtolph Dec 21, 2023
505ae81
logging
StephenButtolph Dec 21, 2023
b7e2a96
remove gossipTx struct
StephenButtolph Dec 21, 2023
cef81cc
add VM context
StephenButtolph Dec 21, 2023
cad3395
Merge branch 'dev' into xchain-gossip
StephenButtolph Dec 21, 2023
809a339
Merge branch 'dev' into xchain-gossip
StephenButtolph Dec 21, 2023
7518e5a
nit
StephenButtolph Dec 21, 2023
eb863bb
Move locking into issueTx
StephenButtolph Dec 21, 2023
3e8b3fc
whoopsie
StephenButtolph Dec 21, 2023
dac0b83
nit
StephenButtolph Dec 21, 2023
e0aa0e0
yessir
StephenButtolph Dec 21, 2023
831720f
Introduce TxVerifier to network
StephenButtolph Dec 21, 2023
a5271af
move invariant
StephenButtolph Dec 21, 2023
705cfd1
cleanup tests
StephenButtolph Dec 21, 2023
7675248
wip merge
StephenButtolph Dec 21, 2023
69c08e9
fix tests
StephenButtolph Dec 22, 2023
a0b1cb6
nit
StephenButtolph Dec 22, 2023
ff37ed0
nit
StephenButtolph Dec 22, 2023
a0b6525
nit
StephenButtolph Dec 22, 2023
411d0a5
nit
StephenButtolph Dec 22, 2023
25e7516
merged
StephenButtolph Dec 22, 2023
d666add
Merge branch 'tx-verifier' into xchain-gossip
StephenButtolph Dec 22, 2023
ea3f8c1
Use configs
StephenButtolph Dec 22, 2023
05e83f4
nit
StephenButtolph Dec 22, 2023
8389126
nit
StephenButtolph Dec 22, 2023
1d96549
nit
StephenButtolph Dec 22, 2023
b7fb777
fix env tests
StephenButtolph Dec 22, 2023
bf02a21
Merge branch 'dev' into tx-verifier
StephenButtolph Dec 22, 2023
4a35548
Merge branch 'tx-verifier' into xchain-gossip
StephenButtolph Dec 22, 2023
052f0ac
reduce diff
StephenButtolph Dec 22, 2023
2bee0c1
Merge branch 'xchain-gossip' of github.com:ava-labs/avalanchego into …
StephenButtolph Dec 22, 2023
66ab0f6
reduce diff
StephenButtolph Dec 22, 2023
4ae04a8
simplify table tests
StephenButtolph Dec 22, 2023
5d4f63e
merged
StephenButtolph Dec 22, 2023
7e7b5d1
merged
StephenButtolph Dec 22, 2023
873ae4c
Merge branch 'dev' into xchain-gossip
dhrubabasu Dec 22, 2023
ccaaed2
Update vms/avm/network/network.go
StephenButtolph Dec 22, 2023
9ba175d
nit
StephenButtolph Dec 22, 2023
0ddeb97
Merge branch 'xchain-gossip' of github.com:ava-labs/avalanchego into …
StephenButtolph Dec 22, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
34 changes: 34 additions & 0 deletions vms/avm/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (C) 2019-2023, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package avm

import (
"encoding/json"

"github.com/ava-labs/avalanchego/vms/avm/network"
)

var DefaultConfig = Config{
Network: network.DefaultConfig,
IndexTransactions: false,
IndexAllowIncomplete: false,
ChecksumsEnabled: false,
}

type Config struct {
Network network.Config `json:"network"`
IndexTransactions bool `json:"index-transactions"`
IndexAllowIncomplete bool `json:"index-allow-incomplete"`
ChecksumsEnabled bool `json:"checksums-enabled"`
}

func ParseConfig(configBytes []byte) (Config, error) {
if len(configBytes) == 0 {
return DefaultConfig, nil
}

config := DefaultConfig
err := json.Unmarshal(configBytes, &config)
return config, err
}
67 changes: 67 additions & 0 deletions vms/avm/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright (C) 2019-2023, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package avm

import (
"testing"
"time"

"github.com/stretchr/testify/require"

"github.com/ava-labs/avalanchego/vms/avm/network"
)

func TestParseConfig(t *testing.T) {
tests := []struct {
name string
configBytes []byte
expectedConfig Config
}{
{
name: "unspecified config",
configBytes: nil,
expectedConfig: DefaultConfig,
},
{
name: "manually specified checksums enabled",
configBytes: []byte(`{"checksums-enabled":true}`),
expectedConfig: Config{
Network: network.DefaultConfig,
IndexTransactions: DefaultConfig.IndexTransactions,
IndexAllowIncomplete: DefaultConfig.IndexAllowIncomplete,
ChecksumsEnabled: true,
},
},
{
name: "manually specified checksums enabled",
configBytes: []byte(`{"network":{"max-validator-set-staleness":1}}`),
expectedConfig: Config{
Network: network.Config{
MaxValidatorSetStaleness: time.Nanosecond,
TargetGossipSize: network.DefaultConfig.TargetGossipSize,
PullGossipPollSize: network.DefaultConfig.PullGossipPollSize,
PullGossipFrequency: network.DefaultConfig.PullGossipFrequency,
PullGossipThrottlingPeriod: network.DefaultConfig.PullGossipThrottlingPeriod,
PullGossipThrottlingLimit: network.DefaultConfig.PullGossipThrottlingLimit,
ExpectedBloomFilterElements: network.DefaultConfig.ExpectedBloomFilterElements,
ExpectedBloomFilterFalsePositiveProbability: network.DefaultConfig.ExpectedBloomFilterFalsePositiveProbability,
MaxBloomFilterFalsePositiveProbability: network.DefaultConfig.MaxBloomFilterFalsePositiveProbability,
LegacyPushGossipCacheSize: network.DefaultConfig.LegacyPushGossipCacheSize,
},
IndexTransactions: DefaultConfig.IndexTransactions,
IndexAllowIncomplete: DefaultConfig.IndexAllowIncomplete,
ChecksumsEnabled: DefaultConfig.ChecksumsEnabled,
},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
require := require.New(t)

config, err := ParseConfig(test.configBytes)
require.NoError(err)
require.Equal(test.expectedConfig, config)
})
}
}
5 changes: 2 additions & 3 deletions vms/avm/environment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,8 @@ func setup(tb testing.TB, c *envConfig) *environment {
Config: vmStaticConfig,
}

vmDynamicConfig := Config{
IndexTransactions: true,
}
vmDynamicConfig := DefaultConfig
vmDynamicConfig.IndexTransactions = true
if c.vmDynamicConfig != nil {
vmDynamicConfig = *c.vmDynamicConfig
}
Expand Down
66 changes: 66 additions & 0 deletions vms/avm/network/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (C) 2019-2023, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package network

import (
"time"

"github.com/ava-labs/avalanchego/utils/units"
)

var DefaultConfig = Config{
MaxValidatorSetStaleness: time.Minute,
TargetGossipSize: 20 * units.KiB,
PullGossipPollSize: 1,
PullGossipFrequency: 1500 * time.Millisecond,
PullGossipThrottlingPeriod: 10 * time.Second,
PullGossipThrottlingLimit: 2,
ExpectedBloomFilterElements: 8 * 1024,
ExpectedBloomFilterFalsePositiveProbability: .01,
MaxBloomFilterFalsePositiveProbability: .05,
LegacyPushGossipCacheSize: 512,
}

type Config struct {
// MaxValidatorSetStaleness limits how old of a validator set the network
// will use for peer sampling and rate limiting.
MaxValidatorSetStaleness time.Duration `json:"max-validator-set-staleness"`
// TargetGossipSize is the number of bytes that will be attempted to be
// sent when pushing transactions and when responded to transaction pull
// requests.
TargetGossipSize int `json:"target-gossip-size"`
// PullGossipPollSize is the number of validators to sample when performing
// a round of pull gossip.
PullGossipPollSize int `json:"pull-gossip-poll-size"`
// PullGossipFrequency is how frequently rounds of pull gossip are
// performed.
PullGossipFrequency time.Duration `json:"pull-gossip-frequency"`
// PullGossipThrottlingPeriod is how large of a window the throttler should
// use.
PullGossipThrottlingPeriod time.Duration `json:"pull-gossip-throttling-period"`
// PullGossipThrottlingLimit is the number of pull querys that are allowed
// by a validator in every throttling window.
PullGossipThrottlingLimit int `json:"pull-gossip-throttling-limit"`
// ExpectedBloomFilterElements is the number of elements to expect when
// creating a new bloom filter. The larger this number is, the larger the
// bloom filter will be.
ExpectedBloomFilterElements uint64 `json:"expected-bloom-filter-elements"`
// ExpectedBloomFilterFalsePositiveProbability is the expected probability
// of a false positive after having inserted ExpectedBloomFilterElements
// into a bloom filter. The smaller this number is, the larger the bloom
// filter will be.
ExpectedBloomFilterFalsePositiveProbability float64 `json:"expected-bloom-filter-false-positive-probability"`
// MaxBloomFilterFalsePositiveProbability is used to determine when the
// bloom filter should be refreshed. Once the expected probability of a
// false positive exceeds this value, the bloom filter will be regenerated.
// The smaller this number is, the more frequently that the bloom filter
// will be regenerated.
MaxBloomFilterFalsePositiveProbability float64 `json:"max-bloom-filter-false-positive-probability"`
// LegacyPushGossipCacheSize tracks the most recently received transactions
// and ensures to only gossip them once.
//
// Deprecated: The legacy push gossip mechanism is deprecated in favor of
// the p2p SDK's push gossip mechanism.
LegacyPushGossipCacheSize int `json:"legacy-push-gossip-cache-size"`
}
157 changes: 157 additions & 0 deletions vms/avm/network/gossip.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
// Copyright (C) 2019-2023, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package network

import (
"context"
"fmt"
"sync"
"time"

"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/network/p2p"
"github.com/ava-labs/avalanchego/network/p2p/gossip"
"github.com/ava-labs/avalanchego/utils/logging"
"github.com/ava-labs/avalanchego/vms/avm/txs"
"github.com/ava-labs/avalanchego/vms/avm/txs/mempool"
)

var (
_ p2p.Handler = (*txGossipHandler)(nil)
_ gossip.Set[*txs.Tx] = (*gossipMempool)(nil)
_ gossip.Marshaller[*txs.Tx] = (*txParser)(nil)
)

// txGossipHandler is the handler called when serving gossip messages
type txGossipHandler struct {
p2p.NoOpHandler
appGossipHandler p2p.Handler
appRequestHandler p2p.Handler
}

func (t txGossipHandler) AppGossip(
ctx context.Context,
nodeID ids.NodeID,
gossipBytes []byte,
) {
t.appGossipHandler.AppGossip(ctx, nodeID, gossipBytes)
}

func (t txGossipHandler) AppRequest(
ctx context.Context,
nodeID ids.NodeID,
deadline time.Time,
requestBytes []byte,
) ([]byte, error) {
return t.appRequestHandler.AppRequest(ctx, nodeID, deadline, requestBytes)
}

type txParser struct {
parser txs.Parser
}

func (*txParser) MarshalGossip(tx *txs.Tx) ([]byte, error) {
return tx.Bytes(), nil
}

func (g *txParser) UnmarshalGossip(bytes []byte) (*txs.Tx, error) {
return g.parser.ParseTx(bytes)
}

func newGossipMempool(
mempool mempool.Mempool,
log logging.Logger,
txVerifier TxVerifier,
parser txs.Parser,
maxExpectedElements uint64,
falsePositiveProbability,
maxFalsePositiveProbability float64,
) (*gossipMempool, error) {
bloom, err := gossip.NewBloomFilter(maxExpectedElements, falsePositiveProbability)
return &gossipMempool{
Mempool: mempool,
log: log,
txVerifier: txVerifier,
parser: parser,
maxFalsePositiveProbability: maxFalsePositiveProbability,
bloom: bloom,
}, err
}

type gossipMempool struct {
mempool.Mempool
log logging.Logger
txVerifier TxVerifier
parser txs.Parser
maxFalsePositiveProbability float64

lock sync.RWMutex
bloom *gossip.BloomFilter
}

// Add is called by the p2p SDK when handling transactions that were pushed to
// us and when handling transactions that were pulled from a peer. If this
// returns a nil error while handling push gossip, the p2p SDK will queue the
// transaction to push gossip as well.
func (g *gossipMempool) Add(tx *txs.Tx) error {
txID := tx.ID()
if _, ok := g.Mempool.Get(txID); ok {
return fmt.Errorf("attempted to issue %w: %s ", mempool.ErrDuplicateTx, txID)
}

if reason := g.Mempool.GetDropReason(txID); reason != nil {
// If the tx is being dropped - just ignore it
//
// TODO: Should we allow re-verification of the transaction even if it
// failed previously?
return reason
}

// Verify the tx at the currently preferred state
if err := g.txVerifier.VerifyTx(tx); err != nil {
g.Mempool.MarkDropped(txID, err)
return err
}

return g.AddVerified(tx)
}

func (g *gossipMempool) AddVerified(tx *txs.Tx) error {
if err := g.Mempool.Add(tx); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we check if tx is already in the mempool?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AddVerified is expected to error if the tx is already in the mempool (which is what happens here)

g.Mempool.MarkDropped(tx.ID(), err)
return err
}

g.lock.Lock()
defer g.lock.Unlock()

g.bloom.Add(tx)
reset, err := gossip.ResetBloomFilterIfNeeded(g.bloom, g.maxFalsePositiveProbability)
if err != nil {
return err
}

if reset {
g.log.Debug("resetting bloom filter")
g.Mempool.Iterate(func(tx *txs.Tx) bool {
g.bloom.Add(tx)
return true
})
}

g.Mempool.RequestBuildBlock()
return nil
}

func (g *gossipMempool) Iterate(f func(*txs.Tx) bool) {
g.Mempool.Iterate(f)
}

func (g *gossipMempool) GetFilter() (bloom []byte, salt []byte, err error) {
g.lock.RLock()
defer g.lock.RUnlock()

bloomBytes, err := g.bloom.Bloom.MarshalBinary()
return bloomBytes, g.bloom.Salt[:], err
}