Skip to content

Commit 736053b

Browse files
committed
Enable EVM Fusaka hard-fork for PreviewNet(Emulator) & Testnet
1 parent 4df61ad commit 736053b

File tree

2 files changed

+193
-0
lines changed

2 files changed

+193
-0
lines changed

fvm/evm/emulator/config.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ var (
2121
PreviewnetPragueActivation = uint64(0) // already on Prague for PreviewNet
2222
TestnetPragueActivation = uint64(1746723600) // Thu May 08 2025 17:00:00 GMT+0000 (10am PDT)
2323
MainnetPragueActivation = uint64(1747328400) // Thu May 15 2025 17:00:00 GMT+0000 (10am PDT)
24+
25+
PreviewnetOsakaActivation = uint64(0) // already on Osaka for PreviewNet
26+
TestnetOsakaActivation = uint64(1761670800) // Wednesday, December 3, 2025 5:00:00 PM GMT+0000
27+
MainnetOsakaActivation = uint64(1764781200) // Wednesday, December 3, 2025 11:59:59 PM GMT+0000
2428
)
2529

2630
// Config aggregates all the configuration (chain, evm, block, tx, ...)
@@ -101,15 +105,20 @@ func MakeChainConfig(chainID *big.Int) *gethParams.ChainConfig {
101105
ShanghaiTime: &zero, // already on Shanghai
102106
CancunTime: &zero, // already on Cancun
103107
PragueTime: nil, // this is conditionally set below
108+
OsakaTime: nil, // this is conditionally set below
104109
VerkleTime: nil, // not on Verkle
105110
}
106111

107112
if chainID.Cmp(types.FlowEVMPreviewNetChainID) == 0 {
108113
chainConfig.PragueTime = &PreviewnetPragueActivation
114+
chainConfig.OsakaTime = &PreviewnetOsakaActivation
109115
} else if chainID.Cmp(types.FlowEVMTestNetChainID) == 0 {
110116
chainConfig.PragueTime = &TestnetPragueActivation
117+
chainConfig.OsakaTime = &TestnetOsakaActivation
111118
} else if chainID.Cmp(types.FlowEVMMainNetChainID) == 0 {
112119
chainConfig.PragueTime = &MainnetPragueActivation
120+
// Do not set this yet, until we know exact date for Mainnet
121+
// chainConfig.OsakaTime = &MainnetOsakaActivation
113122
}
114123

115124
return chainConfig

fvm/evm/evm_test.go

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -577,6 +577,190 @@ func TestEVMRun(t *testing.T) {
577577
},
578578
)
579579
})
580+
581+
t.Run("testing EVM.run failed with gas limit validation error", func(t *testing.T) {
582+
t.Parallel()
583+
584+
RunWithNewEnvironment(t,
585+
chain, func(
586+
ctx fvm.Context,
587+
vm fvm.VM,
588+
snapshot snapshot.SnapshotTree,
589+
testContract *TestContract,
590+
testAccount *EOATestAccount,
591+
) {
592+
sc := systemcontracts.SystemContractsForChain(chain.ChainID())
593+
code := []byte(fmt.Sprintf(
594+
`
595+
import EVM from %s
596+
transaction(tx: [UInt8], coinbaseBytes: [UInt8; 20]){
597+
prepare(account: &Account) {
598+
let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
599+
let res = EVM.run(tx: tx, coinbase: coinbase)
600+
assert(res.status == EVM.Status.invalid, message: "unexpected status")
601+
assert(res.errorCode == 100, message: "unexpected error code: \(res.errorCode)")
602+
assert(res.errorMessage == "transaction gas limit too high (cap: 16777216, tx: 16777220)")
603+
}
604+
}
605+
`,
606+
sc.EVMContract.Address.HexWithPrefix(),
607+
))
608+
609+
coinbaseAddr := types.Address{1, 2, 3}
610+
coinbaseBalance := getEVMAccountBalance(t, ctx, vm, snapshot, coinbaseAddr)
611+
require.Zero(t, types.BalanceToBigInt(coinbaseBalance).Uint64())
612+
613+
num := int64(12)
614+
innerTxBytes := testAccount.PrepareSignAndEncodeTx(t,
615+
testContract.DeployedAt.ToCommon(),
616+
testContract.MakeCallData(t, "store", big.NewInt(num)),
617+
big.NewInt(0),
618+
uint64(16_777_220), // max is 16,777,216
619+
big.NewInt(1),
620+
)
621+
622+
innerTx := cadence.NewArray(
623+
unittest.BytesToCdcUInt8(innerTxBytes),
624+
).WithType(stdlib.EVMTransactionBytesCadenceType)
625+
626+
coinbase := cadence.NewArray(
627+
unittest.BytesToCdcUInt8(coinbaseAddr.Bytes()),
628+
).WithType(stdlib.EVMAddressBytesCadenceType)
629+
630+
txBody, err := flow.NewTransactionBodyBuilder().
631+
SetScript(code).
632+
SetPayer(sc.FlowServiceAccount.Address).
633+
AddAuthorizer(sc.FlowServiceAccount.Address).
634+
AddArgument(json.MustEncode(innerTx)).
635+
AddArgument(json.MustEncode(coinbase)).
636+
Build()
637+
require.NoError(t, err)
638+
639+
tx := fvm.Transaction(txBody, 0)
640+
641+
state, output, err := vm.Run(
642+
ctx,
643+
tx,
644+
snapshot,
645+
)
646+
require.NoError(t, err)
647+
require.NoError(t, output.Err)
648+
require.NotEmpty(t, state.WriteSet)
649+
650+
// assert no events were produced from an invalid EVM transaction
651+
require.Len(t, output.Events, 0)
652+
})
653+
})
654+
655+
t.Run("testing EVM.run with max gas limit cap", func(t *testing.T) {
656+
t.Parallel()
657+
658+
RunWithNewEnvironment(t,
659+
chain, func(
660+
ctx fvm.Context,
661+
vm fvm.VM,
662+
snapshot snapshot.SnapshotTree,
663+
testContract *TestContract,
664+
testAccount *EOATestAccount,
665+
) {
666+
sc := systemcontracts.SystemContractsForChain(chain.ChainID())
667+
code := []byte(fmt.Sprintf(
668+
`
669+
import EVM from %s
670+
transaction(tx: [UInt8], coinbaseBytes: [UInt8; 20]){
671+
prepare(account: &Account) {
672+
let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
673+
let res = EVM.run(tx: tx, coinbase: coinbase)
674+
assert(res.status == EVM.Status.successful, message: "unexpected status")
675+
assert(res.errorCode == 0, message: "unexpected error code: \(res.errorCode)")
676+
}
677+
}
678+
`,
679+
sc.EVMContract.Address.HexWithPrefix(),
680+
))
681+
682+
coinbaseAddr := types.Address{1, 2, 3}
683+
coinbaseBalance := getEVMAccountBalance(t, ctx, vm, snapshot, coinbaseAddr)
684+
require.Zero(t, types.BalanceToBigInt(coinbaseBalance).Uint64())
685+
686+
num := int64(12)
687+
innerTxBytes := testAccount.PrepareSignAndEncodeTx(t,
688+
testContract.DeployedAt.ToCommon(),
689+
testContract.MakeCallData(t, "store", big.NewInt(num)),
690+
big.NewInt(0),
691+
uint64(16_777_216),
692+
big.NewInt(1),
693+
)
694+
695+
innerTx := cadence.NewArray(
696+
unittest.BytesToCdcUInt8(innerTxBytes),
697+
).WithType(stdlib.EVMTransactionBytesCadenceType)
698+
699+
coinbase := cadence.NewArray(
700+
unittest.BytesToCdcUInt8(coinbaseAddr.Bytes()),
701+
).WithType(stdlib.EVMAddressBytesCadenceType)
702+
703+
txBody, err := flow.NewTransactionBodyBuilder().
704+
SetScript(code).
705+
SetPayer(sc.FlowServiceAccount.Address).
706+
AddAuthorizer(sc.FlowServiceAccount.Address).
707+
AddArgument(json.MustEncode(innerTx)).
708+
AddArgument(json.MustEncode(coinbase)).
709+
Build()
710+
require.NoError(t, err)
711+
712+
tx := fvm.Transaction(txBody, 0)
713+
714+
state, output, err := vm.Run(
715+
ctx,
716+
tx,
717+
snapshot,
718+
)
719+
require.NoError(t, err)
720+
require.NoError(t, output.Err)
721+
require.NotEmpty(t, state.WriteSet)
722+
snapshot = snapshot.Append(state)
723+
724+
// assert event fields are correct
725+
require.Len(t, output.Events, 2)
726+
txEvent := output.Events[0]
727+
txEventPayload := TxEventToPayload(t, txEvent, sc.EVMContract.Address)
728+
require.NoError(t, err)
729+
730+
// fee transfer event
731+
feeTransferEvent := output.Events[1]
732+
feeTranferEventPayload := TxEventToPayload(t, feeTransferEvent, sc.EVMContract.Address)
733+
require.NoError(t, err)
734+
require.Equal(t, uint16(types.ErrCodeNoError), feeTranferEventPayload.ErrorCode)
735+
require.Equal(t, uint16(1), feeTranferEventPayload.Index)
736+
require.Equal(t, uint64(21000), feeTranferEventPayload.GasConsumed)
737+
738+
// commit block
739+
blockEventPayload, _ := callEVMHeartBeat(t,
740+
ctx,
741+
vm,
742+
snapshot,
743+
)
744+
745+
require.NotEmpty(t, blockEventPayload.Hash)
746+
require.Equal(t, uint64(64785), blockEventPayload.TotalGasUsed)
747+
require.NotEmpty(t, blockEventPayload.Hash)
748+
749+
txHashes := types.TransactionHashes{txEventPayload.Hash, feeTranferEventPayload.Hash}
750+
require.Equal(t,
751+
txHashes.RootHash(),
752+
blockEventPayload.TransactionHashRoot,
753+
)
754+
require.NotEmpty(t, blockEventPayload.ReceiptRoot)
755+
756+
require.Equal(t, innerTxBytes, txEventPayload.Payload)
757+
require.Equal(t, uint16(types.ErrCodeNoError), txEventPayload.ErrorCode)
758+
require.Equal(t, uint16(0), txEventPayload.Index)
759+
require.Equal(t, blockEventPayload.Height, txEventPayload.BlockHeight)
760+
require.Equal(t, blockEventPayload.TotalGasUsed-feeTranferEventPayload.GasConsumed, txEventPayload.GasConsumed)
761+
require.Empty(t, txEventPayload.ContractAddress)
762+
})
763+
})
580764
}
581765

582766
func TestEVMBatchRun(t *testing.T) {

0 commit comments

Comments
 (0)