From 35fd591311e92d3e4185e88ae2171c560303d3cb Mon Sep 17 00:00:00 2001 From: Likhita Polavarapu <78951027+likhita-809@users.noreply.github.com> Date: Wed, 13 Mar 2024 16:18:48 +0530 Subject: [PATCH] refactor: sdk.Tx implements transaction.Tx (#19588) --- contrib/images/simd-env/Dockerfile | 5 ++ server/mock/tx.go | 22 +++++++- server/v2/stf/mock/tx.go | 7 ++- types/mempool/mempool_test.go | 40 +++++++++++++ .../signer_extraction_adapater_test.go | 20 +++++++ x/auth/tx/gogotx.go | 53 ++++++++++++++++++ x/tx/decode/decode.go | 56 +++++++++++++++++++ x/tx/go.mod | 4 ++ x/tx/go.sum | 15 +++-- 9 files changed, 209 insertions(+), 13 deletions(-) diff --git a/contrib/images/simd-env/Dockerfile b/contrib/images/simd-env/Dockerfile index 86e9670afb9a..88b57ef9e275 100644 --- a/contrib/images/simd-env/Dockerfile +++ b/contrib/images/simd-env/Dockerfile @@ -22,6 +22,11 @@ COPY x/bank/go.mod x/bank/go.sum /work/x/bank/ COPY x/mint/go.mod x/mint/go.sum /work/x/mint/ COPY x/consensus/go.mod x/consensus/go.sum /work/x/consensus/ COPY x/accounts/go.mod x/accounts/go.sum /work/x/accounts/ +COPY runtime/v2/go.mod runtime/v2/go.sum /work/runtime/v2/ +COPY server/v2/appmanager/go.mod server/v2/appmanager/go.sum /work/server/v2/appmanager/ +COPY server/v2/core/go.mod server/v2/core/go.sum /work/server/v2/core/ +COPY server/v2/stf/go.mod server/v2/stf/go.sum /work/server/v2/stf/ + RUN go mod download COPY ./ /work diff --git a/server/mock/tx.go b/server/mock/tx.go index 875c1abb9c10..d8599dbca4af 100644 --- a/server/mock/tx.go +++ b/server/mock/tx.go @@ -4,7 +4,7 @@ import ( "bytes" "fmt" - "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/proto" bankv1beta1 "cosmossdk.io/api/cosmos/bank/v1beta1" errorsmod "cosmossdk.io/errors" @@ -95,6 +95,22 @@ func NewTx(key, value string, accAddress sdk.AccAddress) *KVStoreTx { } } +func (msg *KVStoreTx) Hash() [32]byte { + return [32]byte{} +} + +func (msg *KVStoreTx) GetGasLimit() (uint64, error) { + return 0, nil +} + +func (msg *KVStoreTx) GetMessages() ([]proto.Message, error) { + return nil, nil +} + +func (msg *KVStoreTx) GetSenders() ([][]byte, error) { + return nil, nil +} + func (msg *KVStoreTx) Type() string { return "kvstore_tx" } @@ -103,8 +119,8 @@ func (msg *KVStoreTx) GetMsgs() []sdk.Msg { return []sdk.Msg{msg} } -func (msg *KVStoreTx) GetReflectMessages() ([]protoreflect.Message, error) { - return []protoreflect.Message{(&bankv1beta1.MsgSend{FromAddress: msg.address.String()}).ProtoReflect()}, nil // this is a hack for tests +func (msg *KVStoreTx) GetMsgsV2() ([]proto.Message, error) { + return []proto.Message{&bankv1beta1.MsgSend{FromAddress: msg.address.String()}}, nil // this is a hack for tests } func (msg *KVStoreTx) GetSignBytes() []byte { diff --git a/server/v2/stf/mock/tx.go b/server/v2/stf/mock/tx.go index a40eaa4536bc..4252f30bce98 100644 --- a/server/v2/stf/mock/tx.go +++ b/server/v2/stf/mock/tx.go @@ -22,8 +22,11 @@ func (t Tx) Hash() [32]byte { return sha256.Sum256(t.Bytes()) } -func (t Tx) GetMessages() ([]transaction.Msg, error) { - return []transaction.Msg{t.Msg}, nil +func (t Tx) GetMessages() ([]transaction.Type, error) { + if t.Msg == nil { + return nil, errors.New("messages not available or are nil") + } + return []transaction.Type{t.Msg}, nil } func (t Tx) GetSenders() ([]transaction.Identity, error) { diff --git a/types/mempool/mempool_test.go b/types/mempool/mempool_test.go index 819441a5e5b8..744f58e5920a 100644 --- a/types/mempool/mempool_test.go +++ b/types/mempool/mempool_test.go @@ -75,6 +75,26 @@ var ( _ cryptotypes.PubKey = (*testPubKey)(nil) ) +func (tx testTx) Bytes() []byte { + return []byte{} +} + +func (tx testTx) Hash() [32]byte { + return [32]byte{} +} + +func (tx testTx) GetGasLimit() (uint64, error) { + return 0, nil +} + +func (tx testTx) GetMessages() ([]protov2.Message, error) { + return nil, nil +} + +func (tx testTx) GetSenders() ([][]byte, error) { + return nil, nil +} + func (tx testTx) GetMsgs() []sdk.Msg { return nil } func (tx testTx) GetReflectMessages() ([]protoreflect.Message, error) { return nil, nil } @@ -89,6 +109,26 @@ type sigErrTx struct { getSigs func() ([]txsigning.SignatureV2, error) } +func (sigErrTx) Bytes() []byte { + return []byte{} +} + +func (sigErrTx) Hash() [32]byte { + return [32]byte{} +} + +func (sigErrTx) GetGasLimit() (uint64, error) { + return 0, nil +} + +func (sigErrTx) GetMessages() ([]protov2.Message, error) { + return nil, nil +} + +func (sigErrTx) GetSenders() ([][]byte, error) { + return nil, nil +} + func (sigErrTx) Size() int64 { return 0 } func (sigErrTx) GetMsgs() []sdk.Msg { return nil } diff --git a/types/mempool/signer_extraction_adapater_test.go b/types/mempool/signer_extraction_adapater_test.go index 158cbe071ca0..93850fbfea7e 100644 --- a/types/mempool/signer_extraction_adapater_test.go +++ b/types/mempool/signer_extraction_adapater_test.go @@ -24,6 +24,26 @@ func (n nonVerifiableTx) GetReflectMessages() ([]protoreflect.Message, error) { panic("not implemented") } +func (n nonVerifiableTx) Bytes() []byte { + return []byte{} +} + +func (n nonVerifiableTx) Hash() [32]byte { + return [32]byte{} +} + +func (n nonVerifiableTx) GetGasLimit() (uint64, error) { + return 0, nil +} + +func (n nonVerifiableTx) GetMessages() ([]proto.Message, error) { + return nil, nil +} + +func (n nonVerifiableTx) GetSenders() ([][]byte, error) { + return nil, nil +} + func TestDefaultSignerExtractor(t *testing.T) { accounts := simtypes.RandomAccounts(rand.New(rand.NewSource(0)), 1) sa := accounts[0].Address diff --git a/x/auth/tx/gogotx.go b/x/auth/tx/gogotx.go index 250c9631aada..ef1678190787 100644 --- a/x/auth/tx/gogotx.go +++ b/x/auth/tx/gogotx.go @@ -1,6 +1,8 @@ package tx import ( + "crypto/sha256" + "errors" "fmt" "reflect" "strings" @@ -100,10 +102,61 @@ type gogoTxWrapper struct { fees sdk.Coins feePayer []byte feeGranter []byte + + // Cache for hash and full bytes + cachedHash [32]byte + cachedBytes []byte + cachedHashed bool } func (w *gogoTxWrapper) String() string { return w.decodedTx.Tx.String() } +func (w *gogoTxWrapper) Bytes() []byte { + if !w.cachedHashed { + w.computeHashAndBytes() + } + return w.cachedBytes +} + +func (w *gogoTxWrapper) Hash() [32]byte { + if !w.cachedHashed { + w.computeHashAndBytes() + } + return w.cachedHash +} + +func (w *gogoTxWrapper) computeHashAndBytes() { + bz, err := proto.Marshal(w.decodedTx.TxRaw) + if err != nil { + panic(err) + } + + w.cachedBytes = bz + w.cachedHash = sha256.Sum256(bz) + w.cachedHashed = true +} + +func (w *gogoTxWrapper) GetGasLimit() (uint64, error) { + if w.decodedTx == nil || w.decodedTx.Tx == nil || w.decodedTx.Tx.AuthInfo == nil || w.decodedTx.Tx.AuthInfo.Fee == nil { + return 0, errors.New("gas limit not available, one or more required fields are nil") + } + return w.decodedTx.Tx.AuthInfo.Fee.GasLimit, nil +} + +func (w *gogoTxWrapper) GetMessages() ([]protov2.Message, error) { + if w.decodedTx == nil || w.decodedTx.Messages == nil { + return nil, errors.New("messages not available or are nil") + } + return w.decodedTx.Messages, nil +} + +func (w *gogoTxWrapper) GetSenders() ([][]byte, error) { + if w.decodedTx == nil || w.decodedTx.Signers == nil { + return nil, errors.New("Senders not available or are nil") + } + return w.decodedTx.Signers, nil +} + var ( _ authsigning.Tx = &gogoTxWrapper{} _ ante.HasExtensionOptionsTx = &gogoTxWrapper{} diff --git a/x/tx/decode/decode.go b/x/tx/decode/decode.go index 4dafe9549af4..77cff820393f 100644 --- a/x/tx/decode/decode.go +++ b/x/tx/decode/decode.go @@ -1,12 +1,14 @@ package decode import ( + "crypto/sha256" "errors" "github.com/cosmos/cosmos-proto/anyutil" "google.golang.org/protobuf/proto" v1beta1 "cosmossdk.io/api/cosmos/tx/v1beta1" + "cosmossdk.io/core/transaction" errorsmod "cosmossdk.io/errors" "cosmossdk.io/x/tx/signing" ) @@ -18,8 +20,15 @@ type DecodedTx struct { TxRaw *v1beta1.TxRaw Signers [][]byte TxBodyHasUnknownNonCriticals bool + + // Cache for hash and full bytes + cachedHash [32]byte + cachedBytes []byte + cachedHashed bool } +var _ transaction.Tx = &DecodedTx{} + // Decoder contains the dependencies required for decoding transactions. type Decoder struct { signingCtx *signing.Context @@ -126,3 +135,50 @@ func (d *Decoder) Decode(txBytes []byte) (*DecodedTx, error) { Signers: signers, }, nil } + +// Hash implements the interface for the Tx interface. +func (dtx *DecodedTx) Hash() [32]byte { + if !dtx.cachedHashed { + dtx.computeHashAndBytes() + } + return dtx.cachedHash +} + +func (dtx *DecodedTx) GetGasLimit() (uint64, error) { + if dtx == nil || dtx.Tx == nil || dtx.Tx.AuthInfo == nil || dtx.Tx.AuthInfo.Fee == nil { + return 0, errors.New("gas limit not available or one or more required fields are nil") + } + return dtx.Tx.AuthInfo.Fee.GasLimit, nil +} + +func (dtx *DecodedTx) GetMessages() ([]proto.Message, error) { + if dtx == nil || dtx.Messages == nil { + return nil, errors.New("messages not available or are nil") + } + return dtx.Messages, nil +} + +func (dtx *DecodedTx) GetSenders() ([][]byte, error) { + if dtx == nil || dtx.Signers == nil { + return nil, errors.New("senders not available or are nil") + } + return dtx.Signers, nil +} + +func (dtx *DecodedTx) Bytes() []byte { + if !dtx.cachedHashed { + dtx.computeHashAndBytes() + } + return dtx.cachedBytes +} + +func (dtx *DecodedTx) computeHashAndBytes() { + bz, err := proto.Marshal(dtx.TxRaw) + if err != nil { + panic(err) + } + + dtx.cachedBytes = bz + dtx.cachedHash = sha256.Sum256(bz) + dtx.cachedHashed = true +} diff --git a/x/tx/go.mod b/x/tx/go.mod index 1dc00fe623bc..f2209fd299bd 100644 --- a/x/tx/go.mod +++ b/x/tx/go.mod @@ -22,6 +22,8 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/kr/text v0.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect golang.org/x/net v0.25.0 // indirect @@ -33,6 +35,8 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) +replace cosmossdk.io/core => ../../core + // NOTE: we do not want to replace to the development version of cosmossdk.io/api yet // Until https://github.com/cosmos/cosmos-sdk/issues/19228 is resolved // We are tagging x/tx from main and must keep using released versions of x/tx dependencies diff --git a/x/tx/go.sum b/x/tx/go.sum index b5a03e4cecca..17e0fdffc7b1 100644 --- a/x/tx/go.sum +++ b/x/tx/go.sum @@ -1,15 +1,14 @@ -cosmossdk.io/api v0.7.5 h1:eMPTReoNmGUm8DeiQL9DyM8sYDjEhWzL1+nLbI9DqtQ= -cosmossdk.io/api v0.7.5/go.mod h1:IcxpYS5fMemZGqyYtErK7OqvdM0C8kdW3dq8Q/XIG38= -cosmossdk.io/core v0.11.0 h1:vtIafqUi+1ZNAE/oxLOQQ7Oek2n4S48SWLG8h/+wdbo= -cosmossdk.io/core v0.11.0/go.mod h1:LaTtayWBSoacF5xNzoF8tmLhehqlA9z1SWiPuNC6X1w= +cosmossdk.io/api v0.7.3 h1:V815i8YOwOAQa1rLCsSMjVG5Gnzs02JLq+l7ks8s1jk= +cosmossdk.io/api v0.7.3/go.mod h1:IcxpYS5fMemZGqyYtErK7OqvdM0C8kdW3dq8Q/XIG38= cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= cosmossdk.io/errors v1.0.1/go.mod h1:MeelVSZThMi4bEakzhhhE/CKqVv3nOJDA25bIqRDu/U= cosmossdk.io/math v1.3.0 h1:RC+jryuKeytIiictDslBP9i1fhkVm6ZDmZEoNP316zE= cosmossdk.io/math v1.3.0/go.mod h1:vnRTxewy+M7BtXBNFybkuhSH4WfedVAAnERHgVFhp3k= -github.com/cosmos/cosmos-proto v1.0.0-beta.5 h1:eNcayDLpip+zVLRLYafhzLvQlSmyab+RC5W7ZfmxJLA= -github.com/cosmos/cosmos-proto v1.0.0-beta.5/go.mod h1:hQGLpiIUloJBMdQMMWb/4wRApmI9hjHH05nefC0Ojec= -github.com/cosmos/gogoproto v1.4.12 h1:vB6Lbe/rtnYGjQuFxkPiPYiCybqFT8QvLipDZP8JpFE= -github.com/cosmos/gogoproto v1.4.12/go.mod h1:LnZob1bXRdUoqMMtwYlcR3wjiElmlC+FkjaZRv1/eLY= +github.com/cosmos/cosmos-proto v1.0.0-beta.4 h1:aEL7tU/rLOmxZQ9z4i7mzxcLbSCY48OdY7lIWTLG7oU= +github.com/cosmos/cosmos-proto v1.0.0-beta.4/go.mod h1:oeB+FyVzG3XrQJbJng0EnV8Vljfk9XvTIpGILNU/9Co= +github.com/cosmos/gogoproto v1.4.11 h1:LZcMHrx4FjUgrqQSWeaGC1v/TeuVFqSLa43CC6aWR2g= +github.com/cosmos/gogoproto v1.4.11/go.mod h1:/g39Mh8m17X8Q/GDEs5zYTSNaNnInBSohtaxzQnYq1Y= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=