forked from cerc-io/laconicd-deprecated
!fix(evm): Fix eth tx hashes in json-rpc responses (#1176)
* Fix eth tx hashes in json-rpc responses Closes: #1175 - Remove Size_ field - Validate From/Hash fields in ante handler - Recompute tx hashes in json-rpc apis to cope with old blocks Update CHANGELOG.md remove Size_, validate Hash/From, add unit tests update spec Update CHANGELOG.md Update app/ante/eth.go populate From in SendRawTransaction Apply suggestions from code review keep Size_ field to avoid breaking tx format * move some validation to ValidateBasic * move validation to ValidateBasic * make ToTransaction returns a valid msg * restructure the protoTxProvider check * add comment * workaround tx hash issue in event parsing * fix integration test * fix unit test Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
co-authored by
Federico Kunze Küllmer
parent
8932a6d743
commit
ffe78da36e
@@ -257,6 +257,8 @@ func prepareEthTx(priv *ethsecp256k1.PrivKey, msgEthereumTx *evmtypes.MsgEthereu
|
||||
err = msgEthereumTx.Sign(s.ethSigner, tests.NewSigner(priv))
|
||||
s.Require().NoError(err)
|
||||
|
||||
// A valid msg should have empty `From`
|
||||
msgEthereumTx.From = ""
|
||||
err = txBuilder.SetMsgs(msgEthereumTx)
|
||||
s.Require().NoError(err)
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ An EVM state transition can be achieved by using the `MsgEthereumTx`. This messa
|
||||
type MsgEthereumTx struct {
|
||||
// inner transaction data
|
||||
Data *types.Any `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
|
||||
// encoded storage size of the transaction
|
||||
// DEPRECATED: encoded storage size of the transaction
|
||||
Size_ float64 `protobuf:"fixed64,2,opt,name=size,proto3" json:"-"`
|
||||
// transaction hash in hex format
|
||||
Hash string `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty" rlp:"-"`
|
||||
|
||||
+24
-4
@@ -130,10 +130,12 @@ func newMsgEthereumTx(
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return &MsgEthereumTx{Data: dataAny}
|
||||
msg := MsgEthereumTx{Data: dataAny}
|
||||
msg.Hash = msg.AsTransaction().Hash().Hex()
|
||||
return &msg
|
||||
}
|
||||
|
||||
// fromEthereumTx populates the message fields from the given ethereum transaction
|
||||
// FromEthereumTx populates the message fields from the given ethereum transaction
|
||||
func (msg *MsgEthereumTx) FromEthereumTx(tx *ethtypes.Transaction) error {
|
||||
txData, err := NewTxDataFromTx(tx)
|
||||
if err != nil {
|
||||
@@ -146,7 +148,6 @@ func (msg *MsgEthereumTx) FromEthereumTx(tx *ethtypes.Transaction) error {
|
||||
}
|
||||
|
||||
msg.Data = anyTxData
|
||||
msg.Size_ = float64(tx.Size())
|
||||
msg.Hash = tx.Hash().Hex()
|
||||
return nil
|
||||
}
|
||||
@@ -166,6 +167,11 @@ func (msg MsgEthereumTx) ValidateBasic() error {
|
||||
}
|
||||
}
|
||||
|
||||
// Validate Size_ field, should be kept empty
|
||||
if msg.Size_ != 0 {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "tx size is deprecated")
|
||||
}
|
||||
|
||||
txData, err := UnpackTxData(msg.Data)
|
||||
if err != nil {
|
||||
return sdkerrors.Wrap(err, "failed to unpack tx data")
|
||||
@@ -176,7 +182,17 @@ func (msg MsgEthereumTx) ValidateBasic() error {
|
||||
return sdkerrors.Wrap(ErrInvalidGasLimit, "gas limit must not be zero")
|
||||
}
|
||||
|
||||
return txData.Validate()
|
||||
if err := txData.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Validate Hash field after validated txData to avoid panic
|
||||
txHash := msg.AsTransaction().Hash().Hex()
|
||||
if msg.Hash != txHash {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid tx hash %s, expected: %s", msg.Hash, txHash)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetMsgs returns a single MsgEthereumTx as an sdk.Msg.
|
||||
@@ -342,6 +358,10 @@ func (msg *MsgEthereumTx) BuildTx(b client.TxBuilder, evmDenom string) (signing.
|
||||
}
|
||||
|
||||
builder.SetExtensionOptions(option)
|
||||
|
||||
// A valid msg should have empty `From`
|
||||
msg.From = ""
|
||||
|
||||
err = builder.SetMsgs(msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
+75
-14
@@ -372,24 +372,85 @@ func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasic() {
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range testCases {
|
||||
to := common.HexToAddress(tc.from)
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.msg, func() {
|
||||
to := common.HexToAddress(tc.from)
|
||||
|
||||
tx := types.NewTx(tc.chainID, 1, &to, tc.amount, tc.gasLimit, tc.gasPrice, tc.gasFeeCap, tc.gasTipCap, nil, tc.accessList)
|
||||
tx.From = tc.from
|
||||
tx := types.NewTx(tc.chainID, 1, &to, tc.amount, tc.gasLimit, tc.gasPrice, tc.gasFeeCap, tc.gasTipCap, nil, tc.accessList)
|
||||
tx.From = tc.from
|
||||
|
||||
// apply nil assignment here to test ValidateBasic function instead of NewTx
|
||||
if strings.Contains(tc.msg, "nil tx.Data") {
|
||||
tx.Data = nil
|
||||
}
|
||||
// apply nil assignment here to test ValidateBasic function instead of NewTx
|
||||
if strings.Contains(tc.msg, "nil tx.Data") {
|
||||
tx.Data = nil
|
||||
}
|
||||
|
||||
err := tx.ValidateBasic()
|
||||
err := tx.ValidateBasic()
|
||||
|
||||
if tc.expectPass {
|
||||
suite.Require().NoError(err, "valid test %d failed: %s, %v", i, tc.msg)
|
||||
} else {
|
||||
suite.Require().Error(err, "invalid test %d passed: %s, %v", i, tc.msg)
|
||||
}
|
||||
if tc.expectPass {
|
||||
suite.Require().NoError(err)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func (suite *MsgsTestSuite) TestMsgEthereumTx_ValidateBasicAdvanced() {
|
||||
hundredInt := big.NewInt(100)
|
||||
testCases := []struct {
|
||||
msg string
|
||||
msgBuilder func() *types.MsgEthereumTx
|
||||
expectPass bool
|
||||
}{
|
||||
{
|
||||
"fails - invalid tx hash",
|
||||
func() *types.MsgEthereumTx {
|
||||
msg := types.NewTxContract(
|
||||
hundredInt,
|
||||
1,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
big.NewInt(150),
|
||||
big.NewInt(200),
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
msg.Hash = "0x00"
|
||||
return msg
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"fails - invalid size",
|
||||
func() *types.MsgEthereumTx {
|
||||
msg := types.NewTxContract(
|
||||
hundredInt,
|
||||
1,
|
||||
big.NewInt(10),
|
||||
100000,
|
||||
big.NewInt(150),
|
||||
big.NewInt(200),
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
)
|
||||
msg.Size_ = 1
|
||||
return msg
|
||||
},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.msg, func() {
|
||||
err := tc.msgBuilder().ValidateBasic()
|
||||
if tc.expectPass {
|
||||
suite.Require().NoError(err)
|
||||
} else {
|
||||
suite.Require().Error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Generated
+1
-1
@@ -37,7 +37,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||
type MsgEthereumTx struct {
|
||||
// inner transaction data
|
||||
Data *types.Any `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
|
||||
// encoded storage size of the transaction
|
||||
// DEPRECATED: encoded storage size of the transaction
|
||||
Size_ float64 `protobuf:"fixed64,2,opt,name=size,proto3" json:"-"`
|
||||
// transaction hash in hex format
|
||||
Hash string `protobuf:"bytes,3,opt,name=hash,proto3" json:"hash,omitempty" rlp:"-"`
|
||||
|
||||
@@ -143,10 +143,12 @@ func (args *TransactionArgs) ToTransaction() *MsgEthereumTx {
|
||||
from = args.From.Hex()
|
||||
}
|
||||
|
||||
return &MsgEthereumTx{
|
||||
msg := MsgEthereumTx{
|
||||
Data: any,
|
||||
From: from,
|
||||
}
|
||||
msg.Hash = msg.AsTransaction().Hash().Hex()
|
||||
return &msg
|
||||
}
|
||||
|
||||
// ToMessage converts the arguments to the Message type used by the core evm.
|
||||
|
||||
@@ -62,7 +62,9 @@ func UnwrapEthereumMsg(tx *sdk.Tx, ethHash common.Hash) (*MsgEthereumTx, error)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid tx type: %T", tx)
|
||||
}
|
||||
if ethMsg.AsTransaction().Hash() == ethHash {
|
||||
txHash := ethMsg.AsTransaction().Hash()
|
||||
ethMsg.Hash = txHash.Hex()
|
||||
if txHash == ethHash {
|
||||
return ethMsg, nil
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user