Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Marshal blocks and transactions inside API calls #2153

Merged
merged 2 commits into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions api/common_args_responses.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
package api

import (
stdjson "encoding/json"

"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/formatting"
"github.com/ava-labs/avalanchego/utils/json"
Expand Down Expand Up @@ -75,7 +77,7 @@ type GetBlockByHeightArgs struct {

// GetBlockResponse is the response object for the GetBlock API.
type GetBlockResponse struct {
Block interface{} `json:"block"`
Block stdjson.RawMessage `json:"block"`
// If GetBlockResponse.Encoding is formatting.Hex, GetBlockResponse.Block is
// the string representation of the block under hex encoding.
// If GetBlockResponse.Encoding is formatting.JSON, GetBlockResponse.Block
Expand Down Expand Up @@ -105,7 +107,7 @@ type GetTxReply struct {
// the tx under hex encoding.
// If [GetTxArgs.Encoding] is [JSON], [Tx] is the actual tx, which will be
// returned as JSON to the caller.
Tx interface{} `json:"tx"`
Tx stdjson.RawMessage `json:"tx"`
Encoding formatting.Encoding `json:"encoding"`
}

Expand Down
53 changes: 30 additions & 23 deletions vms/avm/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"math"
"net/http"

stdjson "encoding/json"

"go.uber.org/zap"

"github.com/ava-labs/avalanchego/api"
Expand Down Expand Up @@ -79,6 +81,7 @@ func (s *Service) GetBlock(_ *http.Request, args *api.GetBlockArgs, reply *api.G
}
reply.Encoding = args.Encoding

var result any
if args.Encoding == formatting.JSON {
block.InitCtx(s.vm.ctx)
for _, tx := range block.Txs() {
Expand All @@ -92,16 +95,16 @@ func (s *Service) GetBlock(_ *http.Request, args *api.GetBlockArgs, reply *api.G
return err
}
}
reply.Block = block
return nil
}

reply.Block, err = formatting.Encode(args.Encoding, block.Bytes())
if err != nil {
return fmt.Errorf("couldn't encode block %s as string: %w", args.BlockID, err)
result = block
} else {
result, err = formatting.Encode(args.Encoding, block.Bytes())
if err != nil {
return fmt.Errorf("couldn't encode block %s as string: %w", args.BlockID, err)
}
Comment on lines +101 to +103
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we could move this error and the one above (line 94-96) outside of the if else.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The above error is in a for loop - so I don't think it makes sense to refactor this instance

}

return nil
reply.Block, err = stdjson.Marshal(result)
return err
}

// GetBlockByHeight returns the block at the given height.
Expand Down Expand Up @@ -130,6 +133,7 @@ func (s *Service) GetBlockByHeight(_ *http.Request, args *api.GetBlockByHeightAr
return fmt.Errorf("couldn't get block with id %s: %w", blockID, err)
}

var result any
if args.Encoding == formatting.JSON {
block.InitCtx(s.vm.ctx)
for _, tx := range block.Txs() {
Expand All @@ -143,16 +147,16 @@ func (s *Service) GetBlockByHeight(_ *http.Request, args *api.GetBlockByHeightAr
return err
}
}
reply.Block = block
return nil
}

reply.Block, err = formatting.Encode(args.Encoding, block.Bytes())
if err != nil {
return fmt.Errorf("couldn't encode block %s as string: %w", blockID, err)
result = block
} else {
result, err = formatting.Encode(args.Encoding, block.Bytes())
if err != nil {
return fmt.Errorf("couldn't encode block %s as string: %w", blockID, err)
}
Comment on lines +153 to +155
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: consider mogin this error check and the one on lines 146-149 outside of the if/else scope

}

return nil
reply.Block, err = stdjson.Marshal(result)
return err
}

// GetHeight returns the height of the last accepted block.
Expand Down Expand Up @@ -320,23 +324,26 @@ func (s *Service) GetTx(_ *http.Request, args *api.GetTxArgs, reply *api.GetTxRe
if err != nil {
return err
}

reply.Encoding = args.Encoding

var result any
if args.Encoding == formatting.JSON {
reply.Tx = tx
return tx.Unsigned.Visit(&txInit{
err = tx.Unsigned.Visit(&txInit{
tx: tx,
ctx: s.vm.ctx,
typeToFxIndex: s.vm.typeToFxIndex,
fxs: s.vm.fxs,
})
result = tx
} else {
result, err = formatting.Encode(args.Encoding, tx.Bytes())
}

reply.Tx, err = formatting.Encode(args.Encoding, tx.Bytes())
if err != nil {
return fmt.Errorf("couldn't encode tx as string: %w", err)
return err
}
return nil

reply.Tx, err = stdjson.Marshal(result)
return err
}

// GetUTXOs gets all utxos for passed in addresses
Expand Down
57 changes: 26 additions & 31 deletions vms/avm/service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -481,9 +481,14 @@ func TestServiceGetTx(t *testing.T) {

reply := api.GetTxReply{}
require.NoError(env.service.GetTx(nil, &api.GetTxArgs{
TxID: txID,
TxID: txID,
Encoding: formatting.Hex,
}, &reply))
txBytes, err := formatting.Decode(reply.Encoding, reply.Tx.(string))

var txStr string
require.NoError(stdjson.Unmarshal(reply.Tx, &txStr))

txBytes, err := formatting.Decode(reply.Encoding, txStr)
require.NoError(err)
require.Equal(env.genesisTx.Bytes(), txBytes)
}
Expand All @@ -507,9 +512,7 @@ func TestServiceGetTxJSON_BaseTx(t *testing.T) {
}, &reply))

require.Equal(reply.Encoding, formatting.JSON)
jsonTxBytes, err := stdjson.Marshal(reply.Tx)
require.NoError(err)
jsonString := string(jsonTxBytes)
jsonString := string(reply.Tx)
require.Contains(jsonString, `"memo":"0x0102030405060708"`)
require.Contains(jsonString, `"inputs":[{"txID":"2XGxUr7VF7j1iwUp2aiGe4b6Ue2yyNghNS1SuNTNmZ77dPpXFZ","outputIndex":2,"assetID":"2XGxUr7VF7j1iwUp2aiGe4b6Ue2yyNghNS1SuNTNmZ77dPpXFZ","fxID":"spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ","input":{"amount":50000,"signatureIndices":[0]}}]`)
require.Contains(jsonString, `"outputs":[{"assetID":"2XGxUr7VF7j1iwUp2aiGe4b6Ue2yyNghNS1SuNTNmZ77dPpXFZ","fxID":"spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ","output":{"addresses":["X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e"],"amount":49000,"locktime":0,"threshold":1}}]`)
Expand All @@ -534,9 +537,7 @@ func TestServiceGetTxJSON_ExportTx(t *testing.T) {
}, &reply))

require.Equal(reply.Encoding, formatting.JSON)
jsonTxBytes, err := stdjson.Marshal(reply.Tx)
require.NoError(err)
jsonString := string(jsonTxBytes)
jsonString := string(reply.Tx)
require.Contains(jsonString, `"inputs":[{"txID":"2XGxUr7VF7j1iwUp2aiGe4b6Ue2yyNghNS1SuNTNmZ77dPpXFZ","outputIndex":2,"assetID":"2XGxUr7VF7j1iwUp2aiGe4b6Ue2yyNghNS1SuNTNmZ77dPpXFZ","fxID":"spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ","input":{"amount":50000,"signatureIndices":[0]}}]`)
require.Contains(jsonString, `"exportedOutputs":[{"assetID":"2XGxUr7VF7j1iwUp2aiGe4b6Ue2yyNghNS1SuNTNmZ77dPpXFZ","fxID":"spdxUxVJQbX85MGxMHbKw1sHxMnSqJ3QBzDyDYEP3h6TLuxqQ","output":{"addresses":["X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e"],"amount":49000,"locktime":0,"threshold":1}}]}`)
}
Expand Down Expand Up @@ -566,9 +567,7 @@ func TestServiceGetTxJSON_CreateAssetTx(t *testing.T) {
}, &reply))

require.Equal(reply.Encoding, formatting.JSON)
jsonTxBytes, err := stdjson.Marshal(reply.Tx)
require.NoError(err)
jsonString := string(jsonTxBytes)
jsonString := string(reply.Tx)

// contains the address in the right format
require.Contains(jsonString, `"outputs":[{"addresses":["X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e"],"groupID":1,"locktime":0,"threshold":1},{"addresses":["X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e"],"groupID":2,"locktime":0,"threshold":1}]}`)
Expand Down Expand Up @@ -605,9 +604,7 @@ func TestServiceGetTxJSON_OperationTxWithNftxMintOp(t *testing.T) {
}, &reply))

require.Equal(reply.Encoding, formatting.JSON)
jsonTxBytes, err := stdjson.Marshal(reply.Tx)
require.NoError(err)
jsonString := string(jsonTxBytes)
jsonString := string(reply.Tx)
// assert memo and payload are in hex
require.Contains(jsonString, `"memo":"0x"`)
require.Contains(jsonString, `"payload":"0x68656c6c6f"`)
Expand Down Expand Up @@ -651,9 +648,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleNftxMintOp(t *testing.T) {
}, &reply))

require.Equal(reply.Encoding, formatting.JSON)
jsonTxBytes, err := stdjson.Marshal(reply.Tx)
require.NoError(err)
jsonString := string(jsonTxBytes)
jsonString := string(reply.Tx)

// contains the address in the right format
require.Contains(jsonString, `"outputs":[{"addresses":["X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e"]`)
Expand Down Expand Up @@ -693,9 +688,7 @@ func TestServiceGetTxJSON_OperationTxWithSecpMintOp(t *testing.T) {
}, &reply))

require.Equal(reply.Encoding, formatting.JSON)
jsonTxBytes, err := stdjson.Marshal(reply.Tx)
require.NoError(err)
jsonString := string(jsonTxBytes)
jsonString := string(reply.Tx)

// ensure memo is in hex
require.Contains(jsonString, `"memo":"0x"`)
Expand Down Expand Up @@ -741,9 +734,7 @@ func TestServiceGetTxJSON_OperationTxWithMultipleSecpMintOp(t *testing.T) {
}, &reply))

require.Equal(reply.Encoding, formatting.JSON)
jsonTxBytes, err := stdjson.Marshal(reply.Tx)
require.NoError(err)
jsonString := string(jsonTxBytes)
jsonString := string(reply.Tx)

// contains the address in the right format
require.Contains(jsonString, `"mintOutput":{"addresses":["X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e"]`)
Expand Down Expand Up @@ -784,9 +775,7 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOp(t *testing.T) {
}, &reply))

require.Equal(reply.Encoding, formatting.JSON)
jsonTxBytes, err := stdjson.Marshal(reply.Tx)
require.NoError(err)
jsonString := string(jsonTxBytes)
jsonString := string(reply.Tx)

// ensure memo is in hex
require.Contains(jsonString, `"memo":"0x"`)
Expand Down Expand Up @@ -831,9 +820,7 @@ func TestServiceGetTxJSON_OperationTxWithPropertyFxMintOpMultiple(t *testing.T)
}, &reply))

require.Equal(reply.Encoding, formatting.JSON)
jsonTxBytes, err := stdjson.Marshal(reply.Tx)
require.NoError(err)
jsonString := string(jsonTxBytes)
jsonString := string(reply.Tx)

// contains the address in the right format
require.Contains(jsonString, `"mintOutput":{"addresses":["X-testing1lnk637g0edwnqc2tn8tel39652fswa3xk4r65e"]`)
Expand Down Expand Up @@ -2111,7 +2098,11 @@ func TestServiceGetBlock(t *testing.T) {
return
}
require.Equal(tt.encoding, reply.Encoding)
require.Equal(expected, reply.Block)

expectedJSON, err := stdjson.Marshal(expected)
require.NoError(err)

require.Equal(stdjson.RawMessage(expectedJSON), reply.Block)
})
}
}
Expand Down Expand Up @@ -2313,7 +2304,11 @@ func TestServiceGetBlockByHeight(t *testing.T) {
return
}
require.Equal(tt.encoding, reply.Encoding)
require.Equal(expected, reply.Block)

expectedJSON, err := stdjson.Marshal(expected)
require.NoError(err)

require.Equal(stdjson.RawMessage(expectedJSON), reply.Block)
})
}
}
Expand Down
52 changes: 27 additions & 25 deletions vms/platformvm/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2142,7 +2142,6 @@ func (s *Service) IssueTx(_ *http.Request, args *api.FormattedTx, response *api.
return nil
}

// GetTx gets a tx
func (s *Service) GetTx(_ *http.Request, args *api.GetTxArgs, response *api.GetTxReply) error {
s.vm.ctx.Log.Debug("API called",
zap.String("service", "platform"),
Expand All @@ -2153,20 +2152,21 @@ func (s *Service) GetTx(_ *http.Request, args *api.GetTxArgs, response *api.GetT
if err != nil {
return fmt.Errorf("couldn't get tx: %w", err)
}
txBytes := tx.Bytes()
response.Encoding = args.Encoding

var result any
if args.Encoding == formatting.JSON {
tx.Unsigned.InitCtx(s.vm.ctx)
response.Tx = tx
return nil
result = tx
} else {
result, err = formatting.Encode(args.Encoding, tx.Bytes())
if err != nil {
return fmt.Errorf("couldn't encode tx as %s: %w", args.Encoding, err)
}
}

response.Tx, err = formatting.Encode(args.Encoding, txBytes)
if err != nil {
return fmt.Errorf("couldn't encode tx as %s: %w", args.Encoding, err)
}
return nil
response.Tx, err = stdjson.Marshal(result)
return err
}

type GetTxStatusArgs struct {
Expand Down Expand Up @@ -2638,18 +2638,19 @@ func (s *Service) GetBlock(_ *http.Request, args *api.GetBlockArgs, response *ap
}
response.Encoding = args.Encoding

var result any
if args.Encoding == formatting.JSON {
block.InitCtx(s.vm.ctx)
response.Block = block
return nil
}

response.Block, err = formatting.Encode(args.Encoding, block.Bytes())
if err != nil {
return fmt.Errorf("couldn't encode block %s as %s: %w", args.BlockID, args.Encoding, err)
result = block
} else {
result, err = formatting.Encode(args.Encoding, block.Bytes())
if err != nil {
return fmt.Errorf("couldn't encode block %s as %s: %w", args.BlockID, args.Encoding, err)
}
}

return nil
response.Block, err = stdjson.Marshal(result)
return err
}

// GetBlockByHeight returns the block at the given height.
Expand All @@ -2676,18 +2677,19 @@ func (s *Service) GetBlockByHeight(_ *http.Request, args *api.GetBlockByHeightAr
}
response.Encoding = args.Encoding

var result any
if args.Encoding == formatting.JSON {
block.InitCtx(s.vm.ctx)
response.Block = block
return nil
}

response.Block, err = formatting.Encode(args.Encoding, block.Bytes())
if err != nil {
return fmt.Errorf("couldn't encode block %s as %s: %w", blockID, args.Encoding, err)
result = block
} else {
result, err = formatting.Encode(args.Encoding, block.Bytes())
if err != nil {
return fmt.Errorf("couldn't encode block %s as %s: %w", blockID, args.Encoding, err)
}
}

return nil
response.Block, err = stdjson.Marshal(result)
return err
}

func (s *Service) getAPIUptime(staker *state.Staker) (*json.Float32, error) {
Expand Down
Loading
Loading