Skip to content

Commit 7c85007

Browse files
committed
Add Mainnet Test
1 parent 84ef55e commit 7c85007

File tree

1 file changed

+140
-2
lines changed

1 file changed

+140
-2
lines changed

server/fork_integration_test.go

Lines changed: 140 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package server
22

33
import (
44
"context"
5+
"strings"
56
"testing"
67

78
"github.com/onflow/flow-emulator/convert"
@@ -14,8 +15,6 @@ import (
1415
)
1516

1617
// TestForkingAgainstTestnet exercises the forking path by wiring a remote store
17-
// We do not test Mainnet as at the time of writing Mainnet is not compatibible
18-
// with the latest upstream Forte upgrade available in the latest emulator releases.
1918
func TestForkingAgainstTestnet(t *testing.T) {
2019
logger := zerolog.Nop()
2120

@@ -150,3 +149,142 @@ func TestForkingAgainstTestnet(t *testing.T) {
150149
}
151150
}
152151
}
152+
153+
// TestForkingAgainstMainnet exercises the forking path with mainnet and tests the account key deduplication shim
154+
func TestForkingAgainstMainnet(t *testing.T) {
155+
logger := zerolog.Nop()
156+
157+
// Get remote latest sealed height to pin fork
158+
conn, err := grpc.NewClient("access.mainnet.nodes.onflow.org:9000", grpc.WithTransportCredentials(insecure.NewCredentials()))
159+
if err != nil {
160+
t.Fatalf("dial remote: %v", err)
161+
}
162+
defer conn.Close()
163+
remote := flowaccess.NewAccessAPIClient(conn)
164+
rh, err := remote.GetLatestBlockHeader(context.Background(), &flowaccess.GetLatestBlockHeaderRequest{IsSealed: true})
165+
if err != nil {
166+
t.Fatalf("get remote header: %v", err)
167+
}
168+
remoteHeight := rh.Block.Height
169+
170+
cfg := &Config{
171+
// Do not start listeners; NewEmulatorServer only configures components.
172+
DBPath: "",
173+
Persist: false,
174+
Snapshot: false,
175+
SkipTransactionValidation: true,
176+
ChainID: flowgo.Mainnet, // will be overridden by detectRemoteChainID
177+
ForkURL: "access.mainnet.nodes.onflow.org:9000",
178+
ForkBlockNumber: remoteHeight,
179+
}
180+
181+
srv := NewEmulatorServer(&logger, cfg)
182+
if srv == nil {
183+
t.Fatal("NewEmulatorServer returned nil")
184+
}
185+
186+
if cfg.ChainID != flowgo.Mainnet {
187+
t.Fatalf("expected ChainID to be Mainnet after fork detection, got %q", cfg.ChainID)
188+
}
189+
190+
// Create an initial local block so we have a valid reference block ID in the forked store
191+
if _, _, err := srv.Emulator().ExecuteAndCommitBlock(); err != nil {
192+
t.Fatalf("prime local block: %v", err)
193+
}
194+
195+
// Test account key retrieval for a known mainnet account with multiple keys
196+
// This tests the account key deduplication shim
197+
testAccountScript := []byte(`
198+
transaction {
199+
prepare(acct: auth(Storage) &Account) {
200+
// Test getting account keys for a known mainnet account
201+
let account = getAccount(0xe467b9dd11fa00df)
202+
203+
// Test accessing specific key indices
204+
let key0 = account.keys.get(keyIndex: 0)
205+
if key0 != nil {
206+
log("Key 0 weight: ".concat(key0!.weight.toString()))
207+
if key0!.isRevoked {
208+
log("Key 0 is revoked")
209+
} else {
210+
log("Key 0 is not revoked")
211+
}
212+
}
213+
214+
let key1 = account.keys.get(keyIndex: 1)
215+
if key1 != nil {
216+
log("Key 1 weight: ".concat(key1!.weight.toString()))
217+
if key1!.isRevoked {
218+
log("Key 1 is revoked")
219+
} else {
220+
log("Key 1 is not revoked")
221+
}
222+
}
223+
224+
// Test that we can access keys without errors
225+
log("Account key access test completed")
226+
}
227+
}
228+
`)
229+
230+
latest, err := srv.Emulator().GetLatestBlock()
231+
if err != nil {
232+
t.Fatalf("get latest block: %v", err)
233+
}
234+
// Allow emulator height to be equal to or one greater than remote (if remote advanced by one between queries)
235+
if latest.Height != remoteHeight+1 {
236+
t.Fatalf("fork height mismatch: emulator %d not in {remote, remote+1} where remote=%d", latest.Height, remoteHeight)
237+
}
238+
sk := srv.Emulator().ServiceKey()
239+
240+
tx := flowsdk.NewTransaction().
241+
SetScript(testAccountScript).
242+
SetReferenceBlockID(flowsdk.Identifier(latest.ID())).
243+
SetProposalKey(flowsdk.Address(sk.Address), sk.Index, sk.SequenceNumber).
244+
SetPayer(flowsdk.Address(sk.Address)).
245+
AddAuthorizer(flowsdk.Address(sk.Address))
246+
247+
signer, err := sk.Signer()
248+
if err != nil {
249+
t.Fatalf("signer: %v", err)
250+
}
251+
if err := tx.SignEnvelope(flowsdk.Address(sk.Address), sk.Index, signer); err != nil {
252+
t.Fatalf("sign envelope: %v", err)
253+
}
254+
if err := srv.Emulator().AddTransaction(*convert.SDKTransactionToFlow(*tx)); err != nil {
255+
t.Fatalf("add tx: %v", err)
256+
}
257+
if _, results, err := srv.Emulator().ExecuteAndCommitBlock(); err != nil {
258+
t.Fatalf("execute block: %v", err)
259+
} else {
260+
if len(results) != 1 {
261+
t.Fatalf("expected 1 tx result, got %d", len(results))
262+
}
263+
r := results[0]
264+
if !r.Succeeded() {
265+
t.Fatalf("tx failed: %v", r.Error)
266+
}
267+
268+
// Check that we got meaningful logs about the account keys
269+
logs := r.Logs
270+
hasKeyWeight := false
271+
hasCompletion := false
272+
for _, log := range logs {
273+
if strings.Contains(log, "weight:") {
274+
hasKeyWeight = true
275+
}
276+
if strings.Contains(log, "Account key access test completed") {
277+
hasCompletion = true
278+
}
279+
}
280+
281+
if !hasKeyWeight {
282+
t.Fatalf("expected log with key weight, got: %v", logs)
283+
}
284+
if !hasCompletion {
285+
t.Fatalf("expected completion log, got: %v", logs)
286+
}
287+
288+
t.Logf("Account key test successful. Logs: %v", logs)
289+
}
290+
}

0 commit comments

Comments
 (0)