Skip to content

Commit

Permalink
fix: contstuction payloads (#190)
Browse files Browse the repository at this point in the history
* add:system tests

* add: go.mod

* update: rename send_test

* update: own go mod

* block tests

* add: accounts, mempool and network tests

* some construction endpoints

* add: system-test workflow

* fix: lint

* update: workflows

* fix: lint

* fix: system tests

* fix: makefile rosetta-cli

* fix: payloads get signers

* add: payloads systemtest

* lint :)

* changelog + rabbit

* fix: package name
  • Loading branch information
JulianToledano authored Jan 24, 2025
1 parent 9b56e7a commit 94e8d18
Show file tree
Hide file tree
Showing 15 changed files with 97 additions and 31 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ Ref: https://keepachangelog.com/en/1.0.0/
* [180](https://github.com/cosmos/rosetta/pull/180) Update to cosmos-sdk v0.52.0-rc.1.
* [180](https://github.com/cosmos/rosetta/pull/180) Added bech32 prefix flag.

### Bug Fixes

* [#190](https://github.com/cosmos/rosetta/pull/190) Fixed construction payloads to properly handle transaction signers.

## [v0.50.11](https://github.com/cosmos/rosetta/releases/tag/v0.50.11) 2024-12-19

### Improvements
Expand Down
2 changes: 1 addition & 1 deletion client_online.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ func NewClient(cfg *Config) (*Client, error) {
bank: nil,
tmRPC: nil,
version: fmt.Sprintf("%s/%s", info.AppName, v),
converter: NewConverter(cfg.Codec, cfg.InterfaceRegistry, txConfig),
converter: NewConverter(cfg.Codec, cfg.InterfaceRegistry, txConfig, address.NewBech32Codec(cfg.Bech32Prefix)),
}, nil
}

Expand Down
23 changes: 14 additions & 9 deletions converter.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
secp "github.com/decred/dcrd/dcrec/secp256k1/v4"

signingv1beta1 "cosmossdk.io/api/cosmos/tx/signing/v1beta1"
"cosmossdk.io/core/address"
sdkmath "cosmossdk.io/math"
banktypes "cosmossdk.io/x/bank/types"

Expand Down Expand Up @@ -107,9 +108,10 @@ type converter struct {
bytesToSign func(tx authsigning.Tx, signerData authsigning.SignerData) (b []byte, err error)
ir codectypes.InterfaceRegistry
cdc *codec.ProtoCodec
ac address.Codec
}

func NewConverter(cdc *codec.ProtoCodec, ir codectypes.InterfaceRegistry, cfg sdkclient.TxConfig) Converter {
func NewConverter(cdc *codec.ProtoCodec, ir codectypes.InterfaceRegistry, cfg sdkclient.TxConfig, ac address.Codec) Converter {
return converter{
newTxBuilder: cfg.NewTxBuilder,
txBuilderFromTx: cfg.WrapTxBuilder,
Expand All @@ -131,6 +133,7 @@ func NewConverter(cdc *codec.ProtoCodec, ir codectypes.InterfaceRegistry, cfg sd
},
ir: ir,
cdc: cdc,
ac: ac,
}
}

Expand Down Expand Up @@ -677,7 +680,7 @@ func (c converter) SigningComponents(tx authsigning.Tx, metadata *ConstructionMe
return nil, nil, crgerrs.WrapError(crgerrs.ErrConverter, fmt.Sprintf("getting signers v2 from tx %s", err.Error()))
}

signers, err := tx.GetSignaturesV2()
signers, err := tx.GetSigners()
if err != nil {
return nil, nil, crgerrs.WrapError(crgerrs.ErrConverter, fmt.Sprintf("getting signers v2 from tx %s", err.Error()))
}
Expand Down Expand Up @@ -707,18 +710,23 @@ func (c converter) SigningComponents(tx authsigning.Tx, metadata *ConstructionMe
// by checking if the signer at index i matches the pubkey at index
pubKey, err := c.ToSDK().PubKey(rosPubKeys[0])
if err != nil {
return nil, nil, crgerrs.WrapError(crgerrs.ErrConverter, fmt.Sprintf("while setting signatures %s", err.Error()))
return nil, nil, crgerrs.WrapError(crgerrs.ErrConverter, fmt.Sprintf("while checking pubkey %s", err.Error()))
}
if !bytes.Equal(pubKey.Address().Bytes(), signer.PubKey.Address()) {
if !bytes.Equal(pubKey.Address().Bytes(), signer) {
return nil, nil, crgerrs.WrapError(
crgerrs.ErrBadArgument,
fmt.Sprintf("public key at index %d does not match the expected transaction signer: %X <-> %X", i, rosPubKeys[i].Bytes, signer),
)
}

addr, err := c.ac.BytesToString(signer)
if err != nil {
return nil, nil, crgerrs.WrapError(crgerrs.ErrConverter, fmt.Sprintf("while converting to bech32 address: %s", err.Error()))
}

// set the signer data
signerData := authsigning.SignerData{
Address: string(signer.PubKey.Address()),
Address: addr,
ChainID: metadata.ChainID,
AccountNumber: metadata.SignersData[i].AccountNumber,
Sequence: metadata.SignersData[i].Sequence,
Expand All @@ -731,11 +739,8 @@ func (c converter) SigningComponents(tx authsigning.Tx, metadata *ConstructionMe
return nil, nil, crgerrs.WrapError(crgerrs.ErrUnknown, fmt.Sprintf("unable to sign tx: %s", err.Error()))
}

// set payload
signerAddress := sdk.AccAddress(signer.PubKey.Address()).String()

payloadsToSign[i] = &rosettatypes.SigningPayload{
AccountIdentifier: &rosettatypes.AccountIdentifier{Address: signerAddress},
AccountIdentifier: &rosettatypes.AccountIdentifier{Address: addr},
Bytes: signBytes,
SignatureType: rosettatypes.Ecdsa,
}
Expand Down
2 changes: 1 addition & 1 deletion converter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func (s *ConverterTestSuite) SetupTest() {
// instantiate converter
cdc, ir := rosetta.MakeCodec()
txConfig := authtx.NewTxConfig(cdc, address.NewBech32Codec("cosmos"), address.NewBech32Codec("cosmosvaloper"), authtx.DefaultSignModes)
s.c = rosetta.NewConverter(cdc, ir, txConfig)
s.c = rosetta.NewConverter(cdc, ir, txConfig, address.NewBech32Codec("cosmos"))
// add utils
s.ir = ir
s.cdc = cdc
Expand Down
2 changes: 1 addition & 1 deletion tests/systemtests/accounts_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//go:build system_test

package systemtests
package rossettaSystemTests

import (
"testing"
Expand Down
2 changes: 1 addition & 1 deletion tests/systemtests/block_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//go:build system_test

package systemtests
package rossettaSystemTests

import (
"testing"
Expand Down
37 changes: 33 additions & 4 deletions tests/systemtests/construction_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
//go:build system_test

package systemtests
package rossettaSystemTests

import (
"encoding/base64"
"encoding/hex"
"fmt"
"strings"
"testing"

Expand All @@ -25,12 +26,13 @@ func TestDerive(t *testing.T) {
rosettaRest := newRestClient(rosetta)

pubKey := secp256k1.GenPrivKey().PubKey()
addr, err := address.NewBech32Codec("cosmos").BytesToString(pubKey.Address().Bytes())
assert.NoError(t, err)

hexPk := strings.Split(pubKey.String(), "{")[1]

res, err := rosettaRest.constructionDerive(hexPk[:len(hexPk)-1])
assert.NoError(t, err)

addr, err := address.NewBech32Codec("cosmos").BytesToString(pubKey.Address().Bytes())
assert.NoError(t, err)
assert.Equal(t, addr, gjson.GetBytes(res, "address").String())
}

Expand Down Expand Up @@ -82,3 +84,30 @@ func TestMetadata(t *testing.T) {
assert.Equal(t, gjson.GetBytes(res, "metadata.gas_price").String(), "123uatom")
assert.Greater(t, gjson.GetBytes(res, "suggested_fee.0.value").Int(), int64(0))
}

func TestPayloads(t *testing.T) {
sut.ResetChain(t)
sut.StartChain(t)

rosetta.restart(t)
rosettaRest := newRestClient(rosetta)

cli := systemtests.NewCLIWrapper(t, sut, verbose)
addr := cli.GetKeyAddr("node0")
bz, err := base64.StdEncoding.DecodeString(cli.GetPubKeyByCustomField(addr, "address"))
assert.NoError(t, err)

pk := secp256k1.PubKey{Key: bz}
hexPk := strings.Split(pk.String(), "{")[1]
hexPk = hexPk[:len(hexPk)-1]

op := operation{
msgType: "/cosmos.bank.v1beta1.MsgSend",
metadata: fmt.Sprintf(`{"from_address": "%s", "to_address": "%s", "amount":[{"amount":"123", "denom":"stake"}]}`, addr, cli.AddKey("to_address")),
}

res, err := rosettaRest.constructionPayloads(`"signer_data":[{"account_number":1, "sequence": 0}]`, hexPk, op)
assert.NoError(t, err)
assert.NotEmpty(t, gjson.GetBytes(res, "unsigned_transaction"))
assert.Equal(t, gjson.GetBytes(res, "payloads.0.address").String(), addr)
}
2 changes: 1 addition & 1 deletion tests/systemtests/go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module rossetaSystemTests
module rossettaSystemTests

go 1.23.1

Expand Down
2 changes: 1 addition & 1 deletion tests/systemtests/main_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//go:build system_test

package systemtests
package rossettaSystemTests

import (
"testing"
Expand Down
2 changes: 1 addition & 1 deletion tests/systemtests/mempool_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//go:build system_test

package systemtests
package rossettaSystemTests

import (
"testing"
Expand Down
2 changes: 1 addition & 1 deletion tests/systemtests/network_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//go:build system_test

package systemtests
package rossettaSystemTests

import (
"testing"
Expand Down
34 changes: 33 additions & 1 deletion tests/systemtests/rest_client.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package systemtests
package rossettaSystemTests

import (
"fmt"
Expand Down Expand Up @@ -156,3 +156,35 @@ func (c *restClient) constructionMetadata(hexPk string, options map[string]inter

return res.Body(), nil
}

func (c *restClient) constructionPayloads(metadata, hexPk string, opts ...operation) ([]byte, error) {
body := fmt.Sprintf(
`{%s, "operations":%s, "metadata":{%s}, "public_keys":[{"hex_bytes":"%s", "curve_type":"secp256k1"}]}`,
c.networkIdentifier, payloadsOperations(opts...), metadata, hexPk)
res, err := c.client.R().SetBody(
body,
).Post("/construction/payloads")
if err != nil {
return nil, err
}

return res.Body(), nil
}

type operation struct {
msgType string
metadata string
}

func (o *operation) String() string {
return fmt.Sprintf(`"type":"%s", "metadata": %s`, o.msgType, o.metadata)
}

func payloadsOperations(ops ...operation) []string {
r := make([]string, len(ops))
for i, op := range ops {
r[i] = fmt.Sprintf(`{"operation_identifier":{"index": %d}, %s}`, i, op.String())
}

return r
}
7 changes: 2 additions & 5 deletions tests/systemtests/rosetta.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package systemtests
package rossettaSystemTests

import (
"bufio"
Expand Down Expand Up @@ -35,7 +35,6 @@ type rosettaRunner struct {
Network string // the network name (default "network")
Plugin string // plugin folder name
Tendermint string // CometBFT rpc endpoint
Offline bool // run rosetta only with construction API
verbose bool
out io.Writer
outBuff *ring.Ring
Expand All @@ -46,7 +45,7 @@ type rosettaRunner struct {
outputDir string
}

func newRosettaRunner(binary, denom, grpcTypesServer, plugin string, offline, verbose bool) rosettaRunner {
func newRosettaRunner(binary, denom, grpcTypesServer, plugin string, verbose bool) rosettaRunner {
execBinary := filepath.Join(systemtests.WorkDir, "binaries", binary)
return rosettaRunner{
execBinary: execBinary,
Expand All @@ -58,7 +57,6 @@ func newRosettaRunner(binary, denom, grpcTypesServer, plugin string, offline, ve
Network: "cosmos",
Plugin: plugin,
Tendermint: "tcp://localhost:26657",
Offline: offline,
out: os.Stdout,
outBuff: ring.New(100),
errBuff: ring.New(100),
Expand All @@ -77,7 +75,6 @@ func (r *rosettaRunner) start(t *testing.T) {
"--addr", r.Addr,
"--grpc", r.GRPC,
"--grpc-types-server", r.GRPCTypesServer,
"--plugin", r.Plugin,
}

r.log("Start Rosetta\n")
Expand Down
5 changes: 2 additions & 3 deletions tests/systemtests/test_runner.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package systemtests
package rossettaSystemTests

import (
"flag"
Expand Down Expand Up @@ -33,7 +33,6 @@ func RunTests(m *testing.M) {
rosettaDenom := flag.String("rosetta-denom", "ustake", "rosetta denom to suggest")
rosettaGRPCTypesServer := flag.String("rosetta-grpc-types-server", "localhost:9090", "rosetta gRPC Server endpoint for proto messages types and reflection")
rosettaPlugin := flag.String("rosetta-plugin", "", "rosetta plugin folder name")
rosettaOffline := flag.Bool("rosetta-offline", false, "rosetta run only with construction API")
flag.Parse()

requireEnoughFileHandlers(*nodesCount + 1) // +1 as tests may start another node
Expand All @@ -56,7 +55,7 @@ func RunTests(m *testing.M) {
sut = systemtests.NewSystemUnderTest(*execBinary, verbose, *nodesCount, *blockTime)
sut.SetupChain() // setup chain and keyring

rosetta = newRosettaRunner(*rosettaBinary, *rosettaDenom, *rosettaGRPCTypesServer, *rosettaPlugin, *rosettaOffline, verbose)
rosetta = newRosettaRunner(*rosettaBinary, *rosettaDenom, *rosettaGRPCTypesServer, *rosettaPlugin, verbose)

// run tests
exitCode := m.Run()
Expand Down
2 changes: 1 addition & 1 deletion utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ func parseTxData(tx authsigning.Tx, signerData signing2.SignerData) (*signing2.T
return nil, crgerrs.WrapError(crgerrs.ErrCodec, fmt.Sprintf("parsing tx data %s", err.Error()))
}

// todo: timeouthecigh
// todo: timeoutHeigh
txData := signing2.TxData{
Body: &txv1beta1.TxBody{
Messages: parsedTxMsgs,
Expand Down

0 comments on commit 94e8d18

Please sign in to comment.