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

core,eth,internal/cli,internal/ethapi: add --rpc.allow-unprotected-txs flag to allow txs to get replayed (for shadow node) #705

Merged
merged 4 commits into from
Mar 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion builder/files/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ syncmode = "full"
# snapshot = true
# "bor.logs" = false
# ethstats = ""

# devfakeauthor = false
# ["eth.requiredblocks"]

[p2p]
Expand Down Expand Up @@ -65,6 +65,7 @@ syncmode = "full"
# ipcpath = ""
# gascap = 50000000
# txfeecap = 5.0
# allow-unprotected-txs = false
# [jsonrpc.http]
# enabled = false
# port = 8545
Expand Down
18 changes: 17 additions & 1 deletion consensus/bor/bor.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,8 @@ type Bor struct {
HeimdallClient IHeimdallClient

// The fields below are for testing only
fakeDiff bool // Skip difficulty verifications
fakeDiff bool // Skip difficulty verifications
devFakeAuthor bool

closeOnce sync.Once
}
Expand All @@ -245,6 +246,7 @@ func New(
spanner Spanner,
heimdallClient IHeimdallClient,
genesisContracts GenesisContract,
devFakeAuthor bool,
) *Bor {
// get bor config
borConfig := chainConfig.Bor
Expand All @@ -267,6 +269,7 @@ func New(
spanner: spanner,
GenesisContractsClient: genesisContracts,
HeimdallClient: heimdallClient,
devFakeAuthor: devFakeAuthor,
}

c.authorizedSigner.Store(&signer{
Expand Down Expand Up @@ -480,6 +483,19 @@ func (c *Bor) verifyCascadingFields(chain consensus.ChainHeaderReader, header *t
// nolint: gocognit
func (c *Bor) snapshot(chain consensus.ChainHeaderReader, number uint64, hash common.Hash, parents []*types.Header) (*Snapshot, error) {
// Search for a snapshot in memory or on disk for checkpoints

signer := common.BytesToAddress(c.authorizedSigner.Load().signer.Bytes())
if c.devFakeAuthor && signer.String() != "0x0000000000000000000000000000000000000000" {
log.Info("👨‍💻Using DevFakeAuthor", "signer", signer)

val := valset.NewValidator(signer, 1000)
validatorset := valset.NewValidatorSet([]*valset.Validator{val})

snapshot := newSnapshot(c.config, c.signatures, number, hash, validatorset.Validators)

return snapshot, nil
}

var snap *Snapshot

headers := make([]*types.Header, 0, 16)
Expand Down
19 changes: 10 additions & 9 deletions consensus/bor/valset/validator_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ func (vals *ValidatorSet) UpdateTotalVotingPower() error {
// It recomputes the total voting power if required.
func (vals *ValidatorSet) TotalVotingPower() int64 {
if vals.totalVotingPower == 0 {
log.Info("invoking updateTotalVotingPower before returning it")
log.Debug("invoking updateTotalVotingPower before returning it")

if err := vals.UpdateTotalVotingPower(); err != nil {
// Can/should we do better?
Expand Down Expand Up @@ -641,14 +641,15 @@ func (vals *ValidatorSet) UpdateValidatorMap() {

// UpdateWithChangeSet attempts to update the validator set with 'changes'.
// It performs the following steps:
// - validates the changes making sure there are no duplicates and splits them in updates and deletes
// - verifies that applying the changes will not result in errors
// - computes the total voting power BEFORE removals to ensure that in the next steps the priorities
// across old and newly added validators are fair
// - computes the priorities of new validators against the final set
// - applies the updates against the validator set
// - applies the removals against the validator set
// - performs scaling and centering of priority values
// - validates the changes making sure there are no duplicates and splits them in updates and deletes
// - verifies that applying the changes will not result in errors
// - computes the total voting power BEFORE removals to ensure that in the next steps the priorities
// across old and newly added validators are fair
// - computes the priorities of new validators against the final set
// - applies the updates against the validator set
// - applies the removals against the validator set
// - performs scaling and centering of priority values
//
// If an error is detected during verification steps, it is returned and the validator set
// is not changed.
func (vals *ValidatorSet) UpdateWithChangeSet(changes []*Validator) error {
Expand Down
20 changes: 16 additions & 4 deletions core/tx_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,8 @@ type TxPoolConfig struct {
AccountQueue uint64 // Maximum number of non-executable transaction slots permitted per account
GlobalQueue uint64 // Maximum number of non-executable transaction slots for all accounts

Lifetime time.Duration // Maximum amount of time non-executable transaction are queued
Lifetime time.Duration // Maximum amount of time non-executable transaction are queued
AllowUnprotectedTxs bool // Allow non-EIP-155 transactions
}

// DefaultTxPoolConfig contains the default configurations for the transaction
Expand All @@ -191,7 +192,8 @@ var DefaultTxPoolConfig = TxPoolConfig{
AccountQueue: 64,
GlobalQueue: 1024,

Lifetime: 3 * time.Hour,
Lifetime: 3 * time.Hour,
AllowUnprotectedTxs: false,
}

// sanitize checks the provided user configurations and changes anything that's
Expand Down Expand Up @@ -759,7 +761,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {

// Make sure the transaction is signed properly.
from, err := types.Sender(pool.signer, tx)
if err != nil {
if err != nil && !pool.config.AllowUnprotectedTxs {
return ErrInvalidSender
}

Expand Down Expand Up @@ -1096,6 +1098,11 @@ func (pool *TxPool) addTxs(txs []*types.Transaction, local, sync bool) []error {
// Exclude transactions with invalid signatures as soon as
// possible and cache senders in transactions before
// obtaining lock

if pool.config.AllowUnprotectedTxs {
pool.signer = types.NewFakeSigner(tx.ChainId())
}

_, err = types.Sender(pool.signer, tx)
if err != nil {
errs = append(errs, ErrInvalidSender)
Expand Down Expand Up @@ -1149,11 +1156,16 @@ func (pool *TxPool) addTx(tx *types.Transaction, local, sync bool) error {
// Exclude transactions with invalid signatures as soon as
// possible and cache senders in transactions before
// obtaining lock
if pool.config.AllowUnprotectedTxs {
pool.signer = types.NewFakeSigner(tx.ChainId())
}

_, err = types.Sender(pool.signer, tx)
if err != nil {
invalidTxMeter.Mark(1)

return
} else {
err = nil
}
}()

Expand Down
47 changes: 47 additions & 0 deletions core/tx_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -954,6 +954,53 @@ func TestTransactionQueueAccountLimiting(t *testing.T) {
}
}

// Test that txpool rejects unprotected txs by default
// FIXME: The below test causes some tests to fail randomly (probably due to parallel execution)
//
//nolint:paralleltest
func TestRejectUnprotectedTransaction(t *testing.T) {
//nolint:paralleltest
t.Skip()

pool, key := setupTxPool()
defer pool.Stop()

tx := dynamicFeeTx(0, 22000, big.NewInt(5), big.NewInt(2), key)
from := crypto.PubkeyToAddress(key.PublicKey)

pool.chainconfig.ChainID = big.NewInt(5)
pool.signer = types.LatestSignerForChainID(pool.chainconfig.ChainID)
testAddBalance(pool, from, big.NewInt(0xffffffffffffff))

if err := pool.AddRemote(tx); !errors.Is(err, types.ErrInvalidChainId) {
t.Error("expected", types.ErrInvalidChainId, "got", err)
}
}

// Test that txpool allows unprotected txs when AllowUnprotectedTxs flag is set
// FIXME: The below test causes some tests to fail randomly (probably due to parallel execution)
//
//nolint:paralleltest
func TestAllowUnprotectedTransactionWhenSet(t *testing.T) {
t.Skip()

pool, key := setupTxPool()
defer pool.Stop()

tx := dynamicFeeTx(0, 22000, big.NewInt(5), big.NewInt(2), key)
from := crypto.PubkeyToAddress(key.PublicKey)

// Allow unprotected txs
pool.config.AllowUnprotectedTxs = true
pool.chainconfig.ChainID = big.NewInt(5)
pool.signer = types.LatestSignerForChainID(pool.chainconfig.ChainID)
testAddBalance(pool, from, big.NewInt(0xffffffffffffff))

if err := pool.AddRemote(tx); err != nil {
t.Error("expected", nil, "got", err)
}
}

// Tests that if the transaction count belonging to multiple accounts go above
// some threshold, the higher transactions are dropped to prevent DOS attacks.
//
Expand Down
36 changes: 36 additions & 0 deletions core/types/transaction_signing.go
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,42 @@ func (fs FrontierSigner) Hash(tx *Transaction) common.Hash {
})
}

// FakeSigner implements the Signer interface and accepts unprotected transactions
type FakeSigner struct{ londonSigner }

var _ Signer = FakeSigner{}

func NewFakeSigner(chainId *big.Int) Signer {
signer := NewLondonSigner(chainId)
ls, _ := signer.(londonSigner)

return FakeSigner{londonSigner: ls}
}

func (f FakeSigner) Sender(tx *Transaction) (common.Address, error) {
return f.londonSigner.Sender(tx)
}

func (f FakeSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error) {
return f.londonSigner.SignatureValues(tx, sig)
}

func (f FakeSigner) ChainID() *big.Int {
return f.londonSigner.ChainID()
}

// Hash returns 'signature hash', i.e. the transaction hash that is signed by the
// private key. This hash does not uniquely identify the transaction.
func (f FakeSigner) Hash(tx *Transaction) common.Hash {
return f.londonSigner.Hash(tx)
}

// Equal returns true if the given signer is the same as the receiver.
func (f FakeSigner) Equal(Signer) bool {
// Always return true
return true
}

func decodeSignature(sig []byte) (r, s, v *big.Int) {
if len(sig) != crypto.SignatureLength {
panic(fmt.Sprintf("wrong size for signature: got %d, want %d", len(sig), crypto.SignatureLength))
Expand Down
2 changes: 2 additions & 0 deletions docs/cli/example_config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ gcmode = "full" # Blockchain garbage collection mode ("full", "arch
snapshot = true # Enables the snapshot-database mode
"bor.logs" = false # Enables bor log retrieval
ethstats = "" # Reporting URL of a ethstats service (nodename:secret@host:port)
devfakeauthor = false # Run miner without validator set authorization [dev mode] : Use with '--bor.withoutheimdall' (default: false)

["eth.requiredblocks"] # Comma separated block number-to-hash mappings to require for peering (<number>=<hash>) (default = empty map)
"31000000" = "0x2087b9e2b353209c2c21e370c82daa12278efd0fe5f0febe6c29035352cf050e"
Expand Down Expand Up @@ -64,6 +65,7 @@ ethstats = "" # Reporting URL of a ethstats service (nodename:sec
ipcpath = "" # Filename for IPC socket/pipe within the datadir (explicit paths escape it)
gascap = 50000000 # Sets a cap on gas that can be used in eth_call/estimateGas (0=infinite)
txfeecap = 5.0 # Sets a cap on transaction fee (in ether) that can be sent via the RPC APIs (0 = no cap)
allow-unprotected-txs = false # Allow for unprotected (non EIP155 signed) transactions to be submitted via RPC (default: false)
[jsonrpc.http]
enabled = false # Enable the HTTP-RPC server
port = 8545 # http.port
Expand Down
8 changes: 8 additions & 0 deletions docs/cli/server.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,14 @@ The ```bor server``` command runs the Bor client.

- ```bor.withoutheimdall```: Run without Heimdall service (for testing purpose) (default: false)

- ```bor.devfakeauthor```: Run miner without validator set authorization [dev mode] : Use with '--bor.withoutheimdall' (default: false)

- ```bor.heimdallgRPC```: Address of Heimdall gRPC service

- ```bor.runheimdall```: Run Heimdall service as a child process (default: false)

- ```bor.runheimdallargs```: Arguments to pass to Heimdall service

- ```ethstats```: Reporting URL of a ethstats service (nodename:secret@host:port)

- ```gpo.blocks```: Number of recent blocks to check for gas prices (default: 20)
Expand Down Expand Up @@ -92,6 +98,8 @@ The ```bor server``` command runs the Bor client.

- ```rpc.txfeecap```: Sets a cap on transaction fee (in ether) that can be sent via the RPC APIs (0 = no cap) (default: 5)

- ```rpc.allow-unprotected-txs```: Allow for unprotected (non EIP155 signed) transactions to be submitted via RPC (default: false)

- ```ipcdisable```: Disable the IPC-RPC server (default: false)

- ```ipcpath```: Filename for IPC socket/pipe within the datadir (explicit paths escape it)
Expand Down
4 changes: 3 additions & 1 deletion eth/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,9 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
// START: Bor changes
eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), stack.Config().AllowUnprotectedTxs, eth, nil}
if eth.APIBackend.allowUnprotectedTxs {
log.Info("Unprotected transactions allowed")
log.Debug(" ###########", "Unprotected transactions allowed")

config.TxPool.AllowUnprotectedTxs = true
}
gpoParams := config.GPO
if gpoParams.Default == nil {
Expand Down
10 changes: 8 additions & 2 deletions eth/ethconfig/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ type Config struct {

// OverrideTerminalTotalDifficulty (TODO: remove after the fork)
OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"`

// Develop Fake Author mode to produce blocks without authorisation
DevFakeAuthor bool `hcl:"devfakeauthor,optional" toml:"devfakeauthor,optional"`
}

// CreateConsensusEngine creates a consensus engine for the given chain configuration.
Expand All @@ -255,16 +258,19 @@ func CreateConsensusEngine(stack *node.Node, chainConfig *params.ChainConfig, et
spanner := span.NewChainSpanner(blockchainAPI, contract.ValidatorSet(), chainConfig, common.HexToAddress(chainConfig.Bor.ValidatorContract))

if ethConfig.WithoutHeimdall {
return bor.New(chainConfig, db, blockchainAPI, spanner, nil, genesisContractsClient)
return bor.New(chainConfig, db, blockchainAPI, spanner, nil, genesisContractsClient, ethConfig.DevFakeAuthor)
} else {
if ethConfig.DevFakeAuthor {
log.Warn("Sanitizing DevFakeAuthor", "Use DevFakeAuthor with", "--bor.withoutheimdall")
}
var heimdallClient bor.IHeimdallClient
if ethConfig.HeimdallgRPCAddress != "" {
heimdallClient = heimdallgrpc.NewHeimdallGRPCClient(ethConfig.HeimdallgRPCAddress)
} else {
heimdallClient = heimdall.NewHeimdallClient(ethConfig.HeimdallURL)
}

return bor.New(chainConfig, db, blockchainAPI, spanner, heimdallClient, genesisContractsClient)
return bor.New(chainConfig, db, blockchainAPI, spanner, heimdallClient, genesisContractsClient, false)
}
} else {
switch config.PowMode {
Expand Down
19 changes: 15 additions & 4 deletions internal/cli/server/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ type Config struct {

// Developer has the developer mode related settings
Developer *DeveloperConfig `hcl:"developer,block" toml:"developer,block"`

// Develop Fake Author mode to produce blocks without authorisation
DevFakeAuthor bool `hcl:"devfakeauthor,optional" toml:"devfakeauthor,optional"`
}

type P2PConfig struct {
Expand Down Expand Up @@ -251,6 +254,8 @@ type JsonRPCConfig struct {
Graphql *APIConfig `hcl:"graphql,block" toml:"graphql,block"`

HttpTimeout *HttpTimeouts `hcl:"timeouts,block" toml:"timeouts,block"`

AllowUnprotectedTxs bool `hcl:"allow-unprotected-txs,optional" toml:"allow-unprotected-txs,optional"`
}

type GRPCConfig struct {
Expand Down Expand Up @@ -501,10 +506,11 @@ func DefaultConfig() *Config {
IgnorePrice: gasprice.DefaultIgnorePrice,
},
JsonRPC: &JsonRPCConfig{
IPCDisable: false,
IPCPath: "",
GasCap: ethconfig.Defaults.RPCGasCap,
TxFeeCap: ethconfig.Defaults.RPCTxFeeCap,
IPCDisable: false,
IPCPath: "",
GasCap: ethconfig.Defaults.RPCGasCap,
TxFeeCap: ethconfig.Defaults.RPCTxFeeCap,
AllowUnprotectedTxs: false,
Http: &APIConfig{
Enabled: false,
Port: 8545,
Expand Down Expand Up @@ -580,6 +586,7 @@ func DefaultConfig() *Config {
Enabled: false,
Period: 0,
},
DevFakeAuthor: false,
}
}

Expand Down Expand Up @@ -713,6 +720,9 @@ func (c *Config) buildEth(stack *node.Node, accountManager *accounts.Manager) (*
n.RunHeimdall = c.Heimdall.RunHeimdall
n.RunHeimdallArgs = c.Heimdall.RunHeimdallArgs

// Developer Fake Author for producing blocks without authorisation on bor consensus
n.DevFakeAuthor = c.DevFakeAuthor

// gas price oracle
{
n.GPO.Blocks = int(c.Gpo.Blocks)
Expand Down Expand Up @@ -1042,6 +1052,7 @@ func (c *Config) buildNode() (*node.Config, error) {
InsecureUnlockAllowed: c.Accounts.AllowInsecureUnlock,
Version: params.VersionWithCommit(gitCommit, gitDate),
IPCPath: ipcPath,
AllowUnprotectedTxs: c.JsonRPC.AllowUnprotectedTxs,
P2P: p2p.Config{
MaxPeers: int(c.P2P.MaxPeers),
MaxPendingPeers: int(c.P2P.MaxPendPeers),
Expand Down
Loading