Skip to content

Commit 238d248

Browse files
add transaction index to cadence
address review comments fix hashes extract metrics changes tweak test assertions
1 parent 0f22a33 commit 238d248

File tree

6 files changed

+175
-67
lines changed

6 files changed

+175
-67
lines changed

engine/execution/state/bootstrap/bootstrap_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func TestBootstrapLedger(t *testing.T) {
5858

5959
func TestBootstrapLedger_ZeroTokenSupply(t *testing.T) {
6060
expectedStateCommitmentBytes, _ := hex.DecodeString(
61-
"072ff5128df34db4483879f1b617338cd51def0e55cae25927eb5f3b404f3ef9",
61+
"506f0c7c9c12fb9b37deb015e3f148dd11ed139030fa0a6eeb6b162c73e4fb14",
6262
)
6363
expectedStateCommitment, err := flow.ToStateCommitment(expectedStateCommitmentBytes)
6464
require.NoError(t, err)
@@ -107,7 +107,7 @@ func TestBootstrapLedger_ZeroTokenSupply(t *testing.T) {
107107
// This tests that the state commitment has not changed for the bookkeeping parts of the transaction.
108108
func TestBootstrapLedger_EmptyTransaction(t *testing.T) {
109109
expectedStateCommitmentBytes, _ := hex.DecodeString(
110-
"61acd22132b90efd23bb1c4413ae5071dc9c0e123c288371a755e4f041791a20",
110+
"a16a6bf392c9dcffda1baeea9e70f1f20c504aeb912a1ed5cfadca65feb962ce",
111111
)
112112
expectedStateCommitment, err := flow.ToStateCommitment(expectedStateCommitmentBytes)
113113
require.NoError(t, err)

fvm/bootstrap.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ func Bootstrap(
249249
ServiceAccountPublicKeys: []flow.AccountPublicKey{serviceAccountPublicKey},
250250
FungibleTokenAccountPublicKeys: []flow.AccountPublicKey{serviceAccountPublicKey},
251251
FlowTokenAccountPublicKeys: []flow.AccountPublicKey{serviceAccountPublicKey},
252+
FlowFeesAccountPublicKeys: []flow.AccountPublicKey{serviceAccountPublicKey},
252253
NodeAccountPublicKeys: []flow.AccountPublicKey{serviceAccountPublicKey},
253254
},
254255
transactionFees: BootstrapProcedureFeeParameters{0, 0, 0},

fvm/fvm_test.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"encoding/hex"
88
"fmt"
99
"math"
10+
"strconv"
1011
"strings"
1112
"testing"
1213

@@ -4277,3 +4278,82 @@ func Test_BlockHashListShouldWriteOnPush(t *testing.T) {
42774278
require.Equal(t, expectedBlockHashListBucket, newBlockHashListBucket)
42784279
}))
42794280
}
4281+
4282+
func TestTransactionIndexCall(t *testing.T) {
4283+
t.Parallel()
4284+
4285+
t.Run("in transactions",
4286+
newVMTest().
4287+
run(
4288+
func(
4289+
t *testing.T,
4290+
vm fvm.VM,
4291+
chain flow.Chain,
4292+
ctx fvm.Context,
4293+
snapshotTree snapshot.SnapshotTree,
4294+
) {
4295+
txBodyBuilder := flow.NewTransactionBodyBuilder().
4296+
SetScript([]byte(`
4297+
transaction {
4298+
prepare() {
4299+
let idx = getTransactionIndex()
4300+
log(idx)
4301+
}
4302+
}
4303+
`)).
4304+
SetProposalKey(chain.ServiceAddress(), 0, 0).
4305+
SetPayer(chain.ServiceAddress())
4306+
4307+
err := testutil.SignTransactionAsServiceAccount(txBodyBuilder, 0, chain)
4308+
require.NoError(t, err)
4309+
4310+
txBody, err := txBodyBuilder.Build()
4311+
require.NoError(t, err)
4312+
4313+
ctx = fvm.NewContextFromParent(ctx, fvm.WithCadenceLogging(true))
4314+
4315+
txIndex := uint32(3)
4316+
4317+
_, output, err := vm.Run(
4318+
ctx,
4319+
fvm.Transaction(txBody, txIndex),
4320+
snapshotTree)
4321+
require.NoError(t, err)
4322+
require.NoError(t, output.Err)
4323+
require.Len(t, output.Logs, 1)
4324+
4325+
idx, err := strconv.Atoi(output.Logs[0])
4326+
require.NoError(t, err)
4327+
require.Equal(t, txIndex, uint32(idx))
4328+
},
4329+
),
4330+
)
4331+
4332+
t.Run("in scripts",
4333+
newVMTest().
4334+
run(
4335+
func(
4336+
t *testing.T,
4337+
vm fvm.VM,
4338+
chain flow.Chain,
4339+
ctx fvm.Context,
4340+
snapshotTree snapshot.SnapshotTree,
4341+
) {
4342+
script := fvm.Script(
4343+
[]byte(`
4344+
access(all) fun main(): UInt32 {
4345+
return getTransactionIndex()
4346+
}`))
4347+
4348+
_, output, err := vm.Run(
4349+
ctx,
4350+
script,
4351+
snapshotTree)
4352+
require.NoError(t, err)
4353+
require.NoError(t, output.Err)
4354+
4355+
require.Equal(t, cadence.UInt32(0), output.Value)
4356+
},
4357+
),
4358+
)
4359+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package runtime
2+
3+
import (
4+
"github.com/onflow/cadence/common"
5+
"github.com/onflow/cadence/interpreter"
6+
"github.com/onflow/cadence/sema"
7+
"github.com/onflow/cadence/stdlib"
8+
9+
"github.com/onflow/flow-go/fvm/errors"
10+
)
11+
12+
// randomSourceFunctionType is the type of the `randomSource` function.
13+
// This defines the signature as `func(): [UInt8]`
14+
var randomSourceFunctionType = &sema.FunctionType{
15+
ReturnTypeAnnotation: sema.NewTypeAnnotation(sema.ByteArrayType),
16+
}
17+
18+
func blockRandomSourceDeclaration(renv *ReusableCadenceRuntime) stdlib.StandardLibraryValue {
19+
// Declare the `randomSourceHistory` function. This function is **only** used by the
20+
// System transaction, to fill the `RandomBeaconHistory` contract via the heartbeat
21+
// resource. This allows the `RandomBeaconHistory` contract to be a standard contract,
22+
// without any special parts.
23+
// Since the `randomSourceHistory` function is only used by the System transaction,
24+
// it is not part of the cadence standard library, and can just be injected from here.
25+
// It also doesn't need user documentation, since it is not (and should not)
26+
// be called by the user. If it is called by the user it will panic.
27+
return stdlib.StandardLibraryValue{
28+
Name: "randomSourceHistory",
29+
Type: randomSourceFunctionType,
30+
Kind: common.DeclarationKindFunction,
31+
Value: interpreter.NewUnmeteredStaticHostFunctionValue(
32+
randomSourceFunctionType,
33+
func(invocation interpreter.Invocation) interpreter.Value {
34+
var err error
35+
var source []byte
36+
env := renv.fvmEnv
37+
if env != nil {
38+
source, err = env.RandomSourceHistory()
39+
} else {
40+
err = errors.NewOperationNotSupportedError("randomSourceHistory")
41+
}
42+
43+
if err != nil {
44+
panic(err)
45+
}
46+
47+
return interpreter.ByteSliceToByteArrayValue(
48+
invocation.InvocationContext,
49+
source)
50+
},
51+
),
52+
}
53+
}
54+
55+
// transactionIndexFunctionType is the type of the `getTransactionIndex` function.
56+
// This defines the signature as `func(): UInt32`
57+
var transactionIndexFunctionType = &sema.FunctionType{
58+
ReturnTypeAnnotation: sema.NewTypeAnnotation(sema.UInt32Type),
59+
}
60+
61+
func transactionIndexDeclaration(renv *ReusableCadenceRuntime) stdlib.StandardLibraryValue {
62+
return stdlib.StandardLibraryValue{
63+
Name: "getTransactionIndex",
64+
DocString: `Returns the transaction index in the current block, i.e. first transaction in a block has index of 0, second has index of 1...`,
65+
Type: transactionIndexFunctionType,
66+
Kind: common.DeclarationKindFunction,
67+
Value: interpreter.NewUnmeteredStaticHostFunctionValue(
68+
transactionIndexFunctionType,
69+
func(invocation interpreter.Invocation) interpreter.Value {
70+
return interpreter.NewUInt32Value(
71+
invocation.InvocationContext,
72+
func() uint32 {
73+
env := renv.fvmEnv
74+
if env == nil {
75+
panic(errors.NewOperationNotSupportedError("transactionIndex"))
76+
}
77+
return env.TxIndex()
78+
})
79+
},
80+
),
81+
}
82+
}

fvm/runtime/reusable_cadence_runtime.go

Lines changed: 7 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,8 @@ package runtime
33
import (
44
"github.com/onflow/cadence"
55
"github.com/onflow/cadence/common"
6-
"github.com/onflow/cadence/interpreter"
76
"github.com/onflow/cadence/runtime"
87
"github.com/onflow/cadence/sema"
9-
"github.com/onflow/cadence/stdlib"
10-
11-
"github.com/onflow/flow-go/fvm/errors"
128
)
139

1410
// Note: this is a subset of environment.Environment, redeclared to handle
@@ -18,12 +14,7 @@ type Environment interface {
1814
common.Gauge
1915

2016
RandomSourceHistory() ([]byte, error)
21-
}
22-
23-
// randomSourceFunctionType is the type of the `randomSource` function.
24-
// This defines the signature as `func(): [UInt8]`
25-
var randomSourceFunctionType = &sema.FunctionType{
26-
ReturnTypeAnnotation: sema.NewTypeAnnotation(sema.ByteArrayType),
17+
TxIndex() uint32
2718
}
2819

2920
type ReusableCadenceRuntime struct {
@@ -44,63 +35,17 @@ func NewReusableCadenceRuntime(
4435
ScriptRuntimeEnv: runtime.NewScriptInterpreterEnvironment(config),
4536
}
4637

47-
reusable.declareRandomSourceHistory()
38+
reusable.declareStandardLibraryFunctions()
4839

4940
return reusable
5041
}
5142

52-
func (reusable *ReusableCadenceRuntime) declareRandomSourceHistory() {
53-
54-
// Declare the `randomSourceHistory` function. This function is **only** used by the
55-
// System transaction, to fill the `RandomBeaconHistory` contract via the heartbeat
56-
// resource. This allows the `RandomBeaconHistory` contract to be a standard contract,
57-
// without any special parts.
58-
// Since the `randomSourceHistory` function is only used by the System transaction,
59-
// it is not part of the cadence standard library, and can just be injected from here.
60-
// It also doesnt need user documentation, since it is not (and should not)
61-
// be called by the user. If it is called by the user it will panic.
62-
functionType := randomSourceFunctionType
63-
64-
blockRandomSource := stdlib.StandardLibraryValue{
65-
Name: "randomSourceHistory",
66-
Type: functionType,
67-
Kind: common.DeclarationKindFunction,
68-
Value: interpreter.NewUnmeteredStaticHostFunctionValue(
69-
functionType,
70-
func(invocation interpreter.Invocation) interpreter.Value {
71-
72-
actualArgumentCount := len(invocation.Arguments)
73-
expectedArgumentCount := len(functionType.Parameters)
74-
75-
if actualArgumentCount != expectedArgumentCount {
76-
panic(errors.NewInvalidArgumentErrorf(
77-
"incorrect number of arguments: got %d, expected %d",
78-
actualArgumentCount,
79-
expectedArgumentCount,
80-
))
81-
}
82-
83-
var err error
84-
var source []byte
85-
fvmEnv := reusable.fvmEnv
86-
if fvmEnv != nil {
87-
source, err = fvmEnv.RandomSourceHistory()
88-
} else {
89-
err = errors.NewOperationNotSupportedError("randomSourceHistory")
90-
}
91-
92-
if err != nil {
93-
panic(err)
94-
}
95-
96-
return interpreter.ByteSliceToByteArrayValue(
97-
invocation.InvocationContext,
98-
source)
99-
},
100-
),
101-
}
43+
func (reusable *ReusableCadenceRuntime) declareStandardLibraryFunctions() {
44+
reusable.TxRuntimeEnv.DeclareValue(blockRandomSourceDeclaration(reusable), nil)
10245

103-
reusable.TxRuntimeEnv.DeclareValue(blockRandomSource, nil)
46+
declaration := transactionIndexDeclaration(reusable)
47+
reusable.TxRuntimeEnv.DeclareValue(declaration, nil)
48+
reusable.ScriptRuntimeEnv.DeclareValue(declaration, nil)
10449
}
10550

10651
func (reusable *ReusableCadenceRuntime) SetFvmEnvironment(fvmEnv Environment) {

utils/unittest/execution_state.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const ServiceAccountPrivateKeySignAlgo = crypto.ECDSAP256
2323
const ServiceAccountPrivateKeyHashAlgo = hash.SHA2_256
2424

2525
// Pre-calculated state commitment with root account with the above private key
26-
const GenesisStateCommitmentHex = "dad6fda8f9745ec0e1cf9d4d2429060a9460cef513f29272a6deb973820af6aa"
26+
const GenesisStateCommitmentHex = "e53b39d66b2689882f21d0a0605de5693df8090c01279a14718c81746daf804b"
2727

2828
var GenesisStateCommitment flow.StateCommitment
2929

@@ -87,10 +87,10 @@ func genesisCommitHexByChainID(chainID flow.ChainID) string {
8787
return GenesisStateCommitmentHex
8888
}
8989
if chainID == flow.Testnet {
90-
return "d758711a98ebb0cb16023f8b14dfd18ab6b4292af6634f115f47b2065b839f4b"
90+
return "838452ac649d949992e5fb0da61fdba9cfeb09530e27e259b3b24300d3a7687f"
9191
}
9292
if chainID == flow.Sandboxnet {
9393
return "e1c08b17f9e5896f03fe28dd37ca396c19b26628161506924fbf785834646ea1"
9494
}
95-
return "a3af0430b178103671b02564a1cc3477ab25acf459523449640a2b6198bd83c8"
95+
return "5164cee75a6f5795a77f52bdf6eb05f47162ddd2a54af97ac30dd3068e6c2b5c"
9696
}

0 commit comments

Comments
 (0)