Skip to content

Commit

Permalink
Marshal blocks and transactions inside API calls (#2153)
Browse files Browse the repository at this point in the history
  • Loading branch information
StephenButtolph committed Oct 11, 2023
1 parent 0ac1937 commit c50ea11
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 98 deletions.
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)
}
}

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)
}
}

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

0 comments on commit c50ea11

Please sign in to comment.