Skip to content

Commit 40833bb

Browse files
committed
Merge branch 'master' into bastian/cadence-vm-merge-master
2 parents bab4512 + cdce991 commit 40833bb

File tree

22 files changed

+283
-60
lines changed

22 files changed

+283
-60
lines changed

cmd/util/ledger/util/nop_meter.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package util
22

33
import (
4+
"math"
5+
46
"github.com/onflow/cadence/common"
57

68
"github.com/onflow/flow-go/fvm/environment"
@@ -28,6 +30,10 @@ func (n NopMeter) ComputationIntensities() meter.MeteredComputationIntensities {
2830
return meter.MeteredComputationIntensities{}
2931
}
3032

33+
func (n NopMeter) ComputationRemaining(_ common.ComputationKind) uint64 {
34+
return math.MaxUint64
35+
}
36+
3137
func (n NopMeter) MeterMemory(_ common.MemoryUsage) error {
3238
return nil
3339
}

engine/execution/state/bootstrap/bootstrap_test.go

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,9 @@ func TestBootstrapLedger(t *testing.T) {
5858
}
5959

6060
func TestBootstrapLedger_ZeroTokenSupply(t *testing.T) {
61-
expectedStateCommitmentBytes, _ := hex.DecodeString(ifCompile(
62-
"114c3c6747c0ecdb6f1aaba9278e261e2883d40c0ec917aacc53a6bfaca4c28f",
63-
"d04e95da9811e985c5bf6a8f956ab3571ebf7bd4f15bf36098875b0e51e72906",
64-
))
61+
expectedStateCommitmentBytes, _ := hex.DecodeString(
62+
"9b45ac2b9e1e04fd57761d551110d988c1737855d17f2f540c4b6c79c4b5058e",
63+
)
6564
expectedStateCommitment, err := flow.ToStateCommitment(expectedStateCommitmentBytes)
6665
require.NoError(t, err)
6766

@@ -116,10 +115,7 @@ func ifCompile[T any](a, b T) T {
116115
// This tests that the state commitment has not changed for the bookkeeping parts of the transaction.
117116
func TestBootstrapLedger_EmptyTransaction(t *testing.T) {
118117
expectedStateCommitmentBytes, _ := hex.DecodeString(
119-
ifCompile(
120-
"26c1eb39af9ba9708b49d1149d9fb7ee2a5ab870793c67da0b4bd7c48f0cca33",
121-
"88d0c00ff69668ef8e049f811b13750d4cd75cda2be6ecd3e6dcf3685e28c4e4",
122-
),
118+
"52ca1f4d53adc9ff018f10473a8bd02b4dc9baf5ab04bc1ac0fbb5b40e780d83",
123119
)
124120
expectedStateCommitment, err := flow.ToStateCommitment(expectedStateCommitmentBytes)
125121
require.NoError(t, err)

fvm/environment/meter.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ type Meter interface {
112112

113113
ComputationIntensities() meter.MeteredComputationIntensities
114114
ComputationAvailable(common.ComputationUsage) bool
115+
ComputationRemaining(kind common.ComputationKind) uint64
115116

116117
MeterEmittedEvent(byteSize uint64) error
117118
TotalEmittedEventBytes() uint64
@@ -141,6 +142,10 @@ func (meter *meterImpl) ComputationAvailable(usage common.ComputationUsage) bool
141142
return meter.txnState.ComputationAvailable(usage)
142143
}
143144

145+
func (meter *meterImpl) ComputationRemaining(kind common.ComputationKind) uint64 {
146+
return meter.txnState.ComputationRemaining(kind)
147+
}
148+
144149
func (meter *meterImpl) ComputationUsed() (uint64, error) {
145150
return meter.txnState.TotalComputationUsed(), nil
146151
}

fvm/environment/mock/environment.go

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

fvm/environment/mock/meter.go

Lines changed: 18 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

fvm/evm/backends/wrappedEnv.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,11 @@ func (we *WrappedEnvironment) ComputationAvailable(usage common.ComputationUsage
8282
return we.env.ComputationAvailable(usage)
8383
}
8484

85-
// MeterMemory meters the memory usage of a new operation.
85+
// ComputationRemaining returns the remaining computation for the given kind.
86+
func (we *WrappedEnvironment) ComputationRemaining(kind common.ComputationKind) uint64 {
87+
return we.env.ComputationRemaining(kind)
88+
}
89+
8690
func (we *WrappedEnvironment) MeterMemory(usage common.MemoryUsage) error {
8791
err := we.env.MeterMemory(usage)
8892
return handleEnvironmentError(err)

fvm/evm/evm_test.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"encoding/binary"
66
"fmt"
7+
"math"
78
"math/big"
89
"testing"
910

@@ -1244,6 +1245,89 @@ func TestEVMBatchRun(t *testing.T) {
12441245
require.Equal(t, num, new(big.Int).SetBytes(res.ReturnedData).Int64())
12451246
})
12461247
})
1248+
1249+
// run a batch of two transactions. The sum of their gas usage would overflow an uint46
1250+
// so the batch run should fail with an overflow error.
1251+
t.Run("Batch run evm gas overflow", func(t *testing.T) {
1252+
t.Parallel()
1253+
RunWithNewEnvironment(t,
1254+
chain, func(
1255+
ctx fvm.Context,
1256+
vm fvm.VM,
1257+
snapshot snapshot.SnapshotTree,
1258+
testContract *TestContract,
1259+
testAccount *EOATestAccount,
1260+
) {
1261+
sc := systemcontracts.SystemContractsForChain(chain.ChainID())
1262+
batchRunCode := []byte(fmt.Sprintf(
1263+
`
1264+
import EVM from %s
1265+
1266+
transaction(txs: [[UInt8]], coinbaseBytes: [UInt8; 20]) {
1267+
execute {
1268+
let coinbase = EVM.EVMAddress(bytes: coinbaseBytes)
1269+
let batchResults = EVM.batchRun(txs: txs, coinbase: coinbase)
1270+
}
1271+
}
1272+
`,
1273+
sc.EVMContract.Address.HexWithPrefix(),
1274+
))
1275+
1276+
coinbaseAddr := types.Address{1, 2, 3}
1277+
coinbaseBalance := getEVMAccountBalance(t, ctx, vm, snapshot, coinbaseAddr)
1278+
require.Zero(t, types.BalanceToBigInt(coinbaseBalance).Uint64())
1279+
1280+
batchCount := 2
1281+
txBytes := make([]cadence.Value, batchCount)
1282+
1283+
tx := testAccount.PrepareSignAndEncodeTx(t,
1284+
testContract.DeployedAt.ToCommon(),
1285+
testContract.MakeCallData(t, "storeWithLog", big.NewInt(0)),
1286+
big.NewInt(0),
1287+
uint64(200_000),
1288+
big.NewInt(1),
1289+
)
1290+
1291+
txBytes[0] = cadence.NewArray(
1292+
unittest.BytesToCdcUInt8(tx),
1293+
).WithType(stdlib.EVMTransactionBytesCadenceType)
1294+
1295+
tx = testAccount.PrepareSignAndEncodeTx(t,
1296+
testContract.DeployedAt.ToCommon(),
1297+
testContract.MakeCallData(t, "storeWithLog", big.NewInt(1)),
1298+
big.NewInt(0),
1299+
math.MaxUint64-uint64(100_000),
1300+
big.NewInt(1),
1301+
)
1302+
1303+
txBytes[1] = cadence.NewArray(
1304+
unittest.BytesToCdcUInt8(tx),
1305+
).WithType(stdlib.EVMTransactionBytesCadenceType)
1306+
1307+
coinbase := cadence.NewArray(
1308+
unittest.BytesToCdcUInt8(coinbaseAddr.Bytes()),
1309+
).WithType(stdlib.EVMAddressBytesCadenceType)
1310+
1311+
txs := cadence.NewArray(txBytes).
1312+
WithType(cadence.NewVariableSizedArrayType(
1313+
stdlib.EVMTransactionBytesCadenceType,
1314+
))
1315+
1316+
txBody, err := flow.NewTransactionBodyBuilder().
1317+
SetScript(batchRunCode).
1318+
SetPayer(sc.FlowServiceAccount.Address).
1319+
AddArgument(json.MustEncode(txs)).
1320+
AddArgument(json.MustEncode(coinbase)).
1321+
Build()
1322+
require.NoError(t, err)
1323+
1324+
state, output, err := vm.Run(ctx, fvm.Transaction(txBody, 0), snapshot)
1325+
require.NoError(t, err)
1326+
require.Error(t, output.Err)
1327+
require.ErrorContains(t, output.Err, "insufficient computation")
1328+
require.Empty(t, state.WriteSet)
1329+
})
1330+
})
12471331
}
12481332

12491333
func TestEVMBlockData(t *testing.T) {

fvm/evm/handler/handler.go

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -204,13 +204,12 @@ func (h *ContractHandler) BatchRun(rlpEncodedTxs [][]byte, gasFeeCollector types
204204
}
205205

206206
func (h *ContractHandler) batchRun(rlpEncodedTxs [][]byte) ([]*types.Result, error) {
207-
// step 1 - transaction decoding and compute total gas needed
208-
// This is safe to be done before checking the gas
209-
// as it has its own metering
210-
var totalGasLimit types.GasLimit
207+
// step 1 - transaction decoding and check that enough evm gas is available in the FVM transaction
208+
209+
// remainingGasLimit is the remaining EVM gas available in hte FVM transaction
210+
remainingGasLimit := h.backend.ComputationRemaining(environment.ComputationKindEVMGasUsage)
211211
batchLen := len(rlpEncodedTxs)
212212
txs := make([]*gethTypes.Transaction, batchLen)
213-
214213
for i, rlpEncodedTx := range rlpEncodedTxs {
215214
tx, err := h.decodeTransaction(rlpEncodedTx)
216215
// if any tx fails decoding revert the batch
@@ -219,14 +218,13 @@ func (h *ContractHandler) batchRun(rlpEncodedTxs [][]byte) ([]*types.Result, err
219218
}
220219

221220
txs[i] = tx
222-
totalGasLimit += types.GasLimit(tx.Gas())
223-
}
224221

225-
// step 2 - check if enough computation is available
226-
// for the whole batch
227-
err := h.checkGasLimit(totalGasLimit)
228-
if err != nil {
229-
return nil, err
222+
// step 2 - check if enough computation is available
223+
txGasLimit := tx.Gas()
224+
if remainingGasLimit < txGasLimit {
225+
return nil, types.ErrInsufficientComputation
226+
}
227+
remainingGasLimit -= txGasLimit
230228
}
231229

232230
// step 3 - prepare block context

fvm/evm/offchain/query/view.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ func (v *View) DryCall(
110110
from gethCommon.Address,
111111
to gethCommon.Address,
112112
data []byte,
113+
authList []gethTypes.SetCodeAuthorization,
113114
value *big.Int,
114115
gasLimit uint64,
115116
opts ...DryCallOption,
@@ -160,6 +161,13 @@ func (v *View) DryCall(
160161
// not apply. These endpoints don't mutate the state, they
161162
// simply read the state.
162163
call.SkipTxGasLimitCheck()
164+
165+
// If we are given a non-empty list of SetCode authorizations,
166+
// we need to set them, so that gas estimation works properly.
167+
if len(authList) > 0 {
168+
call.SetCodeAuthorizations(authList)
169+
}
170+
163171
res, err := bv.DirectCall(call)
164172
if err != nil {
165173
return nil, err

0 commit comments

Comments
 (0)