Skip to content

Commit

Permalink
Merge branch 'develop' into sc/ci-release-error-1
Browse files Browse the repository at this point in the history
  • Loading branch information
mergify[bot] committed Mar 27, 2023
2 parents d77aefb + 2a201dc commit e9fa6f3
Show file tree
Hide file tree
Showing 11 changed files with 303 additions and 16 deletions.
8 changes: 8 additions & 0 deletions op-node/flags/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,13 @@ var (
Usage: "Initialize the sequencer in a stopped state. The sequencer can be started using the admin_startSequencer RPC",
EnvVar: prefixEnvVar("SEQUENCER_STOPPED"),
}
SequencerMaxSafeLagFlag = cli.Uint64Flag{
Name: "sequencer.max-safe-lag",
Usage: "Maximum number of L2 blocks for restricting the distance between L2 safe and unsafe. Disabled if 0.",
EnvVar: prefixEnvVar("SEQUENCER_MAX_SAFE_LAG"),
Required: false,
Value: 0,
}
SequencerL1Confs = cli.Uint64Flag{
Name: "sequencer.l1-confs",
Usage: "Number of L1 blocks to keep distance from the L1 head as a sequencer for picking an L1 origin.",
Expand Down Expand Up @@ -221,6 +228,7 @@ var optionalFlags = []cli.Flag{
VerifierL1Confs,
SequencerEnabledFlag,
SequencerStoppedFlag,
SequencerMaxSafeLagFlag,
SequencerL1Confs,
L1EpochPollIntervalFlag,
RPCEnableAdmin,
Expand Down
14 changes: 14 additions & 0 deletions op-node/p2p/mocks/ConnectionGater.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions op-node/p2p/mocks/PeerGater.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 21 additions & 3 deletions op-node/p2p/peer_gater.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package p2p
import (
log "github.com/ethereum/go-ethereum/log"
peer "github.com/libp2p/go-libp2p/core/peer"
slices "golang.org/x/exp/slices"
)

// ConnectionFactor is the factor by which we multiply the connection score.
Expand All @@ -15,6 +14,7 @@ const PeerScoreThreshold = -100
// gater is an internal implementation of the [PeerGater] interface.
type gater struct {
connGater ConnectionGater
blockedMap map[peer.ID]bool
log log.Logger
banEnabled bool
}
Expand All @@ -25,33 +25,51 @@ type gater struct {
type PeerGater interface {
// Update handles a peer score update and blocks/unblocks the peer if necessary.
Update(peer.ID, float64)
// IsBlocked returns true if the given [peer.ID] is blocked.
IsBlocked(peer.ID) bool
}

// NewPeerGater returns a new peer gater.
func NewPeerGater(connGater ConnectionGater, log log.Logger, banEnabled bool) PeerGater {
return &gater{
connGater: connGater,
blockedMap: make(map[peer.ID]bool),
log: log,
banEnabled: banEnabled,
}
}

// IsBlocked returns true if the given [peer.ID] is blocked.
func (s *gater) IsBlocked(peerID peer.ID) bool {
return s.blockedMap[peerID]
}

// setBlocked sets the blocked status of the given [peer.ID].
func (s *gater) setBlocked(peerID peer.ID, blocked bool) {
s.blockedMap[peerID] = blocked
}

// Update handles a peer score update and blocks/unblocks the peer if necessary.
func (s *gater) Update(id peer.ID, score float64) {
// Check if the peer score is below the threshold
// If so, we need to block the peer
if score < PeerScoreThreshold && s.banEnabled {
isAlreadyBlocked := s.IsBlocked(id)
if score < PeerScoreThreshold && s.banEnabled && !isAlreadyBlocked {
s.log.Warn("peer blocking enabled, blocking peer", "id", id.String(), "score", score)
err := s.connGater.BlockPeer(id)
if err != nil {
s.log.Warn("connection gater failed to block peer", "id", id.String(), "err", err)
}
// Set the peer as blocked in the blocked map
s.setBlocked(id, true)
}
// Unblock peers whose score has recovered to an acceptable level
if (score > PeerScoreThreshold) && slices.Contains(s.connGater.ListBlockedPeers(), id) {
if (score > PeerScoreThreshold) && isAlreadyBlocked {
err := s.connGater.UnblockPeer(id)
if err != nil {
s.log.Warn("connection gater failed to unblock peer", "id", id.String(), "err", err)
}
// Set the peer as unblocked in the blocked map
s.setBlocked(id, false)
}
}
37 changes: 33 additions & 4 deletions op-node/p2p/peer_gater_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,30 +37,59 @@ func (testSuite *PeerGaterTestSuite) TestPeerScoreConstants() {
}

// TestPeerGaterUpdate tests the peer gater update hook.
func (testSuite *PeerGaterTestSuite) TestPeerGaterUpdate() {
func (testSuite *PeerGaterTestSuite) TestPeerGater_UpdateBansPeers() {
gater := p2p.NewPeerGater(
testSuite.mockGater,
testSuite.logger,
true,
)

// Return an empty list of already blocked peers
testSuite.mockGater.On("ListBlockedPeers").Return([]peer.ID{}).Once()

// Mock a connection gater peer block call
// Since the peer score is below the [PeerScoreThreshold] of -100,
// the [BlockPeer] method should be called
testSuite.mockGater.On("BlockPeer", peer.ID("peer1")).Return(nil)
testSuite.mockGater.On("BlockPeer", peer.ID("peer1")).Return(nil).Once()

// The peer should initially be unblocked
testSuite.False(gater.IsBlocked(peer.ID("peer1")))

// Apply the peer gater update
gater.Update(peer.ID("peer1"), float64(-100))
gater.Update(peer.ID("peer1"), float64(-101))

// The peer should be considered blocked
testSuite.True(gater.IsBlocked(peer.ID("peer1")))

// Now let's unblock the peer
testSuite.mockGater.On("UnblockPeer", peer.ID("peer1")).Return(nil).Once()
gater.Update(peer.ID("peer1"), float64(0))

// The peer should be considered unblocked
testSuite.False(gater.IsBlocked(peer.ID("peer1")))
}

// TestPeerGaterUpdateNoBanning tests the peer gater update hook without banning set
func (testSuite *PeerGaterTestSuite) TestPeerGaterUpdateNoBanning() {
func (testSuite *PeerGaterTestSuite) TestPeerGater_UpdateNoBanning() {
gater := p2p.NewPeerGater(
testSuite.mockGater,
testSuite.logger,
false,
)

// Return an empty list of already blocked peers
testSuite.mockGater.On("ListBlockedPeers").Return([]peer.ID{})

// Notice: [BlockPeer] should not be called since banning is not enabled
// even though the peer score is way below the [PeerScoreThreshold] of -100
gater.Update(peer.ID("peer1"), float64(-100000))

// The peer should be unblocked
testSuite.False(gater.IsBlocked(peer.ID("peer1")))

// Make sure that if we then "unblock" the peer, nothing happens
gater.Update(peer.ID("peer1"), float64(0))

// The peer should still be unblocked
testSuite.False(gater.IsBlocked(peer.ID("peer1")))
}
170 changes: 170 additions & 0 deletions op-node/rollup/derive/system_config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package derive

import (
"math/big"
"testing"

"github.com/ethereum-optimism/optimism/op-node/eth"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/require"
)

var (
// ABI encoding helpers
dynBytes, _ = abi.NewType("bytes", "", nil)
address, _ = abi.NewType("address", "", nil)
uint256T, _ = abi.NewType("uint256", "", nil)
addressArgs = abi.Arguments{
{Type: address},
}
bytesArgs = abi.Arguments{
{Type: dynBytes},
}
twoUint256 = abi.Arguments{
{Type: uint256T},
{Type: uint256T},
}
oneUint256 = abi.Arguments{
{Type: uint256T},
}
)

// TestProcessSystemConfigUpdateLogEvent tests the parsing of an event and mutating the
// SystemConfig. The hook will build the ABI encoded data dynamically. All tests create
// a new SystemConfig and apply a log against it and then assert that the mutated system
// config is equal to the defined system config in the test.
func TestProcessSystemConfigUpdateLogEvent(t *testing.T) {
tests := []struct {
name string
log *types.Log
config eth.SystemConfig
hook func(*testing.T, *types.Log) *types.Log
err bool
}{
{
// The log data is ignored by consensus and no modifications to the
// system config occur.
name: "SystemConfigUpdateUnsafeBlockSigner",
log: &types.Log{
Topics: []common.Hash{
ConfigUpdateEventABIHash,
ConfigUpdateEventVersion0,
SystemConfigUpdateUnsafeBlockSigner,
},
},
hook: func(t *testing.T, log *types.Log) *types.Log {
addr := common.Address{}
data, err := addressArgs.Pack(&addr)
require.NoError(t, err)
log.Data = data
return log
},
config: eth.SystemConfig{},
err: false,
},
{
// The batcher address should be updated.
name: "SystemConfigUpdateBatcher",
log: &types.Log{
Topics: []common.Hash{
ConfigUpdateEventABIHash,
ConfigUpdateEventVersion0,
SystemConfigUpdateBatcher,
},
},
hook: func(t *testing.T, log *types.Log) *types.Log {
addr := common.Address{19: 0xaa}
addrData, err := addressArgs.Pack(&addr)
require.NoError(t, err)
data, err := bytesArgs.Pack(addrData)
require.NoError(t, err)
log.Data = data
return log
},
config: eth.SystemConfig{
BatcherAddr: common.Address{19: 0xaa},
},
err: false,
},
{
// The overhead and the scalar should be updated.
name: "SystemConfigUpdateGasConfig",
log: &types.Log{
Topics: []common.Hash{
ConfigUpdateEventABIHash,
ConfigUpdateEventVersion0,
SystemConfigUpdateGasConfig,
},
},
hook: func(t *testing.T, log *types.Log) *types.Log {
overhead := big.NewInt(0xff)
scalar := big.NewInt(0xaa)
numberData, err := twoUint256.Pack(overhead, scalar)
require.NoError(t, err)
data, err := bytesArgs.Pack(numberData)
require.NoError(t, err)
log.Data = data
return log
},
config: eth.SystemConfig{
Overhead: eth.Bytes32{31: 0xff},
Scalar: eth.Bytes32{31: 0xaa},
},
err: false,
},
{
// The gas limit should be updated.
name: "SystemConfigUpdateGasLimit",
log: &types.Log{
Topics: []common.Hash{
ConfigUpdateEventABIHash,
ConfigUpdateEventVersion0,
SystemConfigUpdateGasLimit,
},
},
hook: func(t *testing.T, log *types.Log) *types.Log {
gasLimit := big.NewInt(0xbb)
numberData, err := oneUint256.Pack(gasLimit)
require.NoError(t, err)
data, err := bytesArgs.Pack(numberData)
require.NoError(t, err)
log.Data = data
return log
},
config: eth.SystemConfig{
GasLimit: 0xbb,
},
err: false,
},
{
name: "SystemConfigOneTopic",
log: &types.Log{
Topics: []common.Hash{
ConfigUpdateEventABIHash,
},
},
hook: func(t *testing.T, log *types.Log) *types.Log {
return log
},
config: eth.SystemConfig{},
err: true,
},
}

for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
config := eth.SystemConfig{}

err := ProcessSystemConfigUpdateLogEvent(&config, test.hook(t, test.log))
if test.err {
require.Error(t, err)
} else {
require.NoError(t, err)
}
require.Equal(t, config, test.config)
})
}
}
4 changes: 4 additions & 0 deletions op-node/rollup/driver/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,8 @@ type Config struct {

// SequencerStopped is false when the driver should sequence new blocks.
SequencerStopped bool `json:"sequencer_stopped"`

// SequencerMaxSafeLag is the maximum number of L2 blocks for restricting the distance between L2 safe and unsafe.
// Disabled if 0.
SequencerMaxSafeLag uint64 `json:"sequencer_max_safe_lag"`
}
Loading

0 comments on commit e9fa6f3

Please sign in to comment.