[Core + API + Node] Add raw tx size limitation (#2382)

* Define constants for tx-data and check size limit in tx-pool
* Check for raw data size limitation at RPC layer
* Check for raw data size limitation at Network layer
pull/2385/head
Edgar Aroutiounian 5 years ago committed by GitHub
parent 82952fe866
commit 1e5d420fbc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 6
      core/tx_pool.go
  2. 7
      core/types/tx_pool.go
  3. 9
      internal/hmyapi/apiv1/transactionpool.go
  4. 9
      internal/hmyapi/apiv2/transactionpool.go
  5. 9
      node/node_handler.go

@ -179,7 +179,7 @@ var DefaultTxPoolConfig = TxPoolConfig{
AccountQueue: 64, AccountQueue: 64,
GlobalQueue: 1024, GlobalQueue: 1024,
Lifetime: 3 * time.Hour, Lifetime: 30 * time.Minute,
Blacklist: map[common.Address]struct{}{}, Blacklist: map[common.Address]struct{}{},
} }
@ -657,8 +657,8 @@ func (pool *TxPool) validateTx(tx types.PoolTransaction, local bool) error {
if tx.ShardID() != pool.chain.CurrentBlock().ShardID() { if tx.ShardID() != pool.chain.CurrentBlock().ShardID() {
return errors.WithMessagef(ErrInvalidShard, "transaction shard is %d", tx.ShardID()) return errors.WithMessagef(ErrInvalidShard, "transaction shard is %d", tx.ShardID())
} }
// Heuristic limit, reject transactions over 32KB to prevent DOS attacks // For DOS prevention, reject excessively large transactions.
if tx.Size() > 32*1024 { if tx.Size() >= types.MaxPoolTransactionDataSize {
return errors.WithMessagef(ErrOversizedData, "transaction size is %s", tx.Size().String()) return errors.WithMessagef(ErrOversizedData, "transaction size is %s", tx.Size().String())
} }
// Transactions can't be negative. This may never happen using RLP decoded // Transactions can't be negative. This may never happen using RLP decoded

@ -11,6 +11,13 @@ import (
staking "github.com/harmony-one/harmony/staking/types" staking "github.com/harmony-one/harmony/staking/types"
) )
const (
//MaxPoolTransactionDataSize is a 32KB heuristic data limit for DOS prevention
MaxPoolTransactionDataSize = 32 * 1024
//MaxEncodedPoolTransactionSize is a heuristic raw/encoded data size limit. It has an additional 10KB for metadata
MaxEncodedPoolTransactionSize = MaxPoolTransactionDataSize + (10 * 1024)
)
var ( var (
// ErrUnknownPoolTxType is returned when attempting to assert a PoolTransaction to its concrete type // ErrUnknownPoolTxType is returned when attempting to assert a PoolTransaction to its concrete type
ErrUnknownPoolTxType = errors.New("unknown transaction type in tx-pool") ErrUnknownPoolTxType = errors.New("unknown transaction type in tx-pool")

@ -9,6 +9,7 @@ import (
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/harmony-one/harmony/accounts" "github.com/harmony-one/harmony/accounts"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/rawdb" "github.com/harmony-one/harmony/core/rawdb"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
internal_common "github.com/harmony-one/harmony/internal/common" internal_common "github.com/harmony-one/harmony/internal/common"
@ -209,6 +210,10 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
func (s *PublicTransactionPoolAPI) SendRawStakingTransaction( func (s *PublicTransactionPoolAPI) SendRawStakingTransaction(
ctx context.Context, encodedTx hexutil.Bytes, ctx context.Context, encodedTx hexutil.Bytes,
) (common.Hash, error) { ) (common.Hash, error) {
if len(encodedTx) >= types.MaxEncodedPoolTransactionSize {
err := errors.Wrapf(core.ErrOversizedData, "encoded tx size: %d", len(encodedTx))
return common.Hash{}, err
}
tx := new(staking.StakingTransaction) tx := new(staking.StakingTransaction)
if err := rlp.DecodeBytes(encodedTx, tx); err != nil { if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
return common.Hash{}, err return common.Hash{}, err
@ -224,6 +229,10 @@ func (s *PublicTransactionPoolAPI) SendRawStakingTransaction(
// SendRawTransaction will add the signed transaction to the transaction pool. // SendRawTransaction will add the signed transaction to the transaction pool.
// The sender is responsible for signing the transaction and using the correct nonce. // The sender is responsible for signing the transaction and using the correct nonce.
func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encodedTx hexutil.Bytes) (common.Hash, error) { func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encodedTx hexutil.Bytes) (common.Hash, error) {
if len(encodedTx) >= types.MaxEncodedPoolTransactionSize {
err := errors.Wrapf(core.ErrOversizedData, "encoded tx size: %d", len(encodedTx))
return common.Hash{}, err
}
tx := new(types.Transaction) tx := new(types.Transaction)
if err := rlp.DecodeBytes(encodedTx, tx); err != nil { if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
return common.Hash{}, err return common.Hash{}, err

@ -9,6 +9,7 @@ import (
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/rpc"
"github.com/harmony-one/harmony/accounts" "github.com/harmony-one/harmony/accounts"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/rawdb" "github.com/harmony-one/harmony/core/rawdb"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
internal_common "github.com/harmony-one/harmony/internal/common" internal_common "github.com/harmony-one/harmony/internal/common"
@ -207,6 +208,10 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
func (s *PublicTransactionPoolAPI) SendRawStakingTransaction( func (s *PublicTransactionPoolAPI) SendRawStakingTransaction(
ctx context.Context, encodedTx hexutil.Bytes, ctx context.Context, encodedTx hexutil.Bytes,
) (common.Hash, error) { ) (common.Hash, error) {
if len(encodedTx) >= types.MaxEncodedPoolTransactionSize {
err := errors.Wrapf(core.ErrOversizedData, "encoded tx size: %d", len(encodedTx))
return common.Hash{}, err
}
tx := new(staking.StakingTransaction) tx := new(staking.StakingTransaction)
if err := rlp.DecodeBytes(encodedTx, tx); err != nil { if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
return common.Hash{}, err return common.Hash{}, err
@ -222,6 +227,10 @@ func (s *PublicTransactionPoolAPI) SendRawStakingTransaction(
// SendRawTransaction will add the signed transaction to the transaction pool. // SendRawTransaction will add the signed transaction to the transaction pool.
// The sender is responsible for signing the transaction and using the correct nonce. // The sender is responsible for signing the transaction and using the correct nonce.
func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encodedTx hexutil.Bytes) (common.Hash, error) { func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encodedTx hexutil.Bytes) (common.Hash, error) {
if len(encodedTx) >= types.MaxEncodedPoolTransactionSize {
err := errors.Wrapf(core.ErrOversizedData, "encoded tx size: %d", len(encodedTx))
return common.Hash{}, err
}
tx := new(types.Transaction) tx := new(types.Transaction)
if err := rlp.DecodeBytes(encodedTx, tx); err != nil { if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
return common.Hash{}, err return common.Hash{}, err

@ -13,6 +13,7 @@ import (
proto_discovery "github.com/harmony-one/harmony/api/proto/discovery" proto_discovery "github.com/harmony-one/harmony/api/proto/discovery"
proto_node "github.com/harmony-one/harmony/api/proto/node" proto_node "github.com/harmony-one/harmony/api/proto/node"
"github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/types" "github.com/harmony-one/harmony/core/types"
nodeconfig "github.com/harmony-one/harmony/internal/configs/node" nodeconfig "github.com/harmony-one/harmony/internal/configs/node"
"github.com/harmony-one/harmony/internal/ctxerror" "github.com/harmony-one/harmony/internal/ctxerror"
@ -187,6 +188,10 @@ func (node *Node) HandleMessage(content []byte, sender libp2p_peer.ID) {
} }
func (node *Node) transactionMessageHandler(msgPayload []byte) { func (node *Node) transactionMessageHandler(msgPayload []byte) {
if len(msgPayload) >= types.MaxEncodedPoolTransactionSize {
utils.Logger().Warn().Err(core.ErrOversizedData).Msgf("encoded tx size: %d", len(msgPayload))
return
}
if len(msgPayload) < 1 { if len(msgPayload) < 1 {
utils.Logger().Debug().Msgf("Invalid transaction message size") utils.Logger().Debug().Msgf("Invalid transaction message size")
return return
@ -208,6 +213,10 @@ func (node *Node) transactionMessageHandler(msgPayload []byte) {
} }
func (node *Node) stakingMessageHandler(msgPayload []byte) { func (node *Node) stakingMessageHandler(msgPayload []byte) {
if len(msgPayload) >= types.MaxEncodedPoolTransactionSize {
utils.Logger().Warn().Err(core.ErrOversizedData).Msgf("encoded tx size: %d", len(msgPayload))
return
}
if len(msgPayload) < 1 { if len(msgPayload) < 1 {
utils.Logger().Debug().Msgf("Invalid staking transaction message size") utils.Logger().Debug().Msgf("Invalid staking transaction message size")
return return

Loading…
Cancel
Save