Skip to content

Commit

Permalink
[Core + API + Node] Add raw tx size limitation (#2649)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Daniel-VDM authored Mar 31, 2020
1 parent 8959b40 commit d87308b
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 3 deletions.
6 changes: 3 additions & 3 deletions core/tx_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ var DefaultTxPoolConfig = TxPoolConfig{
AccountQueue: 64,
GlobalQueue: 1024,

Lifetime: 3 * time.Hour,
Lifetime: 30 * time.Minute,

Blacklist: &map[common.Address]struct{}{},
}
Expand Down Expand Up @@ -623,8 +623,8 @@ func (pool *TxPool) local() map[common.Address]types.Transactions {
// validateTx checks whether a transaction is valid according to the consensus
// rules and adheres to some heuristic limits of the local node (price and size).
func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
// Heuristic limit, reject transactions over 32KB to prevent DOS attacks
if tx.Size() > 32*1024 {
// For DOS prevention, reject excessively large transactions.
if tx.Size() >= types.MaxPoolTransactionDataSize {
return errors.WithMessagef(ErrOversizedData, "transaction size is %s", tx.Size().String())
}
// Transactions can't be negative. This may never happen using RLP decoded
Expand Down
7 changes: 7 additions & 0 deletions core/types/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ import (
common2 "github.com/harmony-one/harmony/internal/common"
)

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)
)

// RPCTransactionError ..
type RPCTransactionError struct {
TxHashID string `json:"tx-hash-id"`
Expand Down
9 changes: 9 additions & 0 deletions internal/hmyapi/apiv1/transactionpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/ethereum/go-ethereum/rpc"
"github.com/harmony-one/harmony/accounts"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/rawdb"
"github.com/harmony-one/harmony/core/types"
internal_common "github.com/harmony-one/harmony/internal/common"
Expand Down Expand Up @@ -208,6 +209,10 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
func (s *PublicTransactionPoolAPI) SendRawStakingTransaction(
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(staking.StakingTransaction)
if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
return common.Hash{}, err
Expand All @@ -223,6 +228,10 @@ func (s *PublicTransactionPoolAPI) SendRawStakingTransaction(
// SendRawTransaction will add the signed transaction to the transaction pool.
// 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) {
if len(encodedTx) >= types.MaxEncodedPoolTransactionSize {
err := errors.Wrapf(core.ErrOversizedData, "encoded tx size: %d", len(encodedTx))
return common.Hash{}, err
}
tx := new(types.Transaction)
if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
return common.Hash{}, err
Expand Down
9 changes: 9 additions & 0 deletions internal/hmyapi/apiv2/transactionpool.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/ethereum/go-ethereum/rpc"
"github.com/harmony-one/harmony/accounts"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/core"
"github.com/harmony-one/harmony/core/rawdb"
"github.com/harmony-one/harmony/core/types"
internal_common "github.com/harmony-one/harmony/internal/common"
Expand Down Expand Up @@ -206,6 +207,10 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
func (s *PublicTransactionPoolAPI) SendRawStakingTransaction(
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(staking.StakingTransaction)
if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
return common.Hash{}, err
Expand All @@ -221,6 +226,10 @@ func (s *PublicTransactionPoolAPI) SendRawStakingTransaction(
// SendRawTransaction will add the signed transaction to the transaction pool.
// 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) {
if len(encodedTx) >= types.MaxEncodedPoolTransactionSize {
err := errors.Wrapf(core.ErrOversizedData, "encoded tx size: %d", len(encodedTx))
return common.Hash{}, err
}
tx := new(types.Transaction)
if err := rlp.DecodeBytes(encodedTx, tx); err != nil {
return common.Hash{}, err
Expand Down
16 changes: 16 additions & 0 deletions node/node_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,14 @@ func (node *Node) processStakingMessage(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 {
utils.Logger().Debug().Msgf("Invalid transaction message size")
return
}
txMessageType := proto_node.TransactionMessageType(msgPayload[0])

switch txMessageType {
Expand All @@ -211,6 +219,14 @@ func (node *Node) transactionMessageHandler(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 {
utils.Logger().Debug().Msgf("Invalid transaction message size")
return
}
txs := staking.StakingTransactions{}
err := rlp.Decode(bytes.NewReader(msgPayload[:]), &txs)
if err != nil {
Expand Down

0 comments on commit d87308b

Please sign in to comment.