2020-08-11 21:09:30 +00:00
package commands
import (
2021-05-04 01:37:17 +00:00
"bytes"
2020-08-11 21:09:30 +00:00
"context"
2021-05-04 01:37:17 +00:00
"errors"
2020-09-26 21:01:11 +00:00
"fmt"
2021-05-04 01:37:17 +00:00
"math/big"
2020-08-11 21:09:30 +00:00
2021-10-28 14:18:34 +00:00
txPoolProto "github.com/ledgerwatch/erigon-lib/gointerfaces/txpool"
2021-05-20 18:25:53 +00:00
"github.com/ledgerwatch/erigon/common"
"github.com/ledgerwatch/erigon/common/hexutil"
2021-09-18 13:58:23 +00:00
"github.com/ledgerwatch/erigon/core/rawdb"
2021-05-20 18:25:53 +00:00
"github.com/ledgerwatch/erigon/core/types"
2021-09-18 13:58:23 +00:00
"github.com/ledgerwatch/erigon/crypto"
2021-05-20 18:25:53 +00:00
"github.com/ledgerwatch/erigon/eth/ethconfig"
"github.com/ledgerwatch/erigon/params"
"github.com/ledgerwatch/erigon/rlp"
2021-07-29 10:23:23 +00:00
"github.com/ledgerwatch/log/v3"
2020-08-11 21:09:30 +00:00
)
2020-10-24 17:03:52 +00:00
// SendRawTransaction implements eth_sendRawTransaction. Creates new message call transaction or a contract creation for previously-signed transactions.
2021-03-23 09:00:07 +00:00
func ( api * APIImpl ) SendRawTransaction ( ctx context . Context , encodedTx hexutil . Bytes ) ( common . Hash , error ) {
2021-05-04 01:37:17 +00:00
txn , err := types . DecodeTransaction ( rlp . NewStream ( bytes . NewReader ( encodedTx ) , uint64 ( len ( encodedTx ) ) ) )
if err != nil {
return common . Hash { } , err
2020-09-26 21:01:11 +00:00
}
2021-05-04 01:37:17 +00:00
// If the transaction fee cap is already specified, ensure the
// fee of the given transaction is _reasonable_.
if err := checkTxFee ( txn . GetPrice ( ) . ToBig ( ) , txn . GetGas ( ) , ethconfig . Defaults . RPCTxFeeCap ) ; err != nil {
return common . Hash { } , err
}
if ! txn . Protected ( ) {
return common . Hash { } , errors . New ( "only replay-protected (EIP-155) transactions allowed over RPC" )
}
hash := txn . Hash ( )
2021-10-28 14:18:34 +00:00
res , err := api . txPool . Add ( ctx , & txPoolProto . AddRequest { RlpTxs : [ ] [ ] byte { encodedTx } } )
2021-05-04 01:37:17 +00:00
if err != nil {
return common . Hash { } , err
}
2021-10-28 14:18:34 +00:00
if res . Imported [ 0 ] != txPoolProto . ImportResult_SUCCESS {
return hash , fmt . Errorf ( "%s: %s" , txPoolProto . ImportResult_name [ int32 ( res . Imported [ 0 ] ) ] , res . Errors [ 0 ] )
2021-05-04 01:37:17 +00:00
}
2021-09-18 13:58:23 +00:00
tx , err := api . db . BeginRo ( ctx )
if err != nil {
return common . Hash { } , err
}
defer tx . Rollback ( )
// Print a log with full txn details for manual investigations and interventions
blockNum := rawdb . ReadCurrentBlockNumber ( tx )
if blockNum == nil {
return common . Hash { } , err
}
cc , err := api . chainConfig ( tx )
if err != nil {
return common . Hash { } , err
}
2022-08-11 16:44:11 +00:00
txnChainId := txn . GetChainID ( )
chainId := cc . ChainID
if chainId . Cmp ( txnChainId . ToBig ( ) ) != 0 {
return common . Hash { } , fmt . Errorf ( "invalid chain id, expected: %d got: %d" , chainId , * txnChainId )
}
2021-09-18 13:58:23 +00:00
signer := types . MakeSigner ( cc , * blockNum )
from , err := txn . Sender ( * signer )
if err != nil {
return common . Hash { } , err
}
if txn . GetTo ( ) == nil {
addr := crypto . CreateAddress ( from , txn . GetNonce ( ) )
log . Info ( "Submitted contract creation" , "hash" , txn . Hash ( ) . Hex ( ) , "from" , from , "nonce" , txn . GetNonce ( ) , "contract" , addr . Hex ( ) , "value" , txn . GetValue ( ) )
} else {
log . Info ( "Submitted transaction" , "hash" , txn . Hash ( ) . Hex ( ) , "from" , from , "nonce" , txn . GetNonce ( ) , "recipient" , txn . GetTo ( ) , "value" , txn . GetValue ( ) )
}
2021-05-04 01:37:17 +00:00
return txn . Hash ( ) , nil
2020-08-11 21:09:30 +00:00
}
2020-10-24 17:03:52 +00:00
// SendTransaction implements eth_sendTransaction. Creates new message call transaction or a contract creation if the data field contains code.
2020-11-09 08:52:18 +00:00
func ( api * APIImpl ) SendTransaction ( _ context . Context , txObject interface { } ) ( common . Hash , error ) {
return common . Hash { 0 } , fmt . Errorf ( NotImplemented , "eth_sendTransaction" )
}
2021-05-04 01:37:17 +00:00
// checkTxFee is an internal function used to check whether the fee of
// the given transaction is _reasonable_(under the cap).
func checkTxFee ( gasPrice * big . Int , gas uint64 , cap float64 ) error {
// Short circuit if there is no cap for transaction fee at all.
if cap == 0 {
return nil
}
feeEth := new ( big . Float ) . Quo ( new ( big . Float ) . SetInt ( new ( big . Int ) . Mul ( gasPrice , new ( big . Int ) . SetUint64 ( gas ) ) ) , new ( big . Float ) . SetInt ( big . NewInt ( params . Ether ) ) )
feeFloat , _ := feeEth . Float64 ( )
if feeFloat > cap {
return fmt . Errorf ( "tx fee (%.2f ether) exceeds the configured cap (%.2f ether)" , feeFloat , cap )
}
return nil
}