Skip to content

Commit

Permalink
Fix potential JAID collisions in multi chain env
Browse files Browse the repository at this point in the history
This fixes some rest api responses getting omitted when the JAID was same across multiple chains
  • Loading branch information
ilija42 committed Jan 22, 2024
1 parent 958e2c6 commit 2f644d3
Show file tree
Hide file tree
Showing 28 changed files with 284 additions and 34 deletions.
2 changes: 1 addition & 1 deletion core/cmd/cosmos_node_commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ func TestShell_IndexCosmosNodes(t *testing.T) {
nodes := *r.Renders[0].(*cmd.CosmosNodePresenters)
require.Len(t, nodes, 1)
n := nodes[0]
assert.Equal(t, cltest.FormatWithPrefixedChainID(*node.Name, chainID), n.ID)
assert.Equal(t, chainID, n.ChainID)
assert.Equal(t, *node.Name, n.ID)
assert.Equal(t, *node.Name, n.Name)
wantConfig, err := toml.Marshal(node)
require.NoError(t, err)
Expand Down
4 changes: 2 additions & 2 deletions core/cmd/evm_node_commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ func TestShell_IndexEVMNodes(t *testing.T) {
n1 := nodes[0]
n2 := nodes[1]
assert.Equal(t, chainID.String(), n1.ChainID)
assert.Equal(t, *node1.Name, n1.ID)
assert.Equal(t, cltest.FormatWithPrefixedChainID(*node1.Name, chainID.String()), n1.ID)
assert.Equal(t, *node1.Name, n1.Name)
wantConfig, err := toml.Marshal(node1)
require.NoError(t, err)
assert.Equal(t, string(wantConfig), n1.Config)
assert.Equal(t, chainID.String(), n2.ChainID)
assert.Equal(t, *node2.Name, n2.ID)
assert.Equal(t, cltest.FormatWithPrefixedChainID(*node2.Name, chainID.String()), n2.ID)
assert.Equal(t, *node2.Name, n2.Name)
wantConfig2, err := toml.Marshal(node2)
require.NoError(t, err)
Expand Down
2 changes: 1 addition & 1 deletion core/cmd/ocr2_keys_commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func TestOCR2KeyBundlePresenter_RenderTable(t *testing.T) {
pubKeyConfig := key.ConfigEncryptionPublicKey()
pubKey := key.OffchainPublicKey()
p := cmd.OCR2KeyBundlePresenter{
JAID: cmd.JAID{ID: bundleID},
JAID: cmd.NewJAID(bundleID),
OCR2KeysBundleResource: presenters.OCR2KeysBundleResource{
JAID: presenters.NewJAID(key.ID()),
ChainType: "evm",
Expand Down
7 changes: 7 additions & 0 deletions core/cmd/presenters.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package cmd

import "fmt"

// JAID represents a JSON API ID.
//
// It implements the api2go MarshalIdentifier and UnmarshalIdentitier interface.
Expand Down Expand Up @@ -33,3 +35,8 @@ func (jaid *JAID) SetID(value string) error {

return nil
}

// GetWithPrefixedChainID returns JAID formatted with chainID, this is done to prevent cross chain ID collision.
func (jaid JAID) GetWithPrefixedChainID(chainID string) JAID {
return JAID{ID: fmt.Sprintf("%s/%s", chainID, jaid.ID)}
}
4 changes: 2 additions & 2 deletions core/cmd/solana_node_commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ func TestShell_IndexSolanaNodes(t *testing.T) {
n1 := nodes[0]
n2 := nodes[1]
assert.Equal(t, id, n1.ChainID)
assert.Equal(t, *node1.Name, n1.ID)
assert.Equal(t, cltest.FormatWithPrefixedChainID(*node1.Name, id), n1.ID)
assert.Equal(t, *node1.Name, n1.Name)
wantConfig, err := toml.Marshal(node1)
require.NoError(t, err)
assert.Equal(t, string(wantConfig), n1.Config)
assert.Equal(t, id, n2.ChainID)
assert.Equal(t, *node2.Name, n2.ID)
assert.Equal(t, cltest.FormatWithPrefixedChainID(*node2.Name, id), n2.ID)
assert.Equal(t, *node2.Name, n2.Name)
wantConfig2, err := toml.Marshal(node2)
require.NoError(t, err)
Expand Down
4 changes: 2 additions & 2 deletions core/cmd/starknet_node_commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ func TestShell_IndexStarkNetNodes(t *testing.T) {
n1 := nodes[0]
n2 := nodes[1]
assert.Equal(t, id, n1.ChainID)
assert.Equal(t, *node1.Name, n1.ID)
assert.Equal(t, cltest.FormatWithPrefixedChainID(*node1.Name, id), n1.ID)
assert.Equal(t, *node1.Name, n1.Name)
wantConfig, err := toml.Marshal(node1)
require.NoError(t, err)
assert.Equal(t, string(wantConfig), n1.Config)
assert.Equal(t, id, n2.ChainID)
assert.Equal(t, *node2.Name, n2.ID)
assert.Equal(t, cltest.FormatWithPrefixedChainID(*node2.Name, id), n2.ID)
assert.Equal(t, *node2.Name, n2.Name)
wantConfig2, err := toml.Marshal(node2)
require.NoError(t, err)
Expand Down
4 changes: 4 additions & 0 deletions core/internal/cltest/cltest.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,10 @@ func MustRandomBytes(t *testing.T, l int) (b []byte) {
return b
}

func FormatWithPrefixedChainID(id, chainID string) string {
return fmt.Sprintf("%s/%s", chainID, id)
}

type JobPipelineV2TestHelper struct {
Prm pipeline.ORM
Jrm job.ORM
Expand Down
2 changes: 1 addition & 1 deletion core/web/eth_keys_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ func (ekc *ETHKeysController) Chain(c *gin.Context) {
jsonAPIError(c, http.StatusBadRequest, errors.Errorf("invalid address: %s, must be hex address", keyID))
return
}
address := common.HexToAddress((keyID))
address := common.HexToAddress(keyID)

cid := c.Query("evmChainID")
chain, ok := ekc.getChain(c, cid)
Expand Down
15 changes: 10 additions & 5 deletions core/web/eth_keys_controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,8 @@ func TestETHKeysController_ChainSuccess_UpdateNonce(t *testing.T) {
err := cltest.ParseJSONAPIResponse(t, resp, &updatedKey)
assert.NoError(t, err)

assert.Equal(t, key.ID(), updatedKey.ID)
assert.Equal(t, cltest.FormatWithPrefixedChainID(key.Address.String(), cltest.FixtureChainID.String()), updatedKey.ID)
assert.Equal(t, key.Address.String(), updatedKey.Address)
assert.Equal(t, cltest.FixtureChainID.String(), updatedKey.EVMChainID.String())
assert.Equal(t, false, updatedKey.Disabled)
}
Expand Down Expand Up @@ -328,7 +329,8 @@ func TestETHKeysController_ChainSuccess_Disable(t *testing.T) {
err := cltest.ParseJSONAPIResponse(t, resp, &updatedKey)
assert.NoError(t, err)

assert.Equal(t, key.ID(), updatedKey.ID)
assert.Equal(t, cltest.FormatWithPrefixedChainID(key.Address.String(), updatedKey.EVMChainID.String()), updatedKey.ID)
assert.Equal(t, key.Address.String(), updatedKey.Address)
assert.Equal(t, cltest.FixtureChainID.String(), updatedKey.EVMChainID.String())
assert.Equal(t, true, updatedKey.Disabled)
}
Expand Down Expand Up @@ -371,7 +373,8 @@ func TestETHKeysController_ChainSuccess_Enable(t *testing.T) {
err := cltest.ParseJSONAPIResponse(t, resp, &updatedKey)
assert.NoError(t, err)

assert.Equal(t, key.ID(), updatedKey.ID)
assert.Equal(t, cltest.FormatWithPrefixedChainID(key.Address.String(), cltest.FixtureChainID.String()), updatedKey.ID)
assert.Equal(t, key.Address.String(), updatedKey.Address)
assert.Equal(t, cltest.FixtureChainID.String(), updatedKey.EVMChainID.String())
assert.Equal(t, false, updatedKey.Disabled)
}
Expand Down Expand Up @@ -436,7 +439,8 @@ func TestETHKeysController_ChainSuccess_ResetWithAbandon(t *testing.T) {
err = cltest.ParseJSONAPIResponse(t, resp, &updatedKey)
assert.NoError(t, err)

assert.Equal(t, key.ID(), updatedKey.ID)
assert.Equal(t, cltest.FormatWithPrefixedChainID(key.Address.String(), cltest.FixtureChainID.String()), updatedKey.ID)
assert.Equal(t, key.Address.String(), updatedKey.Address)
assert.Equal(t, cltest.FixtureChainID.String(), updatedKey.EVMChainID.String())
assert.Equal(t, false, updatedKey.Disabled)

Expand Down Expand Up @@ -663,7 +667,8 @@ func TestETHKeysController_DeleteSuccess(t *testing.T) {
err := cltest.ParseJSONAPIResponse(t, resp, &deletedKey)
assert.NoError(t, err)

assert.Equal(t, key0.ID(), deletedKey.ID)
assert.Equal(t, cltest.FormatWithPrefixedChainID(key0.Address.String(), cltest.FixtureChainID.String()), deletedKey.ID)
assert.Equal(t, key0.Address.String(), deletedKey.Address)
assert.Equal(t, cltest.FixtureChainID.String(), deletedKey.EVMChainID.String())
assert.Equal(t, false, deletedKey.Disabled)

Expand Down
69 changes: 69 additions & 0 deletions core/web/presenters/chain_msg_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package presenters

import (
"fmt"
"testing"

"github.com/manyminds/api2go/jsonapi"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/smartcontractkit/chainlink/v2/core/internal/testutils/cosmostest"
"github.com/smartcontractkit/chainlink/v2/core/internal/testutils/solanatest"
)

func TestSolanaMessageResource(t *testing.T) {
id := "1"
chainID := solanatest.RandomChainID()
r := NewSolanaMsgResource(id, chainID)
assert.Equal(t, chainID, r.ChainID)

b, err := jsonapi.Marshal(r)
require.NoError(t, err)

expected := fmt.Sprintf(`
{
"data":{
"type":"solana_messages",
"id":"%s/%s",
"attributes":{
"ChainID":"%s",
"from":"",
"to":"",
"amount":0
}
}
}
`, chainID, id, chainID)

assert.JSONEq(t, expected, string(b))
}

func TestCosmosMessageResource(t *testing.T) {
id := "1"
chainID := cosmostest.RandomChainID()
contractID := "cosmos1p3ucd3ptpw902fluyjzkq3fflq4btddac9sa3s"
r := NewCosmosMsgResource(id, chainID, contractID)
assert.Equal(t, chainID, r.ChainID)
assert.Equal(t, contractID, r.ContractID)

b, err := jsonapi.Marshal(r)
require.NoError(t, err)

expected := fmt.Sprintf(`
{
"data":{
"type":"cosmos_messages",
"id":"%s/%s",
"attributes":{
"ChainID":"%s",
"ContractID":"%s",
"State":"",
"TxHash":null
}
}
}
`, chainID, id, chainID, contractID)

assert.JSONEq(t, expected, string(b))
}
2 changes: 1 addition & 1 deletion core/web/presenters/cosmos_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func (r CosmosNodeResource) GetName() string {
// NewCosmosNodeResource returns a new CosmosNodeResource for node.
func NewCosmosNodeResource(node types.NodeStatus) CosmosNodeResource {
return CosmosNodeResource{NodeResource{
JAID: NewJAID(node.Name),
JAID: NewJAID(node.Name).GetWithPrefixedChainID(node.ChainID),
ChainID: node.ChainID,
Name: node.Name,
State: node.State,
Expand Down
2 changes: 1 addition & 1 deletion core/web/presenters/cosmos_msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func (CosmosMsgResource) GetName() string {
// NewCosmosMsgResource returns a new partial CosmosMsgResource.
func NewCosmosMsgResource(id string, chainID string, contractID string) CosmosMsgResource {
return CosmosMsgResource{
JAID: NewJAID(id),
JAID: NewJAID(id).GetWithPrefixedChainID(chainID),
ChainID: chainID,
ContractID: contractID,
}
Expand Down
2 changes: 1 addition & 1 deletion core/web/presenters/eth_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ type NewETHKeyOption func(*ETHKeyResource)
// Use the functional options to inject the ETH and LINK balances
func NewETHKeyResource(k ethkey.KeyV2, state ethkey.State, opts ...NewETHKeyOption) *ETHKeyResource {
r := &ETHKeyResource{
JAID: NewJAID(k.Address.Hex()),
JAID: NewJAID(k.Address.Hex()).GetWithPrefixedChainID(state.EVMChainID.String()),
EVMChainID: state.EVMChainID,
Address: k.Address.Hex(),
EthBalance: nil,
Expand Down
4 changes: 2 additions & 2 deletions core/web/presenters/eth_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func TestETHKeyResource(t *testing.T) {
{
"data":{
"type":"eTHKeys",
"id":"%s",
"id":"42/%s",
"attributes":{
"address":"%s",
"evmChainID":"42",
Expand Down Expand Up @@ -84,7 +84,7 @@ func TestETHKeyResource(t *testing.T) {
{
"data": {
"type":"eTHKeys",
"id":"%s",
"id":"42/%s",
"attributes":{
"address":"%s",
"evmChainID":"42",
Expand Down
1 change: 1 addition & 0 deletions core/web/presenters/eth_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ func NewEthTxResourceFromAttempt(txa txmgr.TxAttempt) EthTxResource {

if txa.Tx.ChainID != nil {
r.EVMChainID = *big.New(txa.Tx.ChainID)
r.JAID = r.JAID.GetWithPrefixedChainID(txa.Tx.ChainID.String())
}

if tx.Sequence != nil {
Expand Down
8 changes: 5 additions & 3 deletions core/web/presenters/eth_tx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ import (
func TestEthTxResource(t *testing.T) {
t.Parallel()

chainID := big.NewInt(54321)
tx := txmgr.Tx{
ID: 1,
EncodedPayload: []byte(`{"data": "is wilding out"}`),
FromAddress: common.HexToAddress("0x1"),
ToAddress: common.HexToAddress("0x2"),
FeeLimit: uint32(5000),
ChainID: chainID,
State: txmgrcommon.TxConfirmed,
Value: big.Int(assets.NewEthValue(1)),
}
Expand All @@ -52,7 +54,7 @@ func TestEthTxResource(t *testing.T) {
"sentAt": "",
"to": "0x0000000000000000000000000000000000000002",
"value": "0.000000000000000001",
"evmChainID": "0"
"evmChainID": "54321"
}
}
}
Expand Down Expand Up @@ -85,7 +87,7 @@ func TestEthTxResource(t *testing.T) {
{
"data": {
"type": "evm_transactions",
"id": "0x0000000000000000000000000000000000000000000000000000000000010203",
"id": "54321/0x0000000000000000000000000000000000000000000000000000000000010203",
"attributes": {
"state": "confirmed",
"data": "0x7b2264617461223a202269732077696c64696e67206f7574227d",
Expand All @@ -98,7 +100,7 @@ func TestEthTxResource(t *testing.T) {
"sentAt": "300",
"to": "0x0000000000000000000000000000000000000002",
"value": "0.000000000000000001",
"evmChainID": "0"
"evmChainID": "54321"
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion core/web/presenters/evm_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (r EVMNodeResource) GetName() string {
// NewEVMNodeResource returns a new EVMNodeResource for node.
func NewEVMNodeResource(node types.NodeStatus) EVMNodeResource {
return EVMNodeResource{NodeResource{
JAID: NewJAID(node.Name),
JAID: NewJAID(node.Name).GetWithPrefixedChainID(node.ChainID),
ChainID: node.ChainID,
Name: node.Name,
State: node.State,
Expand Down
64 changes: 64 additions & 0 deletions core/web/presenters/evm_forwarder_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package presenters

import (
"fmt"
"strings"
"testing"
"time"

"github.com/manyminds/api2go/jsonapi"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils"
"github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils/big"
)

func TestEVMForwarderResource(t *testing.T) {
var (
ID = int64(1)
address = utils.RandomAddress()
chainID = *big.NewI(4)
createdAt = time.Now()
updatedAt = time.Now().Add(time.Second)
)
fwd := forwarders.Forwarder{
ID: ID,
Address: address,
EVMChainID: chainID,
CreatedAt: createdAt,
UpdatedAt: updatedAt,
}

r := NewEVMForwarderResource(fwd)
assert.Equal(t, fmt.Sprint(ID), r.ID)
assert.Equal(t, address, r.Address)
assert.Equal(t, chainID, r.EVMChainID)
assert.Equal(t, createdAt, r.CreatedAt)
assert.Equal(t, updatedAt, r.UpdatedAt)

b, err := jsonapi.Marshal(r)
require.NoError(t, err)

createdAtMarshalled, err := createdAt.MarshalText()
require.NoError(t, err)
updatedAtMarshalled, err := updatedAt.MarshalText()
require.NoError(t, err)

expected := fmt.Sprintf(`
{
"data":{
"type":"evm_forwarder",
"id":"%d",
"attributes":{
"address":"%s",
"evmChainId":"%s",
"createdAt":"%s",
"updatedAt":"%s"
}
}
}
`, ID, strings.ToLower(address.String()), chainID.String(), string(createdAtMarshalled), string(updatedAtMarshalled))
assert.JSONEq(t, expected, string(b))
}
Loading

0 comments on commit 2f644d3

Please sign in to comment.