From 0a334e1bf30d488dc893cfaf0293c145146579dc Mon Sep 17 00:00:00 2001 From: esuwu Date: Mon, 13 Dec 2021 18:07:46 +0300 Subject: [PATCH 1/7] Moved basic check to initialization, big int changed to int --- pkg/proto/eth_transaction.go | 138 ++++++++++++++++++++++++++----- pkg/proto/eth_utils.go | 10 +-- pkg/state/appender.go | 5 +- pkg/state/eth_info.go | 70 ++++------------ pkg/state/transaction_checker.go | 11 +-- pkg/state/transaction_differ.go | 12 +-- 6 files changed, 145 insertions(+), 101 deletions(-) diff --git a/pkg/proto/eth_transaction.go b/pkg/proto/eth_transaction.go index 068b3cb22..ab31c36eb 100644 --- a/pkg/proto/eth_transaction.go +++ b/pkg/proto/eth_transaction.go @@ -27,6 +27,12 @@ const ( EthereumDynamicFeeTxType ) +const ( + EthereumTransferWavesKind = iota + 1 + EthereumTransferAssetsKind + EthereumInvokeKind +) + const ( EthereumTransferMinFee uint64 = 100_000 EthereumScriptedAssetMinFee uint64 = 400_000 @@ -112,10 +118,10 @@ func (tx *EthereumTransferWavesTxKind) String() string { type EthereumTransferAssetsErc20TxKind struct { decodedData ethabi.DecodedCallData Arguments ethabi.ERC20TransferArguments - Asset OptionalAsset + Asset *OptionalAsset } -func NewEthereumTransferAssetsErc20TxKind(decodedData ethabi.DecodedCallData, asset OptionalAsset, arguments ethabi.ERC20TransferArguments) *EthereumTransferAssetsErc20TxKind { +func NewEthereumTransferAssetsErc20TxKind(decodedData ethabi.DecodedCallData, asset *OptionalAsset, arguments ethabi.ERC20TransferArguments) *EthereumTransferAssetsErc20TxKind { return &EthereumTransferAssetsErc20TxKind{Asset: asset, decodedData: decodedData, Arguments: arguments} } @@ -128,15 +134,15 @@ func (tx *EthereumTransferAssetsErc20TxKind) String() string { } type EthereumInvokeScriptTxKind struct { - decodedData ethabi.DecodedCallData + DecodedCallData *ethabi.DecodedCallData } -func NewEthereumInvokeScriptTxKind(decodedData ethabi.DecodedCallData) *EthereumInvokeScriptTxKind { - return &EthereumInvokeScriptTxKind{decodedData: decodedData} +func NewEthereumInvokeScriptTxKind(decodedData *ethabi.DecodedCallData) *EthereumInvokeScriptTxKind { + return &EthereumInvokeScriptTxKind{DecodedCallData: decodedData} } func (tx *EthereumInvokeScriptTxKind) DecodedData() *ethabi.DecodedCallData { - return &tx.decodedData + return tx.DecodedCallData } func (tx *EthereumInvokeScriptTxKind) String() string { @@ -145,6 +151,9 @@ func (tx *EthereumInvokeScriptTxKind) String() string { type EthereumTransaction struct { inner EthereumTxData + value int64 + chainID int64 + gasPrice uint64 innerBinarySize int senderPK atomic.Value // *EthereumPublicKey TxKind EthereumTransactionKind @@ -215,7 +224,7 @@ func (tx *EthereumTransaction) Verify() (*EthereumPublicKey, error) { if senderPK := tx.threadSafeGetSenderPK(); senderPK != nil { return senderPK, nil } - signer := MakeEthereumSigner(tx.ChainId()) + signer := MakeEthereumSigner(tx.inner.chainID()) senderPK, err := signer.SenderPK(tx) if err != nil { return nil, errors.Wrap(err, "failed to verify EthereumTransaction") @@ -228,9 +237,9 @@ func (tx *EthereumTransaction) Verify() (*EthereumPublicKey, error) { // This method doesn't include signature verification. Use Verify method for signature verification func (tx *EthereumTransaction) Validate(scheme Scheme) (Transaction, error) { // same chainID - if tx.ChainId().Cmp(big.NewInt(int64(scheme))) != 0 { + if tx.ChainId() != int64(scheme){ // TODO: introduce new error type for scheme validation - txChainID := tx.ChainId().Uint64() + txChainID := tx.ChainId() return nil, errs.NewTxValidationError(fmt.Sprintf( "Address belongs to another network: expected: %d(%c), actual: %d(%c)", scheme, scheme, @@ -250,6 +259,7 @@ func (tx *EthereumTransaction) Validate(scheme Scheme) (Transaction, error) { return nil, errs.NewFeeValidation("insufficient fee") } // too many waves (this check doesn't exist in scala) + // TODO I'm not sure this is should be checked for all eth tx kinds. Only for transfer waves kind wavelets, err := EthereumWeiToWavelet(tx.Value()) if err != nil { return nil, errs.NewFeeValidation(err.Error()) @@ -259,15 +269,15 @@ func (tx *EthereumTransaction) Validate(scheme Scheme) (Transaction, error) { return nil, errs.NewNonPositiveAmount(wavelets, "waves") } // a cancel transaction: value == 0 && data == 0x - if tx.Value().Cmp(big0) == 0 && len(tx.Data()) == 0 { + if tx.Value() == 0 && len(tx.Data()) == 0 { return nil, errs.NewTxValidationError("Transaction cancellation is not supported") } // either data or value field is set - if tx.Value().Cmp(big0) != 0 && len(tx.Data()) != 0 { + if tx.Value() != 0 && len(tx.Data()) != 0 { return nil, errs.NewTxValidationError("Transaction should have either data or value") } // gasPrice == 10GWei - if tx.GasPrice().Cmp(new(big.Int).SetUint64(EthereumGasPrice)) != 0 { + if tx.GasPrice() != EthereumGasPrice { return nil, errs.NewTxValidationError("Gas price must be 10 Gwei") } // deny a contract creation transaction (this check doesn't exist in scala) @@ -375,8 +385,8 @@ func (tx *EthereumTransaction) EthereumTxType() EthereumTxType { // ChainId returns the EIP155 chain ID of the transaction. The return value will always be // non-nil. For legacy transactions which are not replay-protected, the return value is // zero. -func (tx *EthereumTransaction) ChainId() *big.Int { - return tx.inner.chainID() +func (tx *EthereumTransaction) ChainId() int64 { + return tx.chainID } // Data returns the input data of the transaction. @@ -389,16 +399,10 @@ func (tx *EthereumTransaction) AccessList() EthereumAccessList { return tx.inner func (tx *EthereumTransaction) Gas() uint64 { return tx.inner.gas() } // GasPrice returns the gas price of the transaction. -func (tx *EthereumTransaction) GasPrice() *big.Int { return copyBigInt(tx.inner.gasPrice()) } - -// GasTipCap returns the gasTipCap per gas of the transaction. -func (tx *EthereumTransaction) GasTipCap() *big.Int { return copyBigInt(tx.inner.gasTipCap()) } - -// GasFeeCap returns the fee cap per gas of the transaction. -func (tx *EthereumTransaction) GasFeeCap() *big.Int { return copyBigInt(tx.inner.gasFeeCap()) } +func (tx *EthereumTransaction) GasPrice() uint64 { return tx.gasPrice } // Value returns the ether amount of the transaction. -func (tx *EthereumTransaction) Value() *big.Int { return copyBigInt(tx.inner.value()) } +func (tx *EthereumTransaction) Value() int64 { return tx.value } // Nonce returns the sender account nonce of the transaction. func (tx *EthereumTransaction) Nonce() uint64 { return tx.inner.nonce() } @@ -458,6 +462,78 @@ func (tx *EthereumTransaction) RawSignatureValues() (v, r, s *big.Int) { return tx.inner.rawSignatureValues() } +func validateEthereumTx(tx *EthereumTransaction) error { + switch _ := tx.TxKind.(type) { + case *EthereumTransferWavesTxKind: + res := new(big.Int).Div(tx.inner.value(), big.NewInt(int64(DiffEthWaves))) + if ok := res.IsInt64(); !ok { + return errors.Errorf("failed to convert amount from ethreum transaction (big int) to int64. value is %d", tx.Value()) + } + if res.Int64() == 0 { + return errors.New("the amount of ethereum transfer waves is 0, which is forbidden") + } + tx.value = res.Int64() + return nil + case *EthereumTransferAssetsErc20TxKind: + return nil + case *EthereumInvokeScriptTxKind: + return nil + default: + return errors.New("failed to check ethereum transaction, wrong kind of tx") + } +} + +func GuessEthereumTransactionKind(data []byte) (int64, error) { + if len(data) == 0 { + return EthereumTransferWavesKind, nil + } + + selectorBytes := data + if len(data) < ethabi.SelectorSize { + return 0, errors.Errorf("length of data from ethereum transaction is less than %d", ethabi.SelectorSize) + } + selector, err := ethabi.NewSelectorFromBytes(selectorBytes[:ethabi.SelectorSize]) + if err != nil { + return 0, errors.Wrap(err, "failed to guess ethereum transaction kind") + } + + if ethabi.IsERC20TransferSelector(selector) { + return EthereumTransferAssetsKind, nil + } + + return EthereumInvokeKind, nil +} +func ethereumTransactionKind(ethTx EthereumTransaction) (EthereumTransactionKind, error) { + txKind, err := GuessEthereumTransactionKind(ethTx.Data()) + if err != nil { + return nil, errors.Wrap(err, "failed to guess ethereum tx kind") + } + + switch txKind { + case EthereumTransferWavesKind: + return NewEthereumTransferWavesTxKind(), nil + case EthereumTransferAssetsKind: + db := ethabi.NewErc20MethodsMap() + decodedData, err := db.ParseCallDataRide(ethTx.Data()) + if err != nil { + return nil, errors.Errorf("failed to parse ethereum data") + } + if len(decodedData.Inputs) != ethabi.NumberOfERC20TransferArguments { + return nil, errors.Errorf("the number of arguments of erc20 function is %d, but expected it to be %d", len(decodedData.Inputs), ethabi.NumberOfERC20TransferArguments) + } + + erc20Arguments, err := ethabi.GetERC20TransferArguments(decodedData) + if err != nil { + return nil, errors.Wrap(err, "failed to get erc20 arguments from decoded data") + } + return NewEthereumTransferAssetsErc20TxKind(*decodedData, nil, erc20Arguments), nil + case EthereumInvokeKind: + return NewEthereumInvokeScriptTxKind(nil), nil + default: + return nil, errors.New("unexpected ethereum tx kind") + } +} + // DecodeCanonical decodes the canonical binary encoding of transactions. // It supports legacy RLP transactions and EIP2718 typed transactions. func (tx *EthereumTransaction) DecodeCanonical(canonicalData []byte) error { @@ -488,6 +564,24 @@ func (tx *EthereumTransaction) DecodeCanonical(canonicalData []byte) error { tx.inner = inner } tx.innerBinarySize = len(canonicalData) + + if ok := tx.inner.chainID().IsInt64(); !ok { + return errors.Errorf("failed to recognize chainID of ethereum transaction: over int64") + } + tx.chainID = tx.inner.chainID().Int64() + if ok := tx.inner.gasPrice().IsUint64(); !ok { + return errors.Errorf("failed to recognize GasPrice of ethereum transaction: over uint64") + } + tx.gasPrice = tx.inner.gasPrice().Uint64() + var err error + tx.TxKind, err = ethereumTransactionKind(*tx) + if err != nil { + return errors.Errorf("failed to guess ethereum transaction kind, %v", err) + } + err = validateEthereumTx(tx) + if err != nil { + return errors.Errorf("validation of ethereum transaction after initialization failed , %v", err) + } return nil } diff --git a/pkg/proto/eth_utils.go b/pkg/proto/eth_utils.go index 1ae508407..d9f84dd2d 100644 --- a/pkg/proto/eth_utils.go +++ b/pkg/proto/eth_utils.go @@ -21,12 +21,10 @@ func WaveletToEthereumWei(waveletAmount uint64) *big.Int { ) } -func EthereumWeiToWavelet(weiAmount *big.Int) (int64, error) { - wavelets := new(big.Int).Div(weiAmount, new(big.Int).SetUint64(waveletToWeiMultiplier)) - if !wavelets.IsInt64() { - return 0, errors.Errorf("too many wavelets=%d", wavelets) - } - return wavelets.Int64(), nil +func EthereumWeiToWavelet(weiAmount int64) (int64, error) { + wavelets := weiAmount / int64(waveletToWeiMultiplier) + + return wavelets, nil } func unmarshalTransactionToFieldFastRLP(value *fastrlp.Value) (*EthereumAddress, error) { diff --git a/pkg/state/appender.go b/pkg/state/appender.go index 77f008c62..99bdf9da7 100644 --- a/pkg/state/appender.go +++ b/pkg/state/appender.go @@ -470,10 +470,11 @@ func (a *txAppender) appendTx(tx proto.Transaction, params *appendTxParams) erro if !ok { return errors.New("failed to cast interface transaction to ethereum transaction structure") } - ethTx.TxKind, err = a.ethInfo.ethereumTransactionKind(ethTx, params) + err := a.ethInfo.fillRequiredTxFields(ethTx, params) if err != nil { - return errors.Errorf("failed to guess ethereum transaction kind, %v", err) + return errors.Errorf("failed to fill required fields in ethereum transaction, %v", err) } + switch ethTx.TxKind.(type) { case *proto.EthereumTransferWavesTxKind, *proto.EthereumTransferAssetsErc20TxKind: applicationRes, err = a.handleDefaultTransaction(tx, params, accountHasVerifierScript) diff --git a/pkg/state/eth_info.go b/pkg/state/eth_info.go index d8d4bbf78..03defc8b9 100644 --- a/pkg/state/eth_info.go +++ b/pkg/state/eth_info.go @@ -7,12 +7,6 @@ import ( "github.com/wavesplatform/gowaves/pkg/settings" ) -const ( - EthereumTransferWavesKind = iota + 1 - EthereumTransferAssetsKind - EthereumInvokeKind -) - type ethInfo struct { stor *blockchainEntitiesStorage settings *settings.BlockchainSettings @@ -22,79 +16,49 @@ func newEthInfo(stor *blockchainEntitiesStorage, settings *settings.BlockchainSe return ðInfo{stor: stor, settings: settings} } -func GuessEthereumTransactionKind(data []byte) (int64, error) { - if len(data) == 0 { - return EthereumTransferWavesKind, nil - } - - selectorBytes := data - if len(data) < ethabi.SelectorSize { - return 0, errors.Errorf("length of data from ethereum transaction is less than %d", ethabi.SelectorSize) - } - selector, err := ethabi.NewSelectorFromBytes(selectorBytes[:ethabi.SelectorSize]) - if err != nil { - return 0, errors.Wrap(err, "failed to guess ethereum transaction kind") - } - - if ethabi.IsERC20TransferSelector(selector) { - return EthereumTransferAssetsKind, nil - } - - return EthereumInvokeKind, nil -} - -func (e *ethInfo) ethereumTransactionKind(ethTx *proto.EthereumTransaction, params *appendTxParams) (proto.EthereumTransactionKind, error) { - txKind, err := GuessEthereumTransactionKind(ethTx.Data()) - if err != nil { - return nil, errors.Wrap(err, "failed to guess ethereum tx kind") - } - - switch txKind { - case EthereumTransferWavesKind: - return proto.NewEthereumTransferWavesTxKind(), nil - case EthereumTransferAssetsKind: +func (e *ethInfo) fillRequiredTxFields(ethTx *proto.EthereumTransaction, params *appendTxParams) error { + switch kind := ethTx.TxKind.(type) { + case *proto.EthereumTransferWavesTxKind: + case *proto.EthereumTransferAssetsErc20TxKind: db := ethabi.NewErc20MethodsMap() decodedData, err := db.ParseCallDataRide(ethTx.Data()) if err != nil { - return nil, errors.Errorf("failed to parse ethereum data") + return errors.Errorf("failed to parse ethereum data") } if len(decodedData.Inputs) != ethabi.NumberOfERC20TransferArguments { - return nil, errors.Errorf("the number of arguments of erc20 function is %d, but expected it to be %d", len(decodedData.Inputs), ethabi.NumberOfERC20TransferArguments) + return errors.Errorf("the number of arguments of erc20 function is %d, but expected it to be %d", len(decodedData.Inputs), ethabi.NumberOfERC20TransferArguments) } assetID := (*proto.AssetID)(ethTx.To()) - assetInfo, err := e.stor.assets.newestAssetInfo(*assetID, true) if err != nil { - return nil, errors.Wrap(err, "failed to get asset info") + return errors.Wrap(err, "failed to get asset info") } fullAssetID := proto.ReconstructDigest(*assetID, assetInfo.tail) - erc20Arguments, err := ethabi.GetERC20TransferArguments(decodedData) - if err != nil { - return nil, errors.Wrap(err, "failed to get erc20 arguments from decoded data") - } - return proto.NewEthereumTransferAssetsErc20TxKind(*decodedData, *proto.NewOptionalAssetFromDigest(fullAssetID), erc20Arguments), nil - case EthereumInvokeKind: + + kind.Asset = proto.NewOptionalAssetFromDigest(fullAssetID) + case *proto.EthereumInvokeScriptTxKind: scriptAddr, err := ethTx.WavesAddressTo(e.settings.AddressSchemeCharacter) if err != nil { - return nil, err + return err } tree, err := e.stor.scriptsStorage.newestScriptByAddr(*scriptAddr, !params.initialisation) if err != nil { - return nil, errors.Wrapf(err, "failed to instantiate script on address '%s'", scriptAddr.String()) + return errors.Wrapf(err, "failed to instantiate script on address '%s'", scriptAddr.String()) } db, err := ethabi.NewMethodsMapFromRideDAppMeta(tree.Meta) if err != nil { - return nil, err + return err } decodedData, err := db.ParseCallDataRide(ethTx.Data()) if err != nil { - return nil, errors.Wrap(err, "failed to parse ethereum data") + return errors.Wrap(err, "failed to parse ethereum data") } - return proto.NewEthereumInvokeScriptTxKind(*decodedData), nil + kind.DecodedCallData = decodedData default: - return nil, errors.New("unexpected ethereum tx kind") + return errors.New("unexpected ethereum tx kind") } + return nil } diff --git a/pkg/state/transaction_checker.go b/pkg/state/transaction_checker.go index 338f2115c..6cd517204 100644 --- a/pkg/state/transaction_checker.go +++ b/pkg/state/transaction_checker.go @@ -354,14 +354,7 @@ func (tc *transactionChecker) checkEthereumTransactionWithProofs(transaction pro } // check if the amount is 0 - if tx.Value() == nil { - return nil, errors.New("the amount of ethereum transfer waves is 0, which is forbidden") - } - res := new(big.Int).Div(tx.Value(), big.NewInt(int64(proto.DiffEthWaves))) - if ok := res.IsInt64(); !ok { - return nil, errors.Errorf("failed to convert amount from ethreum transaction (big int) to int64. value is %s", tx.Value().String()) - } - if res.Int64() == 0 { + if tx.Value() == 0 { return nil, errors.New("the amount of ethereum transfer waves is 0, which is forbidden") } @@ -386,7 +379,7 @@ func (tc *transactionChecker) checkEthereumTransactionWithProofs(transaction pro return nil, errors.Errorf("the fee for ethereum transfer assets tx is not enough, min fee is %d, got %d", proto.EthereumTransferMinFee, tx.GetFee()) } - allAssets := []proto.OptionalAsset{kind.Asset} + allAssets := []proto.OptionalAsset{*kind.Asset} smartAssets, err := tc.smartAssets(allAssets, info.initialisation) if err != nil { return nil, err diff --git a/pkg/state/transaction_differ.go b/pkg/state/transaction_differ.go index 7e09e9a16..31031fb32 100644 --- a/pkg/state/transaction_differ.go +++ b/pkg/state/transaction_differ.go @@ -1,8 +1,6 @@ package state import ( - "math/big" - "github.com/ericlagergren/decimal" "github.com/ericlagergren/decimal/math" "github.com/mr-tron/base58" @@ -482,11 +480,7 @@ func (td *transactionDiffer) createDiffEthereumTransferWaves(tx *proto.EthereumT return txBalanceChanges{}, err } - res := new(big.Int).Div(tx.Value(), big.NewInt(int64(proto.DiffEthWaves))) - if ok := res.IsInt64(); !ok { - return txBalanceChanges{}, errors.Errorf("failed to convert amount from ethreum transaction (big int) to int64. value is %s", tx.Value().String()) - } - amount := res.Int64() + amount := tx.Value() senderAmountKey := byteKey(senderAddress.ID(), wavesAsset) @@ -551,7 +545,7 @@ func (td *transactionDiffer) createDiffEthereumErc20(tx *proto.EthereumTransacti // transfer - senderAmountKey := byteKey(senderAddress.ID(), txErc20Kind.Asset) + senderAmountKey := byteKey(senderAddress.ID(), *txErc20Kind.Asset) senderAmountBalanceDiff := -txErc20Kind.Arguments.Amount if err := diff.appendBalanceDiff(senderAmountKey, newBalanceDiff(senderAmountBalanceDiff, 0, 0, updateMinIntermediateBalance)); err != nil { @@ -564,7 +558,7 @@ func (td *transactionDiffer) createDiffEthereumErc20(tx *proto.EthereumTransacti } // Append receiver diff. - receiverKey := byteKey(etc20TransferRecipient.ID(), txErc20Kind.Asset) + receiverKey := byteKey(etc20TransferRecipient.ID(), *txErc20Kind.Asset) receiverBalanceDiff := txErc20Kind.Arguments.Amount if err := diff.appendBalanceDiff(receiverKey, newBalanceDiff(receiverBalanceDiff, 0, 0, updateMinIntermediateBalance)); err != nil { return txBalanceChanges{}, err From 90de7715deec1716a347d690e8d5d081b9cbb86d Mon Sep 17 00:00:00 2001 From: esuwu Date: Mon, 13 Dec 2021 19:18:25 +0300 Subject: [PATCH 2/7] Refactored eth tx --- pkg/metamask/service.go | 8 +++--- pkg/proto/eth_access_list_tx_test.go | 1 + pkg/proto/eth_signer.go | 6 ++-- pkg/proto/eth_transaction.go | 34 +++++++++++++++++------ pkg/ride/converters.go | 19 ++++--------- pkg/ride/converters_test.go | 2 +- pkg/state/eth_info.go | 13 ++++++++- pkg/state/ethereum_tx_test.go | 26 +++++++++++------- pkg/state/invoke_applier.go | 6 ++-- pkg/state/script_caller.go | 2 +- pkg/state/transaction_differ.go | 41 +++++++++------------------- 11 files changed, 84 insertions(+), 74 deletions(-) diff --git a/pkg/metamask/service.go b/pkg/metamask/service.go index 53bdb8367..68fb83f0d 100644 --- a/pkg/metamask/service.go +++ b/pkg/metamask/service.go @@ -163,14 +163,14 @@ func (s RPCService) Eth_EstimateGas(req estimateGasRequest) (string, error) { } } - txKind, err := state.GuessEthereumTransactionKind(data) + txKind, err := proto.GuessEthereumTransactionKind(data) if err != nil { return "", errors.Errorf("failed to guess ethereum tx kind, %v", err) } switch txKind { - case state.EthereumTransferWavesKind: + case proto.EthereumTransferWavesKind: return fmt.Sprintf("%d", proto.MinFee), nil - case state.EthereumTransferAssetsKind: + case proto.EthereumTransferAssetsKind: fee := proto.MinFee assetID := (*proto.AssetID)(req.To) @@ -182,7 +182,7 @@ func (s RPCService) Eth_EstimateGas(req estimateGasRequest) (string, error) { fee += proto.MinFeeScriptedAsset } return fmt.Sprintf("%d", fee), nil - case state.EthereumInvokeKind: + case proto.EthereumInvokeKind: fee := proto.MinFeeInvokeScript scriptAddr, err := req.To.ToWavesAddress(s.nodeRPCApp.Scheme) diff --git a/pkg/proto/eth_access_list_tx_test.go b/pkg/proto/eth_access_list_tx_test.go index 52be8ce17..6a5bb5ee8 100644 --- a/pkg/proto/eth_access_list_tx_test.go +++ b/pkg/proto/eth_access_list_tx_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/require" ) +// TODO inner Data should contain 4 bytes, not 2 func TestEthereumAccessListTxCanonical(t *testing.T) { mustDecodeFomHexString := func(hexString string) []byte { data, err := DecodeFromHexString(hexString) diff --git a/pkg/proto/eth_signer.go b/pkg/proto/eth_signer.go index 46de87a4e..bb7a1943d 100644 --- a/pkg/proto/eth_signer.go +++ b/pkg/proto/eth_signer.go @@ -180,7 +180,7 @@ func (s londonSigner) SenderPK(tx *EthereumTransaction) (*EthereumPublicKey, err // DynamicFee txs are defined to use 0 and 1 as their recovery // id, add 27 to become equivalent to unprotected Homestead signatures. V = new(big.Int).Add(V, big.NewInt(27)) - if tx.ChainId().Cmp(s.chainId) != 0 { + if tx.inner.chainID().Cmp(s.chainId) != 0 { return nil, ErrInvalidChainId } return recoverEthereumPubKey(s.Hash(tx), R, S, V, true) @@ -262,7 +262,7 @@ func (s eip2930Signer) SenderPK(tx *EthereumTransaction) (*EthereumPublicKey, er // AL txs are defined to use 0 and 1 as their recovery // id, add 27 to become equivalent to unprotected Homestead signatures. V = new(big.Int).Add(V, big.NewInt(27)) - if tx.ChainId().Cmp(s.chainId) != 0 { + if tx.inner.chainID().Cmp(s.chainId) != 0 { return nil, ErrInvalidChainId } return recoverEthereumPubKey(s.Hash(tx), R, S, V, true) @@ -342,7 +342,7 @@ func (s eip155Signer) SenderPK(tx *EthereumTransaction) (*EthereumPublicKey, err if !tx.Protected() { return HomesteadSigner{}.SenderPK(tx) } - if tx.ChainId().Cmp(s.chainId) != 0 { + if tx.inner.chainID().Cmp(s.chainId) != 0 { return nil, ErrInvalidChainId } V, R, S := tx.RawSignatureValues() diff --git a/pkg/proto/eth_transaction.go b/pkg/proto/eth_transaction.go index ab31c36eb..f6af95d34 100644 --- a/pkg/proto/eth_transaction.go +++ b/pkg/proto/eth_transaction.go @@ -98,9 +98,11 @@ type EthereumTxData interface { type EthereumTransactionKind interface { String() string DecodedData() *ethabi.DecodedCallData + Sender() WavesAddress } type EthereumTransferWavesTxKind struct { + From WavesAddress } func NewEthereumTransferWavesTxKind() *EthereumTransferWavesTxKind { @@ -115,10 +117,15 @@ func (tx *EthereumTransferWavesTxKind) String() string { return "EthereumTransferWavesTxKind" } +func (tx *EthereumTransferWavesTxKind) Sender() WavesAddress { + return tx.From +} + type EthereumTransferAssetsErc20TxKind struct { decodedData ethabi.DecodedCallData Arguments ethabi.ERC20TransferArguments Asset *OptionalAsset + From WavesAddress } func NewEthereumTransferAssetsErc20TxKind(decodedData ethabi.DecodedCallData, asset *OptionalAsset, arguments ethabi.ERC20TransferArguments) *EthereumTransferAssetsErc20TxKind { @@ -133,8 +140,13 @@ func (tx *EthereumTransferAssetsErc20TxKind) String() string { return "EthereumTransferAssetsErc20TxKind" } +func (tx *EthereumTransferAssetsErc20TxKind) Sender() WavesAddress { + return tx.From +} + type EthereumInvokeScriptTxKind struct { DecodedCallData *ethabi.DecodedCallData + From WavesAddress } func NewEthereumInvokeScriptTxKind(decodedData *ethabi.DecodedCallData) *EthereumInvokeScriptTxKind { @@ -149,11 +161,15 @@ func (tx *EthereumInvokeScriptTxKind) String() string { return "EthereumInvokeScriptTxKind" } +func (tx *EthereumInvokeScriptTxKind) Sender() WavesAddress { + return tx.From +} + type EthereumTransaction struct { inner EthereumTxData value int64 - chainID int64 - gasPrice uint64 + chainID int64 + gasPrice uint64 innerBinarySize int senderPK atomic.Value // *EthereumPublicKey TxKind EthereumTransactionKind @@ -168,6 +184,9 @@ func NewEthereumTransaction(inner EthereumTxData, txKind EthereumTransactionKind TxKind: txKind, ID: id, } + res := new(big.Int).Div(tx.inner.value(), big.NewInt(int64(DiffEthWaves))) + tx.value = res.Int64() + tx.threadSafeSetSenderPK(senderPK) return tx } @@ -237,7 +256,7 @@ func (tx *EthereumTransaction) Verify() (*EthereumPublicKey, error) { // This method doesn't include signature verification. Use Verify method for signature verification func (tx *EthereumTransaction) Validate(scheme Scheme) (Transaction, error) { // same chainID - if tx.ChainId() != int64(scheme){ + if tx.ChainId() != int64(scheme) { // TODO: introduce new error type for scheme validation txChainID := tx.ChainId() return nil, errs.NewTxValidationError(fmt.Sprintf( @@ -463,15 +482,12 @@ func (tx *EthereumTransaction) RawSignatureValues() (v, r, s *big.Int) { } func validateEthereumTx(tx *EthereumTransaction) error { - switch _ := tx.TxKind.(type) { + switch tx.TxKind.(type) { case *EthereumTransferWavesTxKind: res := new(big.Int).Div(tx.inner.value(), big.NewInt(int64(DiffEthWaves))) if ok := res.IsInt64(); !ok { return errors.Errorf("failed to convert amount from ethreum transaction (big int) to int64. value is %d", tx.Value()) } - if res.Int64() == 0 { - return errors.New("the amount of ethereum transfer waves is 0, which is forbidden") - } tx.value = res.Int64() return nil case *EthereumTransferAssetsErc20TxKind: @@ -503,7 +519,7 @@ func GuessEthereumTransactionKind(data []byte) (int64, error) { return EthereumInvokeKind, nil } -func ethereumTransactionKind(ethTx EthereumTransaction) (EthereumTransactionKind, error) { +func GetEthereumTransactionKind(ethTx EthereumTransaction) (EthereumTransactionKind, error) { txKind, err := GuessEthereumTransactionKind(ethTx.Data()) if err != nil { return nil, errors.Wrap(err, "failed to guess ethereum tx kind") @@ -574,7 +590,7 @@ func (tx *EthereumTransaction) DecodeCanonical(canonicalData []byte) error { } tx.gasPrice = tx.inner.gasPrice().Uint64() var err error - tx.TxKind, err = ethereumTransactionKind(*tx) + tx.TxKind, err = GetEthereumTransactionKind(*tx) if err != nil { return errors.Errorf("failed to guess ethereum transaction kind, %v", err) } diff --git a/pkg/ride/converters.go b/pkg/ride/converters.go index 841fc0105..4eaa5fb1b 100644 --- a/pkg/ride/converters.go +++ b/pkg/ride/converters.go @@ -1,8 +1,6 @@ package ride import ( - "math/big" - "github.com/pkg/errors" "github.com/wavesplatform/gowaves/pkg/crypto" "github.com/wavesplatform/gowaves/pkg/proto" @@ -960,13 +958,7 @@ func ethereumTransactionToObject(scheme proto.Scheme, tx *proto.EthereumTransact r["senderPublicKey"] = rideBytes(callerPK) r["recipient"] = rideRecipient(proto.NewRecipientFromAddress(*to)) r["assetId"] = optionalAsset(proto.NewOptionalAssetWaves()) - res := new(big.Int).Div(tx.Value(), big.NewInt(int64(proto.DiffEthWaves))) - if ok := res.IsInt64(); !ok { - return nil, EvaluationFailure.Errorf( - "transferWithProofsToObject: failed to convert amount from ethreum transaction (big int) to int64. value is %s", - tx.Value().String()) - } - amount := res.Int64() + amount := tx.Value() r["amount"] = rideInt(amount) r["fee"] = rideInt(tx.GetFee()) r["feeAssetId"] = optionalAsset(proto.NewOptionalAssetWaves()) @@ -985,7 +977,7 @@ func ethereumTransactionToObject(scheme proto.Scheme, tx *proto.EthereumTransact return nil, errors.Wrap(err, "failed to convert ethereum ERC20 transfer recipient to WavesAddress") } r["recipient"] = rideRecipient(proto.NewRecipientFromAddress(recipientAddr)) - r["assetId"] = optionalAsset(kind.Asset) + r["assetId"] = optionalAsset(*kind.Asset) r["amount"] = rideInt(kind.Arguments.Amount) r["fee"] = rideInt(tx.GetFee()) r["feeAssetId"] = optionalAsset(proto.NewOptionalAssetWaves()) @@ -1176,10 +1168,11 @@ func invocationToObject(v int, scheme byte, tx *proto.InvokeScriptWithProofs) (r } func ethereumInvocationToObject(v int, scheme proto.Scheme, tx *proto.EthereumTransaction, scriptPayments []proto.ScriptPayment) (rideObject, error) { - sender, err := tx.WavesAddressFrom(scheme) - if err != nil { - return nil, err + txKind, ok := tx.TxKind.(*proto.EthereumInvokeScriptTxKind) + if !ok { + return nil, errors.New("failed to recognize ethereum invoke script tx kind") } + sender := txKind.From r := make(rideObject) r[instanceFieldName] = rideString("Invocation") r["transactionId"] = rideBytes(tx.ID.Bytes()) diff --git a/pkg/ride/converters_test.go b/pkg/ride/converters_test.go index 6779e6c2a..43881878d 100644 --- a/pkg/ride/converters_test.go +++ b/pkg/ride/converters_test.go @@ -2238,7 +2238,7 @@ func TestEthereumTransferAssetsTransformTxToRideObj(t *testing.T) { erc20arguments, err := ethabi.GetERC20TransferArguments(decodedData) assert.NoError(t, err) - tx.TxKind = proto.NewEthereumTransferAssetsErc20TxKind(*decodedData, *proto.NewOptionalAssetFromDigest(asset.ID), erc20arguments) + tx.TxKind = proto.NewEthereumTransferAssetsErc20TxKind(*decodedData, proto.NewOptionalAssetFromDigest(asset.ID), erc20arguments) rideObj, err := transactionToObject(proto.MainNetScheme, &tx) assert.NoError(t, err) diff --git a/pkg/state/eth_info.go b/pkg/state/eth_info.go index 03defc8b9..cf710a7e6 100644 --- a/pkg/state/eth_info.go +++ b/pkg/state/eth_info.go @@ -17,9 +17,19 @@ func newEthInfo(stor *blockchainEntitiesStorage, settings *settings.BlockchainSe } func (e *ethInfo) fillRequiredTxFields(ethTx *proto.EthereumTransaction, params *appendTxParams) error { + EthSenderAddr, err := ethTx.From() + if err != nil { + return err + } + senderAddress, err := EthSenderAddr.ToWavesAddress(e.settings.AddressSchemeCharacter) + if err != nil { + return err + } switch kind := ethTx.TxKind.(type) { case *proto.EthereumTransferWavesTxKind: + kind.From = senderAddress + case *proto.EthereumTransferAssetsErc20TxKind: db := ethabi.NewErc20MethodsMap() decodedData, err := db.ParseCallDataRide(ethTx.Data()) @@ -37,6 +47,7 @@ func (e *ethInfo) fillRequiredTxFields(ethTx *proto.EthereumTransaction, params fullAssetID := proto.ReconstructDigest(*assetID, assetInfo.tail) kind.Asset = proto.NewOptionalAssetFromDigest(fullAssetID) + kind.From = senderAddress case *proto.EthereumInvokeScriptTxKind: scriptAddr, err := ethTx.WavesAddressTo(e.settings.AddressSchemeCharacter) if err != nil { @@ -56,7 +67,7 @@ func (e *ethInfo) fillRequiredTxFields(ethTx *proto.EthereumTransaction, params } kind.DecodedCallData = decodedData - + kind.From = senderAddress default: return errors.New("unexpected ethereum tx kind") } diff --git a/pkg/state/ethereum_tx_test.go b/pkg/state/ethereum_tx_test.go index e09f9b815..a1c0b4598 100644 --- a/pkg/state/ethereum_tx_test.go +++ b/pkg/state/ethereum_tx_test.go @@ -80,8 +80,9 @@ func TestEthereumTransferWaves(t *testing.T) { txData := defaultEthereumLegacyTxData(1000000000000000, &recipientEth, nil, 100000) tx := proto.NewEthereumTransaction(txData, nil, nil, &senderPK, 0) - tx.TxKind, err = txAppender.ethInfo.ethereumTransactionKind(&tx, nil) - + tx.TxKind, err = proto.GetEthereumTransactionKind(tx) + assert.NoError(t, err) + err = txAppender.ethInfo.fillRequiredTxFields(&tx, appendTxParams) assert.NoError(t, err) applRes, err := txAppender.handleDefaultTransaction(&tx, appendTxParams, false) assert.NoError(t, err) @@ -156,7 +157,7 @@ func TestEthereumTransferAssets(t *testing.T) { assetInfo, err := txAppender.ethInfo.stor.assets.newestAssetInfo(*assetID, true) require.NoError(t, err) fullAssetID := proto.ReconstructDigest(*assetID, assetInfo.tail) - tx.TxKind = proto.NewEthereumTransferAssetsErc20TxKind(*decodedData, *proto.NewOptionalAssetFromDigest(fullAssetID), erc20arguments) + tx.TxKind = proto.NewEthereumTransferAssetsErc20TxKind(*decodedData, proto.NewOptionalAssetFromDigest(fullAssetID), erc20arguments) applRes, err := txAppender.handleDefaultTransaction(&tx, appendTxParams, false) assert.NoError(t, err) assert.True(t, applRes.status) @@ -251,7 +252,7 @@ func TestEthereumInvoke(t *testing.T) { txData := defaultEthereumLegacyTxData(1000000000000000, &recipientEth, nil, 500000) decodedData := defaultDecodedData("call", []ethabi.DecodedArg{{Value: ethabi.Int(10)}}, []ethabi.Payment{{Amount: 5, AssetID: proto.NewOptionalAssetWaves().ID}}) - txKind := proto.NewEthereumInvokeScriptTxKind(decodedData) + txKind := proto.NewEthereumInvokeScriptTxKind(&decodedData) tx := proto.NewEthereumTransaction(txData, txKind, &crypto.Digest{}, &senderPK, 0) fallibleInfo := &fallibleValidationParams{appendTxParams: appendTxParams, senderScripted: false, senderAddress: sender} @@ -287,7 +288,9 @@ func TestTransferZeroAmount(t *testing.T) { txData := defaultEthereumLegacyTxData(0, &recipientEth, nil, 100000) tx := proto.NewEthereumTransaction(txData, nil, nil, &senderPK, 0) - tx.TxKind, err = txAppender.ethInfo.ethereumTransactionKind(&tx, nil) + tx.TxKind, err = proto.GetEthereumTransactionKind(tx) + assert.NoError(t, err) + err = txAppender.ethInfo.fillRequiredTxFields(&tx, appendTxParams) assert.NoError(t, err) _, err = txAppender.handleDefaultTransaction(&tx, appendTxParams, false) @@ -305,9 +308,10 @@ func TestTransferMainNetTestnet(t *testing.T) { txData := defaultEthereumLegacyTxData(100, &recipientEth, nil, 100000) tx := proto.NewEthereumTransaction(txData, nil, nil, &senderPK, 0) - tx.TxKind, err = txAppender.ethInfo.ethereumTransactionKind(&tx, nil) + tx.TxKind, err = proto.GetEthereumTransactionKind(tx) + assert.NoError(t, err) + err = txAppender.ethInfo.fillRequiredTxFields(&tx, appendTxParams) assert.NoError(t, err) - _, err = txAppender.handleDefaultTransaction(&tx, appendTxParams, false) require.Error(t, err) } @@ -323,7 +327,9 @@ func TestTransferCheckFee(t *testing.T) { txData := defaultEthereumLegacyTxData(100, &recipientEth, nil, 100) tx := proto.NewEthereumTransaction(txData, nil, nil, &senderPK, 0) - tx.TxKind, err = txAppender.ethInfo.ethereumTransactionKind(&tx, nil) + tx.TxKind, err = proto.GetEthereumTransactionKind(tx) + assert.NoError(t, err) + err = txAppender.ethInfo.fillRequiredTxFields(&tx, appendTxParams) assert.NoError(t, err) _, err = txAppender.handleDefaultTransaction(&tx, appendTxParams, false) @@ -380,7 +386,7 @@ func TestEthereumInvokeWithoutPaymentsAndArguments(t *testing.T) { txData := defaultEthereumLegacyTxData(1000000000000000, &recipientEth, nil, 500000) decodedData := defaultDecodedData("call", nil, nil) - tx := proto.NewEthereumTransaction(txData, proto.NewEthereumInvokeScriptTxKind(decodedData), &crypto.Digest{}, &senderPK, 0) + tx := proto.NewEthereumTransaction(txData, proto.NewEthereumInvokeScriptTxKind(&decodedData), &crypto.Digest{}, &senderPK, 0) fallibleInfo := &fallibleValidationParams{appendTxParams: appendTxParams, senderScripted: false, senderAddress: sender} scriptAddress, tree := applyScript(t, &tx, storage, fallibleInfo) @@ -454,7 +460,7 @@ func TestEthereumInvokeAllArguments(t *testing.T) { {Value: ethabi.Bool(true)}, // will leave it here {Value: ethabi.List{ethabi.Int(4)}}, }, nil) - tx := proto.NewEthereumTransaction(txData, proto.NewEthereumInvokeScriptTxKind(decodedData), &crypto.Digest{}, &senderPK, 0) + tx := proto.NewEthereumTransaction(txData, proto.NewEthereumInvokeScriptTxKind(&decodedData), &crypto.Digest{}, &senderPK, 0) fallibleInfo := &fallibleValidationParams{appendTxParams: appendTxParams, senderScripted: false, senderAddress: sender} scriptAddress, tree := applyScript(t, &tx, storage, fallibleInfo) diff --git a/pkg/state/invoke_applier.go b/pkg/state/invoke_applier.go index 7e6d69306..b9cf2cb0b 100644 --- a/pkg/state/invoke_applier.go +++ b/pkg/state/invoke_applier.go @@ -754,10 +754,8 @@ func (ia *invokeApplier) applyInvokeScript(tx proto.Transaction, info *fallibleV decodedData := transaction.TxKind.DecodedData() paymentsLength = len(decodedData.Payments) txID = *transaction.ID - sender, err = transaction.WavesAddressFrom(ia.settings.AddressSchemeCharacter) - if err != nil { - return nil, errors.Wrapf(err, "failed to apply script invocation") - } + sender = transaction.TxKind.Sender() + default: return nil, errors.New("failed to apply an invoke script: unexpected type of transaction ") } diff --git a/pkg/state/script_caller.go b/pkg/state/script_caller.go index 8ee4ce7d7..7ea6e81b2 100644 --- a/pkg/state/script_caller.go +++ b/pkg/state/script_caller.go @@ -257,7 +257,7 @@ func (a *scriptCaller) invokeFunction(tree *ride.Tree, tx proto.Transaction, inf if err != nil { return nil, err } - sender, err = transaction.WavesAddressFrom(a.settings.AddressSchemeCharacter) + sender = transaction.TxKind.Sender() if err != nil { return nil, errors.Errorf("failed to get waves address from ethereum transaction %v", err) } diff --git a/pkg/state/transaction_differ.go b/pkg/state/transaction_differ.go index 31031fb32..adffa05b0 100644 --- a/pkg/state/transaction_differ.go +++ b/pkg/state/transaction_differ.go @@ -463,18 +463,19 @@ func (td *transactionDiffer) createDiffTransfer(tx *proto.Transfer, info *differ func (td *transactionDiffer) createDiffEthereumTransferWaves(tx *proto.EthereumTransaction, info *differInfo) (txBalanceChanges, error) { diff := newTxDiff() + txKind, ok := tx.TxKind.(*proto.EthereumTransferWavesTxKind) + if !ok { + return txBalanceChanges{}, errors.New("failed to convert ethereum tx kind to EthereumTransferAssetsErc20TxKind") + } + updateMinIntermediateBalance := false if info.blockInfo.Timestamp >= td.settings.CheckTempNegativeAfterTime { updateMinIntermediateBalance = true } // Append sender diff. - senderAddress, err := tx.WavesAddressFrom(td.settings.AddressSchemeCharacter) - if err != nil { - return txBalanceChanges{}, err - } wavesAsset := proto.NewOptionalAssetWaves() - senderFeeKey := byteKey(senderAddress.ID(), wavesAsset) + senderFeeKey := byteKey(txKind.From.ID(), wavesAsset) senderFeeBalanceDiff := -int64(tx.GetFee()) if err := diff.appendBalanceDiff(senderFeeKey, newBalanceDiff(senderFeeBalanceDiff, 0, 0, updateMinIntermediateBalance)); err != nil { return txBalanceChanges{}, err @@ -482,7 +483,7 @@ func (td *transactionDiffer) createDiffEthereumTransferWaves(tx *proto.EthereumT amount := tx.Value() - senderAmountKey := byteKey(senderAddress.ID(), wavesAsset) + senderAmountKey := byteKey(txKind.From.ID(), wavesAsset) senderAmountBalanceDiff := -amount if err := diff.appendBalanceDiff(senderAmountKey, newBalanceDiff(senderAmountBalanceDiff, 0, 0, updateMinIntermediateBalance)); err != nil { @@ -498,7 +499,7 @@ func (td *transactionDiffer) createDiffEthereumTransferWaves(tx *proto.EthereumT if err := diff.appendBalanceDiff(receiverKey, newBalanceDiff(receiverBalanceDiff, 0, 0, updateMinIntermediateBalance)); err != nil { return txBalanceChanges{}, err } - addrs := []proto.WavesAddress{senderAddress, recipientAddress} + addrs := []proto.WavesAddress{txKind.From, recipientAddress} changes := newTxBalanceChanges(addrs, diff) // sponsorship might be handled here return changes, nil @@ -519,25 +520,13 @@ func (td *transactionDiffer) createDiffEthereumErc20(tx *proto.EthereumTransacti decodedData := txErc20Kind.DecodedData() - var senderAddress proto.WavesAddress - // Append sender diff. - if !ethabi.IsERC20TransferSelector(decodedData.Signature.Selector()) { return txBalanceChanges{}, errors.New("unexpected type of eth selector") } - EthSenderAddr, err := tx.From() - if err != nil { - return txBalanceChanges{}, err - } - senderAddress, err = EthSenderAddr.ToWavesAddress(td.settings.AddressSchemeCharacter) - if err != nil { - return txBalanceChanges{}, err - } - // Fee wavesAsset := proto.NewOptionalAssetWaves() - senderFeeKey := byteKey(senderAddress.ID(), wavesAsset) + senderFeeKey := byteKey(txErc20Kind.From.ID(), wavesAsset) senderFeeBalanceDiff := -int64(tx.GetFee()) if err := diff.appendBalanceDiff(senderFeeKey, newBalanceDiff(senderFeeBalanceDiff, 0, 0, updateMinIntermediateBalance)); err != nil { return txBalanceChanges{}, err @@ -545,7 +534,7 @@ func (td *transactionDiffer) createDiffEthereumErc20(tx *proto.EthereumTransacti // transfer - senderAmountKey := byteKey(senderAddress.ID(), *txErc20Kind.Asset) + senderAmountKey := byteKey(txErc20Kind.From.ID(), *txErc20Kind.Asset) senderAmountBalanceDiff := -txErc20Kind.Arguments.Amount if err := diff.appendBalanceDiff(senderAmountKey, newBalanceDiff(senderAmountBalanceDiff, 0, 0, updateMinIntermediateBalance)); err != nil { @@ -563,7 +552,7 @@ func (td *transactionDiffer) createDiffEthereumErc20(tx *proto.EthereumTransacti if err := diff.appendBalanceDiff(receiverKey, newBalanceDiff(receiverBalanceDiff, 0, 0, updateMinIntermediateBalance)); err != nil { return txBalanceChanges{}, err } - addrs := []proto.WavesAddress{senderAddress, etc20TransferRecipient} + addrs := []proto.WavesAddress{txErc20Kind.From, etc20TransferRecipient} changes := newTxBalanceChanges(addrs, diff) // sponsorship might be handled here return changes, nil @@ -1436,12 +1425,8 @@ func (td *transactionDiffer) createDiffEthereumInvokeScript(tx *proto.EthereumTr } diff := newTxDiff() // Append sender diff. - senderAddress, err := tx.WavesAddressFrom(td.settings.AddressSchemeCharacter) - if err != nil { - return txBalanceChanges{}, errors.Wrapf(err, "failed to get sender address from ethereum invoke tx") - } - senderAddrID := senderAddress.ID() + senderAddrID := txInvokeScriptKind.From.ID() assetFee := proto.NewOptionalAssetWaves() senderFeeKey := byteKey(senderAddrID, assetFee) senderFeeBalanceDiff := -int64(tx.GetFee()) @@ -1454,7 +1439,7 @@ func (td *transactionDiffer) createDiffEthereumInvokeScript(tx *proto.EthereumTr } scriptAddrID := scriptAddr.ID() - addresses := []proto.WavesAddress{senderAddress, *scriptAddr} + addresses := []proto.WavesAddress{txInvokeScriptKind.From, *scriptAddr} changes := newTxBalanceChanges(addresses, diff) for _, payment := range decodedData.Payments { From 0881f5a37db8854f9eed4a829353ac3a3d897216 Mon Sep 17 00:00:00 2001 From: Nikolay Eskov Date: Tue, 14 Dec 2021 12:30:17 +0300 Subject: [PATCH 3/7] Renamed some methods in 'ethabi' package. --- pkg/metamask/service.go | 2 +- pkg/proto/eth_transaction.go | 2 +- pkg/proto/ethabi/argument.go | 4 ++-- pkg/proto/ethabi/methods_map.go | 8 ++++---- pkg/proto/ethabi/parsing_test.go | 8 ++++---- pkg/ride/converters_test.go | 2 +- pkg/state/eth_info.go | 4 ++-- pkg/state/ethereum_tx_test.go | 2 +- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/pkg/metamask/service.go b/pkg/metamask/service.go index 68fb83f0d..e9a76c967 100644 --- a/pkg/metamask/service.go +++ b/pkg/metamask/service.go @@ -201,7 +201,7 @@ func (s RPCService) Eth_EstimateGas(req estimateGasRequest) (string, error) { if err != nil { return "", err } - decodedData, err := db.ParseCallDataRide(data) + decodedData, err := db.ParseCallData(data) if err != nil { return "", errors.Errorf("failed to parse ethereum data, %v", err) } diff --git a/pkg/proto/eth_transaction.go b/pkg/proto/eth_transaction.go index f6af95d34..58637aa56 100644 --- a/pkg/proto/eth_transaction.go +++ b/pkg/proto/eth_transaction.go @@ -530,7 +530,7 @@ func GetEthereumTransactionKind(ethTx EthereumTransaction) (EthereumTransactionK return NewEthereumTransferWavesTxKind(), nil case EthereumTransferAssetsKind: db := ethabi.NewErc20MethodsMap() - decodedData, err := db.ParseCallDataRide(ethTx.Data()) + decodedData, err := db.ParseCallData(ethTx.Data()) if err != nil { return nil, errors.Errorf("failed to parse ethereum data") } diff --git a/pkg/proto/ethabi/argument.go b/pkg/proto/ethabi/argument.go index f9787a275..6a7b6ae77 100644 --- a/pkg/proto/ethabi/argument.go +++ b/pkg/proto/ethabi/argument.go @@ -26,10 +26,10 @@ func NewArgumentFromRideTypeMeta(name string, rideT meta.Type) (Argument, error) return arg, err } -// UnpackRideValues can be used to unpack ABI-encoded hexdata according to the ABI-specification, +// UnpackValues can be used to unpack ABI-encoded hexdata according to the ABI-specification, // without supplying a struct to unpack into. Instead, this method returns a list containing the // values. An atomic argument will be a list with one element. -func (arguments Arguments) UnpackRideValues(data []byte) ([]DataType, int, error) { +func (arguments Arguments) UnpackValues(data []byte) ([]DataType, int, error) { retval := make([]DataType, 0, len(arguments)) virtualArgs := 0 for index, arg := range arguments { diff --git a/pkg/proto/ethabi/methods_map.go b/pkg/proto/ethabi/methods_map.go index 94826aa12..626ef887f 100644 --- a/pkg/proto/ethabi/methods_map.go +++ b/pkg/proto/ethabi/methods_map.go @@ -72,7 +72,7 @@ func (db MethodsMap) MethodBySelector(id Selector) (Method, error) { return Method{}, fmt.Errorf("signature %q not found", id.String()) } -func (db MethodsMap) ParseCallDataRide(data []byte) (*DecodedCallData, error) { +func (db MethodsMap) ParseCallData(data []byte) (*DecodedCallData, error) { // If the data is empty, we have a plain value transfer, nothing more to do if len(data) == 0 { return nil, errors.New("transaction doesn't contain data") @@ -91,7 +91,7 @@ func (db MethodsMap) ParseCallDataRide(data []byte) (*DecodedCallData, error) { return nil, errors.Errorf("Transaction contains data, but the ABI signature could not be found: %v", err) } - info, err := parseArgDataToRideTypes(&method, data[SelectorSize:], db.parsePayments) + info, err := parseArgDataToEthABITypes(&method, data[SelectorSize:], db.parsePayments) if err != nil { return nil, errors.Errorf("Transaction contains data, but provided ABI signature could not be verified: %v", err) } @@ -122,8 +122,8 @@ func (da *DecodedArg) InternalType() byte { return byte(da.Soltype.Type.T) } -func parseArgDataToRideTypes(method *Method, argData []byte, parsePayments bool) (*DecodedCallData, error) { - values, paymentsOffset, err := method.Inputs.UnpackRideValues(argData) +func parseArgDataToEthABITypes(method *Method, argData []byte, parsePayments bool) (*DecodedCallData, error) { + values, paymentsOffset, err := method.Inputs.UnpackValues(argData) if err != nil { return nil, errors.Wrap(err, "failed to unpack Inputs arguments ABI data") } diff --git a/pkg/proto/ethabi/parsing_test.go b/pkg/proto/ethabi/parsing_test.go index 1700ce4cd..619d5ea9f 100644 --- a/pkg/proto/ethabi/parsing_test.go +++ b/pkg/proto/ethabi/parsing_test.go @@ -25,7 +25,7 @@ func TestERC20EthereumTransfer(t *testing.T) { require.NoError(t, err) erc20Db := NewErc20MethodsMap() - callData, err := erc20Db.ParseCallDataRide(data) + callData, err := erc20Db.ParseCallData(data) require.NoError(t, err) require.Equal(t, expectedSignature, callData.Signature.String()) @@ -50,7 +50,7 @@ func TestGetERC20TransferArguments(t *testing.T) { require.NoError(t, err) erc20Db := NewErc20MethodsMap() - callData, err := erc20Db.ParseCallDataRide(data) + callData, err := erc20Db.ParseCallData(data) require.NoError(t, err) transferArgs, err := GetERC20TransferArguments(callData) @@ -89,7 +89,7 @@ func TestRandomFunctionABIParsing(t *testing.T) { methods: customDB, parsePayments: false, } - callData, err := db.ParseCallDataRide(data) + callData, err := db.ParseCallData(data) require.NoError(t, err) require.Equal(t, "minta", callData.Name) @@ -315,7 +315,7 @@ func TestParsingABIUsingRideMeta(t *testing.T) { db, err := newMethodsMapFromRideDAppMeta(dAppMeta, tc.parsePayments) require.NoError(t, err) - decodedCallData, err := db.ParseCallDataRide(data) + decodedCallData, err := db.ParseCallData(data) require.NoError(t, err) values := make([]DataType, 0, len(decodedCallData.Inputs)) diff --git a/pkg/ride/converters_test.go b/pkg/ride/converters_test.go index 43881878d..3261a059b 100644 --- a/pkg/ride/converters_test.go +++ b/pkg/ride/converters_test.go @@ -2226,7 +2226,7 @@ func TestEthereumTransferAssetsTransformTxToRideObj(t *testing.T) { tx := proto.NewEthereumTransaction(txData, nil, &crypto.Digest{}, &senderPK, 0) db := ethabi.NewErc20MethodsMap() assert.NotNil(t, tx.Data()) - decodedData, err := db.ParseCallDataRide(tx.Data()) + decodedData, err := db.ParseCallData(tx.Data()) assert.NoError(t, err) makeLessDataAmount(t, decodedData) diff --git a/pkg/state/eth_info.go b/pkg/state/eth_info.go index cf710a7e6..c2a6bf183 100644 --- a/pkg/state/eth_info.go +++ b/pkg/state/eth_info.go @@ -32,7 +32,7 @@ func (e *ethInfo) fillRequiredTxFields(ethTx *proto.EthereumTransaction, params case *proto.EthereumTransferAssetsErc20TxKind: db := ethabi.NewErc20MethodsMap() - decodedData, err := db.ParseCallDataRide(ethTx.Data()) + decodedData, err := db.ParseCallData(ethTx.Data()) if err != nil { return errors.Errorf("failed to parse ethereum data") } @@ -61,7 +61,7 @@ func (e *ethInfo) fillRequiredTxFields(ethTx *proto.EthereumTransaction, params if err != nil { return err } - decodedData, err := db.ParseCallDataRide(ethTx.Data()) + decodedData, err := db.ParseCallData(ethTx.Data()) if err != nil { return errors.Wrap(err, "failed to parse ethereum data") } diff --git a/pkg/state/ethereum_tx_test.go b/pkg/state/ethereum_tx_test.go index a1c0b4598..96290d17b 100644 --- a/pkg/state/ethereum_tx_test.go +++ b/pkg/state/ethereum_tx_test.go @@ -145,7 +145,7 @@ func TestEthereumTransferAssets(t *testing.T) { db := ethabi.NewErc20MethodsMap() assert.NotNil(t, tx.Data()) - decodedData, err := db.ParseCallDataRide(tx.Data()) + decodedData, err := db.ParseCallData(tx.Data()) assert.NoError(t, err) lessenDecodedDataAmount(t, decodedData) From f50ceb1d637c8276f28ac30353155090c1af59af Mon Sep 17 00:00:00 2001 From: Nikolay Eskov Date: Tue, 14 Dec 2021 12:31:08 +0300 Subject: [PATCH 4/7] Fixed 'TestEthereumAccessListTxCanonical' test. --- pkg/proto/eth_access_list_tx_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pkg/proto/eth_access_list_tx_test.go b/pkg/proto/eth_access_list_tx_test.go index 6a5bb5ee8..9e094aad1 100644 --- a/pkg/proto/eth_access_list_tx_test.go +++ b/pkg/proto/eth_access_list_tx_test.go @@ -7,14 +7,13 @@ import ( "github.com/stretchr/testify/require" ) -// TODO inner Data should contain 4 bytes, not 2 func TestEthereumAccessListTxCanonical(t *testing.T) { mustDecodeFomHexString := func(hexString string) []byte { data, err := DecodeFromHexString(hexString) require.NoError(t, err) return data } - const expectedCanonical = "0x01f8630103018261a894b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a825544c001a0c9519f4f2b30335884581971573fadf60c6204f59a911df35ee8a540456b2660a032f1e8e2c5dd761f9e4f88f41c8310aeaba26a8bfcdacfedfa12ec3862d37521" + const expectedCanonical = "0x01f8650103018261a894b94f5374fce5edbc8e2a8697c15331677e6ebf0b0a84bdc01110c001a0c9519f4f2b30335884581971573fadf60c6204f59a911df35ee8a540456b2660a032f1e8e2c5dd761f9e4f88f41c8310aeaba26a8bfcdacfedfa12ec3862d37521" var ( expectedCanonicalBytes = mustDecodeFomHexString(expectedCanonical) testAddrBytes = mustDecodeFomHexString("0xb94f5374fce5edbc8e2a8697c15331677e6ebf0b") @@ -35,7 +34,7 @@ func TestEthereumAccessListTxCanonical(t *testing.T) { Value: big.NewInt(10), Gas: 25000, GasPrice: big.NewInt(1), - Data: mustDecodeFomHexString("5544"), + Data: mustDecodeFomHexString("0xbdc01110"), V: &v, R: &r, S: &s, From c78fb26778f40f05d93eddf683b94f2c70fe47b3 Mon Sep 17 00:00:00 2001 From: esuwu Date: Tue, 14 Dec 2021 13:37:42 +0300 Subject: [PATCH 5/7] Moved addresses from tx kinds --- pkg/proto/eth_transaction.go | 96 +++++++++++++++++--------------- pkg/ride/converters.go | 24 +++++--- pkg/state/transaction_checker.go | 13 ++++- pkg/state/transaction_differ.go | 51 +++++++++++------ 4 files changed, 111 insertions(+), 73 deletions(-) diff --git a/pkg/proto/eth_transaction.go b/pkg/proto/eth_transaction.go index f6af95d34..46317fa13 100644 --- a/pkg/proto/eth_transaction.go +++ b/pkg/proto/eth_transaction.go @@ -97,82 +97,78 @@ type EthereumTxData interface { type EthereumTransactionKind interface { String() string - DecodedData() *ethabi.DecodedCallData - Sender() WavesAddress + DecodedData() (*ethabi.DecodedCallData, error) } type EthereumTransferWavesTxKind struct { - From WavesAddress } func NewEthereumTransferWavesTxKind() *EthereumTransferWavesTxKind { return &EthereumTransferWavesTxKind{} } -func (tx *EthereumTransferWavesTxKind) DecodedData() *ethabi.DecodedCallData { - return nil +func (tx *EthereumTransferWavesTxKind) DecodedData() (*ethabi.DecodedCallData, error) { + return nil, errors.New("transfer waves ethereum tx kind does not have decoded call data") } func (tx *EthereumTransferWavesTxKind) String() string { return "EthereumTransferWavesTxKind" } -func (tx *EthereumTransferWavesTxKind) Sender() WavesAddress { - return tx.From -} - type EthereumTransferAssetsErc20TxKind struct { decodedData ethabi.DecodedCallData Arguments ethabi.ERC20TransferArguments - Asset *OptionalAsset - From WavesAddress + asset *OptionalAsset } func NewEthereumTransferAssetsErc20TxKind(decodedData ethabi.DecodedCallData, asset *OptionalAsset, arguments ethabi.ERC20TransferArguments) *EthereumTransferAssetsErc20TxKind { - return &EthereumTransferAssetsErc20TxKind{Asset: asset, decodedData: decodedData, Arguments: arguments} + return &EthereumTransferAssetsErc20TxKind{asset: asset, decodedData: decodedData, Arguments: arguments} } -func (tx *EthereumTransferAssetsErc20TxKind) DecodedData() *ethabi.DecodedCallData { - return &tx.decodedData +func (tx *EthereumTransferAssetsErc20TxKind) DecodedData() (*ethabi.DecodedCallData, error) { + return &tx.decodedData, nil +} +func (tx *EthereumTransferAssetsErc20TxKind) Asset() (*OptionalAsset, error) { + if tx.asset == nil { + return nil, errors.New("asset field of ethereum transfer assets tx is empty") + } + return tx.asset, nil } func (tx *EthereumTransferAssetsErc20TxKind) String() string { return "EthereumTransferAssetsErc20TxKind" } -func (tx *EthereumTransferAssetsErc20TxKind) Sender() WavesAddress { - return tx.From -} - type EthereumInvokeScriptTxKind struct { - DecodedCallData *ethabi.DecodedCallData - From WavesAddress + decodedCallData *ethabi.DecodedCallData } func NewEthereumInvokeScriptTxKind(decodedData *ethabi.DecodedCallData) *EthereumInvokeScriptTxKind { - return &EthereumInvokeScriptTxKind{DecodedCallData: decodedData} + return &EthereumInvokeScriptTxKind{decodedCallData: decodedData} } -func (tx *EthereumInvokeScriptTxKind) DecodedData() *ethabi.DecodedCallData { - return tx.DecodedCallData +func (tx *EthereumInvokeScriptTxKind) DecodedData() (*ethabi.DecodedCallData, error) { + if tx.decodedCallData == nil { + return nil, errors.New("ethereum invoke script tx has empty decoded data") + } + return tx.decodedCallData, nil } func (tx *EthereumInvokeScriptTxKind) String() string { return "EthereumInvokeScriptTxKind" } -func (tx *EthereumInvokeScriptTxKind) Sender() WavesAddress { - return tx.From -} - type EthereumTransaction struct { - inner EthereumTxData + // Ethereum representation + senderPK atomic.Value // *EthereumPublicKey + inner EthereumTxData // + + // Waves representation + TxKind EthereumTransactionKind value int64 chainID int64 gasPrice uint64 innerBinarySize int - senderPK atomic.Value // *EthereumPublicKey - TxKind EthereumTransactionKind ID *crypto.Digest } @@ -519,6 +515,8 @@ func GuessEthereumTransactionKind(data []byte) (int64, error) { return EthereumInvokeKind, nil } + +// note: in this method not all of the fields are filled func GetEthereumTransactionKind(ethTx EthereumTransaction) (EthereumTransactionKind, error) { txKind, err := GuessEthereumTransactionKind(ethTx.Data()) if err != nil { @@ -550,6 +548,27 @@ func GetEthereumTransactionKind(ethTx EthereumTransaction) (EthereumTransactionK } } +func (tx *EthereumTransaction) initTransactionFields() error { + if ok := tx.inner.chainID().IsInt64(); !ok { + return errors.Errorf("failed to recognize chainID of ethereum transaction: over int64") + } + tx.chainID = tx.inner.chainID().Int64() + if ok := tx.inner.gasPrice().IsUint64(); !ok { + return errors.Errorf("failed to recognize GasPrice of ethereum transaction: over uint64") + } + tx.gasPrice = tx.inner.gasPrice().Uint64() + var err error + tx.TxKind, err = GetEthereumTransactionKind(*tx) + if err != nil { + return errors.Errorf("failed to guess ethereum transaction kind, %v", err) + } + err = validateEthereumTx(tx) + if err != nil { + return errors.Errorf("validation of ethereum transaction after initialization failed , %v", err) + } + return nil +} + // DecodeCanonical decodes the canonical binary encoding of transactions. // It supports legacy RLP transactions and EIP2718 typed transactions. func (tx *EthereumTransaction) DecodeCanonical(canonicalData []byte) error { @@ -581,22 +600,9 @@ func (tx *EthereumTransaction) DecodeCanonical(canonicalData []byte) error { } tx.innerBinarySize = len(canonicalData) - if ok := tx.inner.chainID().IsInt64(); !ok { - return errors.Errorf("failed to recognize chainID of ethereum transaction: over int64") - } - tx.chainID = tx.inner.chainID().Int64() - if ok := tx.inner.gasPrice().IsUint64(); !ok { - return errors.Errorf("failed to recognize GasPrice of ethereum transaction: over uint64") - } - tx.gasPrice = tx.inner.gasPrice().Uint64() - var err error - tx.TxKind, err = GetEthereumTransactionKind(*tx) - if err != nil { - return errors.Errorf("failed to guess ethereum transaction kind, %v", err) - } - err = validateEthereumTx(tx) + err := tx.initTransactionFields() if err != nil { - return errors.Errorf("validation of ethereum transaction after initialization failed , %v", err) + return errors.Wrap(err, "failed to initialize waves representation fields of ethereum transaction") } return nil } diff --git a/pkg/ride/converters.go b/pkg/ride/converters.go index 4eaa5fb1b..d565280a0 100644 --- a/pkg/ride/converters.go +++ b/pkg/ride/converters.go @@ -977,7 +977,12 @@ func ethereumTransactionToObject(scheme proto.Scheme, tx *proto.EthereumTransact return nil, errors.Wrap(err, "failed to convert ethereum ERC20 transfer recipient to WavesAddress") } r["recipient"] = rideRecipient(proto.NewRecipientFromAddress(recipientAddr)) - r["assetId"] = optionalAsset(*kind.Asset) + asset, err := kind.Asset() + if err != nil { + return nil, err + } + + r["assetId"] = optionalAsset(*asset) r["amount"] = rideInt(kind.Arguments.Amount) r["fee"] = rideInt(tx.GetFee()) r["feeAssetId"] = optionalAsset(proto.NewOptionalAssetWaves()) @@ -992,8 +997,12 @@ func ethereumTransactionToObject(scheme proto.Scheme, tx *proto.EthereumTransact r["senderPublicKey"] = rideBytes(callerPK) r["dApp"] = rideRecipient(proto.NewRecipientFromAddress(*to)) + decodedData, err := tx.TxKind.DecodedData() + if err != nil { + return nil, err + } var scriptPayments []proto.ScriptPayment - for _, p := range tx.TxKind.DecodedData().Payments { + for _, p := range decodedData.Payments { var optAsset proto.OptionalAsset if p.PresentAssetID { optAsset = *proto.NewOptionalAssetFromDigest(p.AssetID) @@ -1021,8 +1030,8 @@ func ethereumTransactionToObject(scheme proto.Scheme, tx *proto.EthereumTransact r["payments"] = make(rideList, 0) } r["feeAssetId"] = optionalAsset(proto.NewOptionalAssetWaves()) - r["function"] = rideString(tx.TxKind.DecodedData().Name) - arguments, err := ConvertDecodedEthereumArgumentsToProtoArguments(tx.TxKind.DecodedData().Inputs) + r["function"] = rideString(decodedData.Name) + arguments, err := ConvertDecodedEthereumArgumentsToProtoArguments(decodedData.Inputs) if err != nil { return nil, errors.Errorf("failed to convert ethereum arguments, %v", err) } @@ -1168,11 +1177,10 @@ func invocationToObject(v int, scheme byte, tx *proto.InvokeScriptWithProofs) (r } func ethereumInvocationToObject(v int, scheme proto.Scheme, tx *proto.EthereumTransaction, scriptPayments []proto.ScriptPayment) (rideObject, error) { - txKind, ok := tx.TxKind.(*proto.EthereumInvokeScriptTxKind) - if !ok { - return nil, errors.New("failed to recognize ethereum invoke script tx kind") + sender, err := tx.WavesAddressFrom(scheme) + if err != nil { + return nil, err } - sender := txKind.From r := make(rideObject) r[instanceFieldName] = rideString("Invocation") r["transactionId"] = rideBytes(tx.ID.Bytes()) diff --git a/pkg/state/transaction_checker.go b/pkg/state/transaction_checker.go index 6cd517204..6377a83b5 100644 --- a/pkg/state/transaction_checker.go +++ b/pkg/state/transaction_checker.go @@ -366,8 +366,12 @@ func (tc *transactionChecker) checkEthereumTransactionWithProofs(transaction pro if kind.Arguments.Amount == 0 { return nil, errors.New("the amount of ethereum transfer assets is 0, which is forbidden") } + asset, err := kind.Asset() + if err != nil { + return nil, err + } - isSmart, err := tc.stor.scriptsStorage.newestIsSmartAsset(proto.AssetIDFromDigest(kind.Asset.ID), true) + isSmart, err := tc.stor.scriptsStorage.newestIsSmartAsset(proto.AssetIDFromDigest(asset.ID), true) if err != nil { return nil, errors.Errorf("failed to get asset info, %v", err) } @@ -379,7 +383,7 @@ func (tc *transactionChecker) checkEthereumTransactionWithProofs(transaction pro return nil, errors.Errorf("the fee for ethereum transfer assets tx is not enough, min fee is %d, got %d", proto.EthereumTransferMinFee, tx.GetFee()) } - allAssets := []proto.OptionalAsset{*kind.Asset} + allAssets := []proto.OptionalAsset{*asset} smartAssets, err := tc.smartAssets(allAssets, info.initialisation) if err != nil { return nil, err @@ -393,7 +397,10 @@ func (tc *transactionChecker) checkEthereumTransactionWithProofs(transaction pro if err := tc.checkTimestamps(tx.GetTimestamp(), info.currentTimestamp, info.parentTimestamp); err != nil { return nil, errs.Extend(err, "invalid timestamp") } - decodedData := tx.TxKind.DecodedData() + decodedData, err := tx.TxKind.DecodedData() + if err != nil { + return nil, err + } abiPayments := decodedData.Payments if len(abiPayments) > 10 { diff --git a/pkg/state/transaction_differ.go b/pkg/state/transaction_differ.go index adffa05b0..aa2417107 100644 --- a/pkg/state/transaction_differ.go +++ b/pkg/state/transaction_differ.go @@ -463,19 +463,18 @@ func (td *transactionDiffer) createDiffTransfer(tx *proto.Transfer, info *differ func (td *transactionDiffer) createDiffEthereumTransferWaves(tx *proto.EthereumTransaction, info *differInfo) (txBalanceChanges, error) { diff := newTxDiff() - txKind, ok := tx.TxKind.(*proto.EthereumTransferWavesTxKind) - if !ok { - return txBalanceChanges{}, errors.New("failed to convert ethereum tx kind to EthereumTransferAssetsErc20TxKind") - } - updateMinIntermediateBalance := false if info.blockInfo.Timestamp >= td.settings.CheckTempNegativeAfterTime { updateMinIntermediateBalance = true } // Append sender diff. wavesAsset := proto.NewOptionalAssetWaves() + senderAddress, err := tx.WavesAddressFrom(td.settings.AddressSchemeCharacter) + if err != nil { + return txBalanceChanges{}, err + } - senderFeeKey := byteKey(txKind.From.ID(), wavesAsset) + senderFeeKey := byteKey(senderAddress.ID(), wavesAsset) senderFeeBalanceDiff := -int64(tx.GetFee()) if err := diff.appendBalanceDiff(senderFeeKey, newBalanceDiff(senderFeeBalanceDiff, 0, 0, updateMinIntermediateBalance)); err != nil { return txBalanceChanges{}, err @@ -483,7 +482,7 @@ func (td *transactionDiffer) createDiffEthereumTransferWaves(tx *proto.EthereumT amount := tx.Value() - senderAmountKey := byteKey(txKind.From.ID(), wavesAsset) + senderAmountKey := byteKey(senderAddress.ID(), wavesAsset) senderAmountBalanceDiff := -amount if err := diff.appendBalanceDiff(senderAmountKey, newBalanceDiff(senderAmountBalanceDiff, 0, 0, updateMinIntermediateBalance)); err != nil { @@ -499,7 +498,7 @@ func (td *transactionDiffer) createDiffEthereumTransferWaves(tx *proto.EthereumT if err := diff.appendBalanceDiff(receiverKey, newBalanceDiff(receiverBalanceDiff, 0, 0, updateMinIntermediateBalance)); err != nil { return txBalanceChanges{}, err } - addrs := []proto.WavesAddress{txKind.From, recipientAddress} + addrs := []proto.WavesAddress{senderAddress, recipientAddress} changes := newTxBalanceChanges(addrs, diff) // sponsorship might be handled here return changes, nil @@ -518,23 +517,34 @@ func (td *transactionDiffer) createDiffEthereumErc20(tx *proto.EthereumTransacti return txBalanceChanges{}, errors.New("failed to convert ethereum tx kind to EthereumTransferAssetsErc20TxKind") } - decodedData := txErc20Kind.DecodedData() + decodedData, err := txErc20Kind.DecodedData() + if err != nil { + return txBalanceChanges{}, nil + } if !ethabi.IsERC20TransferSelector(decodedData.Signature.Selector()) { return txBalanceChanges{}, errors.New("unexpected type of eth selector") } + senderAddress, err := tx.WavesAddressFrom(td.settings.AddressSchemeCharacter) + if err != nil { + return txBalanceChanges{}, err + } + // Fee wavesAsset := proto.NewOptionalAssetWaves() - senderFeeKey := byteKey(txErc20Kind.From.ID(), wavesAsset) + senderFeeKey := byteKey(senderAddress.ID(), wavesAsset) senderFeeBalanceDiff := -int64(tx.GetFee()) if err := diff.appendBalanceDiff(senderFeeKey, newBalanceDiff(senderFeeBalanceDiff, 0, 0, updateMinIntermediateBalance)); err != nil { return txBalanceChanges{}, err } // transfer - - senderAmountKey := byteKey(txErc20Kind.From.ID(), *txErc20Kind.Asset) + asset, err := txErc20Kind.Asset() + if err != nil { + return txBalanceChanges{}, err + } + senderAmountKey := byteKey(senderAddress.ID(), *asset) senderAmountBalanceDiff := -txErc20Kind.Arguments.Amount if err := diff.appendBalanceDiff(senderAmountKey, newBalanceDiff(senderAmountBalanceDiff, 0, 0, updateMinIntermediateBalance)); err != nil { @@ -547,12 +557,12 @@ func (td *transactionDiffer) createDiffEthereumErc20(tx *proto.EthereumTransacti } // Append receiver diff. - receiverKey := byteKey(etc20TransferRecipient.ID(), *txErc20Kind.Asset) + receiverKey := byteKey(etc20TransferRecipient.ID(), *asset) receiverBalanceDiff := txErc20Kind.Arguments.Amount if err := diff.appendBalanceDiff(receiverKey, newBalanceDiff(receiverBalanceDiff, 0, 0, updateMinIntermediateBalance)); err != nil { return txBalanceChanges{}, err } - addrs := []proto.WavesAddress{txErc20Kind.From, etc20TransferRecipient} + addrs := []proto.WavesAddress{senderAddress, etc20TransferRecipient} changes := newTxBalanceChanges(addrs, diff) // sponsorship might be handled here return changes, nil @@ -1417,7 +1427,10 @@ func (td *transactionDiffer) createDiffEthereumInvokeScript(tx *proto.EthereumTr return txBalanceChanges{}, errors.New("failed to convert ethereum tx kind to EthereumTransferAssetsErc20TxKind") } - decodedData := txInvokeScriptKind.DecodedData() + decodedData, err := txInvokeScriptKind.DecodedData() + if err != nil { + return txBalanceChanges{}, err + } noPayments := len(decodedData.Payments) == 0 if info.blockInfo.Timestamp >= td.settings.CheckTempNegativeAfterTime && !noPayments { @@ -1425,8 +1438,12 @@ func (td *transactionDiffer) createDiffEthereumInvokeScript(tx *proto.EthereumTr } diff := newTxDiff() // Append sender diff. + senderAddress, err := tx.WavesAddressFrom(td.settings.AddressSchemeCharacter) + if err != nil { + return txBalanceChanges{}, errors.Wrapf(err, "failed to get sender address from ethereum invoke tx") + } - senderAddrID := txInvokeScriptKind.From.ID() + senderAddrID := senderAddress.ID() assetFee := proto.NewOptionalAssetWaves() senderFeeKey := byteKey(senderAddrID, assetFee) senderFeeBalanceDiff := -int64(tx.GetFee()) @@ -1439,7 +1456,7 @@ func (td *transactionDiffer) createDiffEthereumInvokeScript(tx *proto.EthereumTr } scriptAddrID := scriptAddr.ID() - addresses := []proto.WavesAddress{txInvokeScriptKind.From, *scriptAddr} + addresses := []proto.WavesAddress{senderAddress, *scriptAddr} changes := newTxBalanceChanges(addresses, diff) for _, payment := range decodedData.Payments { From 9a8f962d932c7b2c6ee514106cdf51858abcb57f Mon Sep 17 00:00:00 2001 From: esuwu Date: Tue, 14 Dec 2021 13:51:02 +0300 Subject: [PATCH 6/7] Renamed some of the methods --- pkg/state/eth_info.go | 14 +------------- pkg/state/invoke_applier.go | 10 ++++++++-- pkg/state/script_caller.go | 9 ++++++--- 3 files changed, 15 insertions(+), 18 deletions(-) diff --git a/pkg/state/eth_info.go b/pkg/state/eth_info.go index c2a6bf183..1fc7b22b0 100644 --- a/pkg/state/eth_info.go +++ b/pkg/state/eth_info.go @@ -17,18 +17,8 @@ func newEthInfo(stor *blockchainEntitiesStorage, settings *settings.BlockchainSe } func (e *ethInfo) fillRequiredTxFields(ethTx *proto.EthereumTransaction, params *appendTxParams) error { - EthSenderAddr, err := ethTx.From() - if err != nil { - return err - } - senderAddress, err := EthSenderAddr.ToWavesAddress(e.settings.AddressSchemeCharacter) - if err != nil { - return err - } - switch kind := ethTx.TxKind.(type) { case *proto.EthereumTransferWavesTxKind: - kind.From = senderAddress case *proto.EthereumTransferAssetsErc20TxKind: db := ethabi.NewErc20MethodsMap() @@ -46,8 +36,7 @@ func (e *ethInfo) fillRequiredTxFields(ethTx *proto.EthereumTransaction, params } fullAssetID := proto.ReconstructDigest(*assetID, assetInfo.tail) - kind.Asset = proto.NewOptionalAssetFromDigest(fullAssetID) - kind.From = senderAddress + kind.OptAsset = proto.NewOptionalAssetFromDigest(fullAssetID) case *proto.EthereumInvokeScriptTxKind: scriptAddr, err := ethTx.WavesAddressTo(e.settings.AddressSchemeCharacter) if err != nil { @@ -67,7 +56,6 @@ func (e *ethInfo) fillRequiredTxFields(ethTx *proto.EthereumTransaction, params } kind.DecodedCallData = decodedData - kind.From = senderAddress default: return errors.New("unexpected ethereum tx kind") } diff --git a/pkg/state/invoke_applier.go b/pkg/state/invoke_applier.go index b9cf2cb0b..3d73cd9f2 100644 --- a/pkg/state/invoke_applier.go +++ b/pkg/state/invoke_applier.go @@ -751,10 +751,16 @@ func (ia *invokeApplier) applyInvokeScript(tx proto.Transaction, info *fallibleV if err != nil { return nil, err } - decodedData := transaction.TxKind.DecodedData() + decodedData, err := transaction.TxKind.DecodedData() + if err != nil { + return nil, err + } paymentsLength = len(decodedData.Payments) txID = *transaction.ID - sender = transaction.TxKind.Sender() + sender, err = transaction.WavesAddressFrom(ia.settings.AddressSchemeCharacter) + if err != nil { + return nil, err + } default: return nil, errors.New("failed to apply an invoke script: unexpected type of transaction ") diff --git a/pkg/state/script_caller.go b/pkg/state/script_caller.go index 7ea6e81b2..2e0e22edf 100644 --- a/pkg/state/script_caller.go +++ b/pkg/state/script_caller.go @@ -239,7 +239,11 @@ func (a *scriptCaller) invokeFunction(tree *ride.Tree, tx proto.Transaction, inf defaultFunction = transaction.FunctionCall.Default case *proto.EthereumTransaction: - abiPayments := transaction.TxKind.DecodedData().Payments + decodedData, err := transaction.TxKind.DecodedData() + if err != nil { + return nil, err + } + abiPayments := decodedData.Payments scriptPayments := make([]proto.ScriptPayment, 0, len(abiPayments)) for _, p := range abiPayments { var optAsset proto.OptionalAsset @@ -257,11 +261,10 @@ func (a *scriptCaller) invokeFunction(tree *ride.Tree, tx proto.Transaction, inf if err != nil { return nil, err } - sender = transaction.TxKind.Sender() + sender, err = transaction.WavesAddressFrom(a.settings.AddressSchemeCharacter) if err != nil { return nil, errors.Errorf("failed to get waves address from ethereum transaction %v", err) } - decodedData := transaction.TxKind.DecodedData() functionName = decodedData.Name arguments, err := ride.ConvertDecodedEthereumArgumentsToProtoArguments(decodedData.Inputs) if err != nil { From 66f1d546addcdd8803a639b648ade5f95b9592ad Mon Sep 17 00:00:00 2001 From: esuwu Date: Tue, 14 Dec 2021 13:51:18 +0300 Subject: [PATCH 7/7] Renamed some of the methods --- pkg/proto/eth_transaction.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pkg/proto/eth_transaction.go b/pkg/proto/eth_transaction.go index 5bce227a4..3af62d35d 100644 --- a/pkg/proto/eth_transaction.go +++ b/pkg/proto/eth_transaction.go @@ -118,21 +118,21 @@ func (tx *EthereumTransferWavesTxKind) String() string { type EthereumTransferAssetsErc20TxKind struct { decodedData ethabi.DecodedCallData Arguments ethabi.ERC20TransferArguments - asset *OptionalAsset + OptAsset *OptionalAsset } func NewEthereumTransferAssetsErc20TxKind(decodedData ethabi.DecodedCallData, asset *OptionalAsset, arguments ethabi.ERC20TransferArguments) *EthereumTransferAssetsErc20TxKind { - return &EthereumTransferAssetsErc20TxKind{asset: asset, decodedData: decodedData, Arguments: arguments} + return &EthereumTransferAssetsErc20TxKind{OptAsset: asset, decodedData: decodedData, Arguments: arguments} } func (tx *EthereumTransferAssetsErc20TxKind) DecodedData() (*ethabi.DecodedCallData, error) { return &tx.decodedData, nil } func (tx *EthereumTransferAssetsErc20TxKind) Asset() (*OptionalAsset, error) { - if tx.asset == nil { + if tx.OptAsset == nil { return nil, errors.New("asset field of ethereum transfer assets tx is empty") } - return tx.asset, nil + return tx.OptAsset, nil } func (tx *EthereumTransferAssetsErc20TxKind) String() string { @@ -140,18 +140,18 @@ func (tx *EthereumTransferAssetsErc20TxKind) String() string { } type EthereumInvokeScriptTxKind struct { - decodedCallData *ethabi.DecodedCallData + DecodedCallData *ethabi.DecodedCallData } func NewEthereumInvokeScriptTxKind(decodedData *ethabi.DecodedCallData) *EthereumInvokeScriptTxKind { - return &EthereumInvokeScriptTxKind{decodedCallData: decodedData} + return &EthereumInvokeScriptTxKind{DecodedCallData: decodedData} } func (tx *EthereumInvokeScriptTxKind) DecodedData() (*ethabi.DecodedCallData, error) { - if tx.decodedCallData == nil { + if tx.DecodedCallData == nil { return nil, errors.New("ethereum invoke script tx has empty decoded data") } - return tx.decodedCallData, nil + return tx.DecodedCallData, nil } func (tx *EthereumInvokeScriptTxKind) String() string {