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

Solana changeset support for e2e testing #15892

Merged
merged 216 commits into from
Jan 29, 2025
Merged

Conversation

yashnevatia
Copy link
Contributor

Requires

Supports

Copy link
Contributor

@makramkd makramkd left a comment

Choose a reason for hiding this comment

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

Partial review, haven't gone thru the solana directory yet.

deployment/ccip/changeset/internal/deploy_home_chain.go Outdated Show resolved Hide resolved
deployment/ccip/changeset/internal/deploy_home_chain.go Outdated Show resolved Hide resolved
deployment/ccip/changeset/internal/deploy_home_chain.go Outdated Show resolved Hide resolved
deployment/ccip/changeset/internal/deploy_home_chain.go Outdated Show resolved Hide resolved
var signer [20]uint8
copy(signer[:], node.SignerKey[:20])
signerAddresses = append(signerAddresses, signer)
transmitterAddresses = append(transmitterAddresses, solana.MustPublicKeyFromBase58(string(node.TransmitterKey)))
Copy link
Contributor

Choose a reason for hiding this comment

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

Don't think this is correct. string(node.TransmitterKey) doesn't base58 encode the bytes, it tries to convert the byte-slice into a string by interpreting the bytes as UTF-8 encoded characters. You should encode to base58 first and then do the decoding.

Also MustPublicKeyFromBase58 looks like it'll panic - rather we should just catch and error gracefully.

Copy link
Contributor

Choose a reason for hiding this comment

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

So it took me a bit to remember why we did this, but it does work and the tests do pass with this. The reason is because of the changes in delegate.go https://github.com/smartcontractkit/chainlink/pull/15892/files#diff-5a6126b485353ba3fd28b03f608fa8bd9b1c8ae744845f019eff1fdbc9a6775cR278

Calling String() on a solana key actually base58 encodes the key, so doing a string cast and decode to base58 does work.

We will add the error check rather than the must though to avoid the panic.

Copy link
Contributor

Choose a reason for hiding this comment

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

That code you linked is completely unrelated to this code right here. Can you link what test you're referring to? node.TransmitterKey is just []byte so there is no Solana stringer going on here, as far as I can tell.

Copy link
Contributor

Choose a reason for hiding this comment

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

Is it unrelated? The transmitter key should be encoded in the delegate and decoded here, no? That appears to be what's happening here.

The test that invokes this line is TestDeployCCIPContracts (in the solana folder) -> DoDeployCCIPContracts -> NewMemoryEnvironment -> NewEnvironmentWithJobsAndContracts -> AddCCIPContractsToEnvironment -> SetOCR3ConfigSolana

Copy link
Contributor

Choose a reason for hiding this comment

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

There's no common exec context b/w the code in the delegate (run in the CL node ctx) and the code here. So there is no encoding in the delegate and then decoding here, there's simply no relationship / call stack of that kind. Nowadays we use JD to fetch a nops' solana OCR keys and use those keys to create the proper OCR config. That delegate is only run when the job on the CL node is created (also by JD).

Also, that kind of test doesn't test that this decoding is working as expected, because the string([]byte) doesn't actually return a base58 encoded string. Here's a test that fails pretty often with the msg "decode: high-bit set on invalid digit":

func TestDecodeBase58(t *testing.T) {
	transmitterKeyBytes := utils.RandomBytes32()
	key, err := solana.PublicKeyFromBase58(string(transmitterKeyBytes[:20]))
	require.NoError(t, err)

	require.Equal(t, transmitterKeyBytes, key[:])
}

To properly do this you have to encode the transmitterKeyBytes as base58 first then decode it, or just load the solana public key from the bytes directly

func TestDecodeBase58(t *testing.T) {
	transmitterKeyBytes := utils.RandomBytes32()
	_, err := solana.PublicKeyFromBase58(string(transmitterKeyBytes[:])) // no base58 encode
	require.Error(t, err)

	keyFromBase58, err := solana.PublicKeyFromBase58(base58.Encode(transmitterKeyBytes[:]))
	require.NoError(t, err)
	require.Equal(t, keyFromBase58.Bytes(), transmitterKeyBytes[:])

	keyFromBytes := solana.PublicKeyFromBytes(transmitterKeyBytes[:])
	require.Equal(t, keyFromBytes.Bytes(), transmitterKeyBytes[:])
}

Copy link
Contributor

Choose a reason for hiding this comment

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

We took this offline, but the base58 encoding is happening when we serialize the transmitter key

transmitters[chain] = transmitter.ID()

Under the covers it calls

return base58.Encode(key.pubKey)
which base58 encodes.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah we should have a follow up ticket here where, in order to maintain consistence within the OCRConfig itself (both router address + transmitter addresses represented as 32 byte arrays vs. base58 encoded - right now it seems like router is just 32 bytes but transmitters are base58 encoded addresses as bytes)

// in state.GetOffRamp(..)
offRampAddress = s.SolChains[chainSelector].Router.Bytes()

Copy link
Contributor

Choose a reason for hiding this comment

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

Added a ticket and comment in the code https://smartcontract-it.atlassian.net/browse/NONEVM-1254

@@ -456,16 +451,14 @@ func (p SetCandidatePluginInfo) Validate(state CCIPOnChainState, homeChain uint6
return errors.New("PluginType must be set to either CCIPCommit or CCIPExec")
}
for chainSelector, params := range p.OCRConfigPerRemoteChainSelector {
_, ok := state.Chains[chainSelector]
if !ok {
if _, exists := state.SupportedChains()[chainSelector]; !exists {
Copy link
Contributor

Choose a reason for hiding this comment

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

Small nit: cleaner API seems to be state.IsChainSupported(chainSelector)

Copy link
Contributor

Choose a reason for hiding this comment

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

Will handle in a followup that just changes the fn name. Don't disagree but the fn already existed for us.

deployment/ccip/changeset/state.go Outdated Show resolved Hide resolved
deployment/ccip/changeset/state.go Show resolved Hide resolved
deployment/environment/memory/environment.go Show resolved Hide resolved
deployment/ccip/changeset/cs_deploy_chain.go Outdated Show resolved Hide resolved
deployment/ccip/changeset/cs_deploy_chain.go Outdated Show resolved Hide resolved
deployment/ccip/changeset/cs_deploy_chain.go Outdated Show resolved Hide resolved
deployment/ccip/changeset/cs_deploy_chain.go Outdated Show resolved Hide resolved
@@ -145,3 +156,18 @@ func GetEvmDestChainStatePDA(ccipRouterProgramID solana.PublicKey, evmChainSelec
)
return pda
}

func GetReceiverTargetAccountPDA(ccipReceiverProgram solana.PublicKey) solana.PublicKey {
pda, _, _ := solana.FindProgramAddress([][]byte{[]byte("counter")}, ccipReceiverProgram)
Copy link
Contributor

Choose a reason for hiding this comment

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

No error checking?

Copy link
Contributor

Choose a reason for hiding this comment

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

Also these strings "counter", "external_execution_config", "token_admin_registry" are fetched from where? Are there any constants that can be used instead, perhaps from Go bindings?

Copy link
Contributor

Choose a reason for hiding this comment

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

If not, please link where these strings are defined originally / referenced.

Copy link
Contributor

Choose a reason for hiding this comment

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

We actually refactored this in chainlink-ccip last week because the programs were hardcoded to test programs. smartcontractkit/chainlink-ccip@5b8bdc1

We can't incorporate the changes in this PR because chainlink-ccip introduced breaking contract changes. We're bumping chainlink-ccip and using the helpers in a followup. https://github.com/smartcontractkit/chainlink/pull/16088/files#diff-b7f8a498937d8fcd6b2d3850cfe63f19fec5932061406345cf5f22e9c8433b11R565

deployment/ccip/changeset/testhelpers/test_helpers.go Outdated Show resolved Hide resolved
deployment/ccip/changeset/testhelpers/test_helpers.go Outdated Show resolved Hide resolved
deployment/common/changeset/save_existing.go Outdated Show resolved Hide resolved
Comment on lines +193 to +194
maxRetries := 10
var url, wsURL string
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't really wanna retcon memory here to really mean docker for solana. Why not only spin up solana in the docker env? cc @AnieeG

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

@archseer archseer Jan 29, 2025

Choose a reason for hiding this comment

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

Because the in-memory environment is a lot simpler and faster, it avoids spinning up docker containers for all the chainlink nodes (and job distributor). Memory env is the main way a lot of these tests are ran so we'd have to make changes on CI to accommodate from what I understand

Copy link
Contributor

Choose a reason for hiding this comment

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

Sure, but I think now memory will no longer be as simple and fast due to the Solana docker container spinup (which also seems to be flakey). Overall not great, and just more burden on folks to continue maintaining flakey envs (of which we already have regularly flaking tests)

Copy link
Contributor

Choose a reason for hiding this comment

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

Solana only spins up in tests that ask for solana chains. I do think we need to introduce tags though so that tests for a specific chain type can be ran locally

Copy link
Contributor

Choose a reason for hiding this comment

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

Solana's local validator is rust based so it shouldn't take more than a second or two to boot. I'm hoping we can address any flakes and make the env reliable

@tt-cll tt-cll requested a review from makramkd January 29, 2025 11:35
@@ -538,6 +533,7 @@ func deployChainContractsEVM(e deployment.Environment, chain deployment.Chain, a
return nil
}

// TODO: move everything below to solana file
Copy link
Contributor

Choose a reason for hiding this comment

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

We doing this in a follow-up?

Copy link
Contributor

Choose a reason for hiding this comment

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

deployment/ccip/changeset/solana/cs_chain_contracts.go Outdated Show resolved Hide resolved
deployment/ccip/changeset/solana/cs_chain_contracts.go Outdated Show resolved Hide resolved
Comment on lines +122 to +124
// TODO: what if chain family is solana ?
// bytes4(keccak256("CCIP ChainFamilySelector EVM"))
ChainFamilySelector: [4]uint8{40, 18, 213, 44},
Copy link
Contributor

Choose a reason for hiding this comment

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

Isn't this provided by the update object? Why hardcode?

Copy link
Contributor

Choose a reason for hiding this comment

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

@tt-cll
Copy link
Contributor

tt-cll commented Jan 29, 2025

just for context, we're already working on a followup to add full token pool support. This is addressing a lot of the issues here with hardcoded configs or TODOs in code #16088

Some ccip contracts changed (including token pools) and wanted to handle that separately rather than all in one.

@AnieeG AnieeG added this pull request to the merge queue Jan 29, 2025
Merged via the queue into develop with commit f342658 Jan 29, 2025
206 of 209 checks passed
@AnieeG AnieeG deleted the solana-home-chain-update branch January 29, 2025 19:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants