Skip to content

Commit

Permalink
Merge pull request #153 from kaleido-io/large-json-numbers
Browse files Browse the repository at this point in the history
Exploit new support in `firefly-signer` and `firefly-common` for large & scientific JSON numbers
  • Loading branch information
matthew1001 authored Sep 4, 2024
2 parents 6aff1e6 + 3d18e2f commit 102fac7
Show file tree
Hide file tree
Showing 6 changed files with 249 additions and 16 deletions.
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ toolchain go1.21.6

require (
github.com/hashicorp/golang-lru v1.0.2
github.com/hyperledger/firefly-common v1.4.8
github.com/hyperledger/firefly-signer v1.1.13
github.com/hyperledger/firefly-transaction-manager v1.3.15
github.com/hyperledger/firefly-common v1.4.9
github.com/hyperledger/firefly-signer v1.1.14
github.com/hyperledger/firefly-transaction-manager v1.3.16
github.com/sirupsen/logrus v1.9.3
github.com/spf13/cobra v1.8.0
github.com/stretchr/testify v1.8.4
Expand Down
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,12 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU=
github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/hyperledger/firefly-common v1.4.8 h1:0o1Qp1c5YzQo8nbnX+gAo9SVd2tR4Z9U2t8Y4zEzyaA=
github.com/hyperledger/firefly-common v1.4.8/go.mod h1:dXewcVMFNON2SvQ1UPvu64OWUt77+M3p8qy61lT1kE4=
github.com/hyperledger/firefly-signer v1.1.13 h1:eiHjc6HPRG8AzXUCUgm51qqX1I9BokiuiiqJ89XwK4M=
github.com/hyperledger/firefly-signer v1.1.13/go.mod h1:pK6kivzBFSue3zpJSQpH67VasnLLbwBJOBUNv0zHbRA=
github.com/hyperledger/firefly-transaction-manager v1.3.15 h1:IyWIId+uytqjIRMxROk5OqOcdHMzJFGFKpQQybiISOU=
github.com/hyperledger/firefly-transaction-manager v1.3.15/go.mod h1:N3BoHh8+dWG710oQKuNiXmJNEOBBeLTsQ8GpZ41vhog=
github.com/hyperledger/firefly-common v1.4.9 h1:PfPZ73FN8WUoPl8iF8ud00B8476+jmqXHHi94w0Krbc=
github.com/hyperledger/firefly-common v1.4.9/go.mod h1:dXewcVMFNON2SvQ1UPvu64OWUt77+M3p8qy61lT1kE4=
github.com/hyperledger/firefly-signer v1.1.14 h1:gSGwdBHTLPchGlmLOKk2Y2nawfMhlH2CDm2owt0lIUE=
github.com/hyperledger/firefly-signer v1.1.14/go.mod h1:Xj2PF6y8Ce26jX38ch0KasNnnZCSyzcwyLSv8NN+7JA=
github.com/hyperledger/firefly-transaction-manager v1.3.16 h1:rW6rptO4LcOeUYVOMTyvsfPcOzNLBpmBTj4T6n0/vpY=
github.com/hyperledger/firefly-transaction-manager v1.3.16/go.mod h1:UT4Cijjsz5AqiXa9H3GUiT2vm2Hq1wEgT0n/shsYZp0=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
Expand Down
2 changes: 1 addition & 1 deletion internal/ethereum/deploy_contract_prepare.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func (c *ethConnector) prepareDeployData(ctx context.Context, req *ffcapi.Contra
ethParams := make([]interface{}, len(req.Params))
for i, p := range req.Params {
if p != nil {
err := json.Unmarshal([]byte(*p), &ethParams[i])
err := p.Unmarshal(ctx, &ethParams[i])
if err != nil {
return nil, nil, i18n.NewError(ctx, msgs.MsgUnmarshalParamFail, i, err)
}
Expand Down
124 changes: 119 additions & 5 deletions internal/ethereum/deploy_contract_prepare_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package ethereum

import (
"encoding/json"
"strings"
"testing"

"github.com/hyperledger/firefly-common/pkg/fftypes"
Expand All @@ -39,19 +40,91 @@ const samplePrepareDeployTX = `{
"gas": 1000000,
"nonce": "111",
"value": "12345678901234567890123456789",
"contract": "0xfeedbeef",
"contract": "0xdeadbeef",
"definition": [{
"inputs": [
{
"internalType":" uint256",
"name": "x",
"type": "uint256"
}
},
{
"internalType":" address",
"name": "y",
"type": "address"
},
{
"internalType":" string",
"name": "z",
"type": "string"
}
],
"outputs":[],
"type":"constructor"
}],
"params": [ 4276993775 ]
"params": [ 4276993775, "0x5f906824E562B6a0F278D910D388728b833a43bB", "some-text" ]
}`

const samplePrepareDeployTXLargeInputParams = `{
"ffcapi": {
"version": "v1.0.0",
"id": "904F177C-C790-4B01-BDF4-F2B4E52E607E",
"type": "DeployContract"
},
"from": "0xb480F96c0a3d6E9e9a263e4665a39bFa6c4d01E8",
"to": "0xe1a078b9e2b145d0a7387f09277c6ae1d9470771",
"gas": 1000000,
"nonce": "111",
"value": "12345678901234567890123456789",
"contract": "0xdeadbeef",
"definition": [{
"inputs": [
{
"internalType":" uint256",
"name": "x",
"type": "uint256"
},
{
"internalType":" string",
"name": "y",
"type": "string"
}
],
"outputs":[],
"type":"constructor"
}],
"params": [ 10000000000000000000000001, "some-text" ]
}`

const samplePrepareDeployTXScientificNotation = `{
"ffcapi": {
"version": "v1.0.0",
"id": "904F177C-C790-4B01-BDF4-F2B4E52E607E",
"type": "DeployContract"
},
"from": "0xb480F96c0a3d6E9e9a263e4665a39bFa6c4d01E8",
"to": "0xe1a078b9e2b145d0a7387f09277c6ae1d9470771",
"gas": 1000000,
"nonce": "111",
"value": "12345678901234567890123456789",
"contract": "0xdeadbeef",
"definition": [{
"inputs": [
{
"internalType":" uint256",
"name": "x",
"type": "uint256"
},
{
"internalType":" string",
"name": "y",
"type": "string"
}
],
"outputs":[],
"type":"constructor"
}],
"params": [ 1.0000000000000000000000001e+25, "some-text" ]
}`

func TestDeployContractPrepareOkNoEstimate(t *testing.T) {
Expand All @@ -63,12 +136,53 @@ func TestDeployContractPrepareOkNoEstimate(t *testing.T) {
err := json.Unmarshal([]byte(samplePrepareDeployTX), &req)
assert.NoError(t, err)
res, reason, err := c.DeployContractPrepare(ctx, &req)

assert.NoError(t, err)
assert.Empty(t, reason)
assert.Equal(t, int64(1000000), res.Gas.Int64())

// Basic check that our input param 4276993775 is in the TX data
assert.True(t, strings.Contains(res.TransactionData, "feedbeef"))
// Basic check that our input param "some-text" is in the TX data
assert.True(t, strings.Contains(res.TransactionData, strings.ToLower("736f6d652d74657874")))
// Basic check that our input param address is in the TX data
assert.True(t, strings.Contains(res.TransactionData, strings.ToLower("5f906824E562B6a0F278D910D388728b833a43bB")))
}

func TestDeployContractPrepareOkLargeInputParam(t *testing.T) {

ctx, c, _, done := newTestConnector(t)
defer done()

var req ffcapi.ContractDeployPrepareRequest
err := json.Unmarshal([]byte(samplePrepareDeployTXLargeInputParams), &req)
assert.NoError(t, err)
res, reason, err := c.DeployContractPrepare(ctx, &req)
assert.NoError(t, err)
assert.Empty(t, reason)
assert.Equal(t, int64(1000000), res.Gas.Int64())

// Basic check that our input param 10000000000000000000000001 is in the TX data
assert.True(t, strings.Contains(res.TransactionData, "84595161401484a000001"))
// Basic check that our input param "some-text" is in the TX data
assert.True(t, strings.Contains(res.TransactionData, "736f6d652d74657874"))
}

func TestDeployContractPrepareOkScientificNotationParam(t *testing.T) {

ctx, c, _, done := newTestConnector(t)
defer done()

var req ffcapi.ContractDeployPrepareRequest
err := json.Unmarshal([]byte(samplePrepareDeployTXScientificNotation), &req)
assert.NoError(t, err)
res, reason, err := c.DeployContractPrepare(ctx, &req)
assert.NoError(t, err)
assert.Empty(t, reason)
assert.Equal(t, int64(1000000), res.Gas.Int64())
// Basic check that our input param 1.0000000000000000000000001e+25 is in the TX data
assert.True(t, strings.Contains(res.TransactionData, "84595161401484a000001"))
// Basic check that our input param "some-text" is in the TX data
assert.True(t, strings.Contains(res.TransactionData, "736f6d652d74657874"))
}

func TestDeployContractPrepareWithEstimateRevert(t *testing.T) {
Expand Down Expand Up @@ -209,7 +323,7 @@ func TestDeployContractPrepareBadParamType(t *testing.T) {

var req ffcapi.ContractDeployPrepareRequest
err := json.Unmarshal([]byte(samplePrepareDeployTX), &req)
req.Params = []*fftypes.JSONAny{fftypes.JSONAnyPtr(`"!wrong"`)}
req.Params = []*fftypes.JSONAny{fftypes.JSONAnyPtr(`"!wrong"`), fftypes.JSONAnyPtr(`"0x90eB678C3586103805a676d21721Cc6883a6c3AE"`), fftypes.JSONAnyPtr(`"helloworld"`)}
assert.NoError(t, err)
_, reason, err := c.DeployContractPrepare(ctx, &req)

Expand Down
2 changes: 1 addition & 1 deletion internal/ethereum/prepare_transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ func (c *ethConnector) prepareCallData(ctx context.Context, req *ffcapi.Transact
ethParams := make([]interface{}, len(req.Params))
for i, p := range req.Params {
if p != nil {
err := json.Unmarshal([]byte(*p), &ethParams[i])
err := p.Unmarshal(ctx, &ethParams[i])
if err != nil {
return nil, nil, i18n.NewError(ctx, msgs.MsgUnmarshalParamFail, i, err)
}
Expand Down
119 changes: 119 additions & 0 deletions internal/ethereum/prepare_transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package ethereum
import (
"context"
"encoding/json"
"strings"
"testing"

"github.com/hyperledger/firefly-common/pkg/fftypes"
Expand Down Expand Up @@ -155,6 +156,70 @@ const samplePrepareTXBadErrors = `{
"errors": [false]
}`

const samplePrepareTXHugeNumberParam = `{
"ffcapi": {
"version": "v1.0.0",
"id": "904F177C-C790-4B01-BDF4-F2B4E52E607E",
"type": "prepare_transaction"
},
"from": "0xb480F96c0a3d6E9e9a263e4665a39bFa6c4d01E8",
"to": "0xe1a078b9e2b145d0a7387f09277c6ae1d9470771",
"nonce": "222",
"method": {
"inputs": [],
"name":"do",
"outputs":[],
"stateMutability":"nonpayable",
"type":"function"
},
"method": {
"inputs": [
{
"internalType":" uint256",
"name": "x",
"type": "uint256"
}
],
"name":"set",
"outputs":[],
"stateMutability":"nonpayable",
"type":"function"
},
"params": [ 10000000000000000000000001 ]
}`

const samplePrepareTXScientificNumberParam = `{
"ffcapi": {
"version": "v1.0.0",
"id": "904F177C-C790-4B01-BDF4-F2B4E52E607E",
"type": "prepare_transaction"
},
"from": "0xb480F96c0a3d6E9e9a263e4665a39bFa6c4d01E8",
"to": "0xe1a078b9e2b145d0a7387f09277c6ae1d9470771",
"nonce": "222",
"method": {
"inputs": [],
"name":"do",
"outputs":[],
"stateMutability":"nonpayable",
"type":"function"
},
"method": {
"inputs": [
{
"internalType":" uint256",
"name": "x",
"type": "uint256"
}
],
"name":"set",
"outputs":[],
"stateMutability":"nonpayable",
"type":"function"
},
"params": [ 1.0000000000000000000000002e+25 ]
}`

func TestPrepareTransactionOkNoEstimate(t *testing.T) {

ctx, c, _, done := newTestConnector(t)
Expand All @@ -172,6 +237,60 @@ func TestPrepareTransactionOkNoEstimate(t *testing.T) {

}

func TestPrepareTransactionOkHugeNumberParam(t *testing.T) {

ctx, c, mRPC, done := newTestConnector(t)
defer done()

mRPC.On("CallRPC", mock.Anything, mock.Anything, "eth_estimateGas",
mock.MatchedBy(func(tx *ethsigner.Transaction) bool {
assert.Equal(t, "0x60fe47b1000000000000000000000000000000000000000000084595161401484a000001", tx.Data.String())
return true
})).
Return(nil).
Run(func(args mock.Arguments) {
args[1].(*ethtypes.HexInteger).BigInt().SetString("12345", 10)
})

var req ffcapi.TransactionPrepareRequest
err := json.Unmarshal([]byte(samplePrepareTXHugeNumberParam), &req)
assert.NoError(t, err)
res, reason, err := c.TransactionPrepare(ctx, &req)

assert.NoError(t, err)
assert.Empty(t, reason)

// Basic check that our input param 10000000000000000000000001 is in the TX data
assert.True(t, strings.Contains(res.TransactionData, "84595161401484a000001"))
}

func TestPrepareTransactionOkScientificNumberParam(t *testing.T) {

ctx, c, mRPC, done := newTestConnector(t)
defer done()

mRPC.On("CallRPC", mock.Anything, mock.Anything, "eth_estimateGas",
mock.MatchedBy(func(tx *ethsigner.Transaction) bool {
assert.Equal(t, "0x60fe47b1000000000000000000000000000000000000000000084595161401484a000002", tx.Data.String())
return true
})).
Return(nil).
Run(func(args mock.Arguments) {
args[1].(*ethtypes.HexInteger).BigInt().SetString("12345", 10)
})

var req ffcapi.TransactionPrepareRequest
err := json.Unmarshal([]byte(samplePrepareTXScientificNumberParam), &req)
assert.NoError(t, err)
res, reason, err := c.TransactionPrepare(ctx, &req)

assert.NoError(t, err)
assert.Empty(t, reason)

// Basic check that our input param 1.0000000000000000000000002e+25 is in the TX data
assert.True(t, strings.Contains(res.TransactionData, "84595161401484a000002"))
}

func TestPrepareTransactionWithEstimate(t *testing.T) {

ctx, c, mRPC, done := newTestConnector(t)
Expand Down

0 comments on commit 102fac7

Please sign in to comment.