From 4bc8c3e203a31a983473a3701bd4a7b13e5619e4 Mon Sep 17 00:00:00 2001 From: Ramtin Mehdizadeh Seraj Date: Wed, 25 Nov 2020 11:01:11 -0800 Subject: [PATCH 01/14] add errors to the interface --- runtime/interface.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/runtime/interface.go b/runtime/interface.go index 44109a420e..e9e66c83d5 100644 --- a/runtime/interface.go +++ b/runtime/interface.go @@ -41,7 +41,7 @@ type ResolvedLocation = sema.ResolvedLocation type Interface interface { // ResolveLocation resolves an import location. - ResolveLocation(identifiers []Identifier, location Location) []ResolvedLocation + ResolveLocation(identifiers []Identifier, location Location) ([]ResolvedLocation, error) // GetCode returns the code at a given location GetCode(location Location) ([]byte, error) // GetCachedProgram attempts to get a parsed program from a cache. @@ -65,26 +65,26 @@ type Interface interface { // RemoveAccountContractCode removes the code associated with an account contract. RemoveAccountContractCode(address Address, name string) (err error) // GetSigningAccounts returns the signing accounts. - GetSigningAccounts() []Address + GetSigningAccounts() ([]Address, error) // Log logs a string. - Log(string) + Log(string) error // EmitEvent is called when an event is emitted by the runtime. EmitEvent(cadence.Event) (err error) // ValueExists returns true if the given key exists in the storage, owned by the given account. ValueExists(owner, key []byte) (exists bool, err error) // GenerateUUID is called to generate a UUID. - GenerateUUID() uint64 + GenerateUUID() (uint64, error) // GetComputationLimit returns the computation limit. A value <= 0 means there is no limit GetComputationLimit() uint64 // DecodeArgument decodes a transaction argument against the given type. DecodeArgument(argument []byte, argumentType cadence.Type) (cadence.Value, error) // GetCurrentBlockHeight returns the current block height. - GetCurrentBlockHeight() uint64 + GetCurrentBlockHeight() (uint64, error) // GetBlockAtHeight returns the block at the given height. GetBlockAtHeight(height uint64) (block Block, exists bool, err error) // UnsafeRandom returns a random uint64, where the process of random number derivation is not cryptographically // secure. - UnsafeRandom() uint64 + UnsafeRandom() (uint64, error) // VerifySignature returns true if the given signature was produced by signing the given tag + data // using the given public key, signature algorithm, and hash algorithm. VerifySignature( @@ -94,9 +94,9 @@ type Interface interface { publicKey []byte, signatureAlgorithm string, hashAlgorithm string, - ) bool + ) (bool, error) // Hash returns the digest of hashing the given data with using the given hash algorithm - Hash(data []byte, hashAlgorithm string) []byte + Hash(data []byte, hashAlgorithm string) ([]byte, error) // GetStorageUsed gets storage used in bytes by the address at the moment of the function call. GetStorageUsed(address Address) (value uint64, err error) // GetStorageCapacity gets storage capacity in bytes on the address. @@ -240,10 +240,10 @@ func (i *EmptyRuntimeInterface) Hash( return nil } -func (i EmptyRuntimeInterface) GetStorageUsed(_ Address) (uint64,error) { +func (i EmptyRuntimeInterface) GetStorageUsed(_ Address) (uint64, error) { return 0, nil } -func (i EmptyRuntimeInterface) GetStorageCapacity(_ Address) (uint64,error) { +func (i EmptyRuntimeInterface) GetStorageCapacity(_ Address) (uint64, error) { return 0, nil } From 5de07954f9e712a401d49524c7865546f14d25d0 Mon Sep 17 00:00:00 2001 From: Ramtin Mehdizadeh Seraj Date: Wed, 25 Nov 2020 11:12:43 -0800 Subject: [PATCH 02/14] update the mocked interface --- runtime/runtime_test.go | 48 ++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/runtime/runtime_test.go b/runtime/runtime_test.go index e5095ceeef..582a1f3518 100644 --- a/runtime/runtime_test.go +++ b/runtime/runtime_test.go @@ -87,7 +87,7 @@ func newTestStorage( } type testRuntimeInterface struct { - resolveLocation func(identifiers []Identifier, location Location) []ResolvedLocation + resolveLocation func(identifiers []Identifier, location Location) ([]ResolvedLocation, error) getCode func(_ Location) ([]byte, error) getCachedProgram func(Location) (*ast.Program, error) cacheProgram func(Location, *ast.Program) error @@ -98,10 +98,10 @@ type testRuntimeInterface struct { updateAccountContractCode func(address Address, name string, code []byte) error getAccountContractCode func(address Address, name string) (code []byte, err error) removeAccountContractCode func(address Address, name string) (err error) - getSigningAccounts func() []Address + getSigningAccounts func() ([]Address, error) log func(string) emitEvent func(cadence.Event) error - generateUUID func() uint64 + generateUUID func() (uint64, error) computationLimit uint64 decodeArgument func(b []byte, t cadence.Type) (cadence.Value, error) programParsed func(location ast.Location, duration time.Duration) @@ -109,7 +109,7 @@ type testRuntimeInterface struct { programInterpreted func(location ast.Location, duration time.Duration) valueEncoded func(duration time.Duration) valueDecoded func(duration time.Duration) - unsafeRandom func() uint64 + unsafeRandom func() (uint64, error) verifySignature func( signature []byte, tag string, @@ -117,8 +117,8 @@ type testRuntimeInterface struct { publicKey []byte, signatureAlgorithm string, hashAlgorithm string, - ) bool - hash func(data []byte, hashAlgorithm string) []byte + ) (bool, error) + hash func(data []byte, hashAlgorithm string) ([]byte, error) setCadenceValue func(owner Address, key string, value cadence.Value) (err error) getStorageUsed func(_ Address) (uint64, error) getStorageCapacity func(_ Address) (uint64, error) @@ -126,14 +126,14 @@ type testRuntimeInterface struct { var _ Interface = &testRuntimeInterface{} -func (i *testRuntimeInterface) ResolveLocation(identifiers []Identifier, location Location) []ResolvedLocation { +func (i *testRuntimeInterface) ResolveLocation(identifiers []Identifier, location Location) ([]ResolvedLocation, error) { if i.resolveLocation == nil { return []ResolvedLocation{ { Location: location, Identifiers: identifiers, - }, - } + } + }, nil } return i.resolveLocation(identifiers, location) } @@ -195,9 +195,9 @@ func (i *testRuntimeInterface) RemoveAccountContractCode(address Address, name s return i.removeAccountContractCode(address, name) } -func (i *testRuntimeInterface) GetSigningAccounts() []Address { +func (i *testRuntimeInterface) GetSigningAccounts() ([]Address, error) { if i.getSigningAccounts == nil { - return nil + return nil, nil } return i.getSigningAccounts() } @@ -210,9 +210,9 @@ func (i *testRuntimeInterface) EmitEvent(event cadence.Event) error { return i.emitEvent(event) } -func (i *testRuntimeInterface) GenerateUUID() uint64 { +func (i *testRuntimeInterface) GenerateUUID() (uint64, error) { if i.generateUUID == nil { - return 0 + return 0, nil } return i.generateUUID() } @@ -260,8 +260,8 @@ func (i *testRuntimeInterface) ValueDecoded(duration time.Duration) { i.valueDecoded(duration) } -func (i *testRuntimeInterface) GetCurrentBlockHeight() uint64 { - return 1 +func (i *testRuntimeInterface) GetCurrentBlockHeight() (uint64, error) { + return 1, nil } func (i *testRuntimeInterface) GetBlockAtHeight(height uint64) (block Block, exists bool, err error) { @@ -285,11 +285,11 @@ func (i *testRuntimeInterface) GetBlockAtHeight(height uint64) (block Block, exi return block, true, nil } -func (i *testRuntimeInterface) UnsafeRandom() uint64 { +func (i *testRuntimeInterface) UnsafeRandom() (uint64, error){ if i.unsafeRandom == nil { - return 0 + return 0, nil } - return i.unsafeRandom() + return i.unsafeRandom(), nil } func (i *testRuntimeInterface) VerifySignature( @@ -299,9 +299,9 @@ func (i *testRuntimeInterface) VerifySignature( publicKey []byte, signatureAlgorithm string, hashAlgorithm string, -) bool { +) (bool, error) { if i.verifySignature == nil { - return false + return false, nil } return i.verifySignature( signature, @@ -310,14 +310,14 @@ func (i *testRuntimeInterface) VerifySignature( publicKey, signatureAlgorithm, hashAlgorithm, - ) + ), nil } -func (i *testRuntimeInterface) Hash(data []byte, hashAlgorithm string) []byte { +func (i *testRuntimeInterface) Hash(data []byte, hashAlgorithm string) ([]byte, error) { if i.hash == nil { - return nil + return nil, nil } - return i.hash(data, hashAlgorithm) + return i.hash(data, hashAlgorithm), nil } func (i *testRuntimeInterface) HighLevelStorageEnabled() bool { From 748ad6ed2d8bd43555e087e4c68e9a2c5862574f Mon Sep 17 00:00:00 2001 From: Ramtin Mehdizadeh Seraj Date: Wed, 25 Nov 2020 13:38:28 -0800 Subject: [PATCH 03/14] update interface and runtime --- runtime/interface.go | 34 ++++++++++++++++++---------------- runtime/runtime.go | 29 +++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/runtime/interface.go b/runtime/interface.go index e9e66c83d5..55c0097c74 100644 --- a/runtime/interface.go +++ b/runtime/interface.go @@ -69,7 +69,7 @@ type Interface interface { // Log logs a string. Log(string) error // EmitEvent is called when an event is emitted by the runtime. - EmitEvent(cadence.Event) (err error) + EmitEvent(cadence.Event) error // ValueExists returns true if the given key exists in the storage, owned by the given account. ValueExists(owner, key []byte) (exists bool, err error) // GenerateUUID is called to generate a UUID. @@ -127,13 +127,13 @@ type EmptyRuntimeInterface struct{} var _ Interface = &EmptyRuntimeInterface{} -func (i *EmptyRuntimeInterface) ResolveLocation(identifiers []Identifier, location Location) []ResolvedLocation { +func (i *EmptyRuntimeInterface) ResolveLocation(identifiers []Identifier, location Location) ([]ResolvedLocation, error) { return []ResolvedLocation{ { Location: location, Identifiers: identifiers, }, - } + }, nil } func (i *EmptyRuntimeInterface) GetCode(_ Location) ([]byte, error) { @@ -188,18 +188,20 @@ func (i *EmptyRuntimeInterface) RemoveAccountContractCode(_ Address, _ string) ( return nil } -func (i *EmptyRuntimeInterface) GetSigningAccounts() []Address { - return nil +func (i *EmptyRuntimeInterface) GetSigningAccounts() ([]Address, error) { + return nil, nil } -func (i *EmptyRuntimeInterface) Log(_ string) {} +func (i *EmptyRuntimeInterface) Log(_ string) error { + return nil +} func (i *EmptyRuntimeInterface) EmitEvent(_ cadence.Event) error { return nil } -func (i *EmptyRuntimeInterface) GenerateUUID() uint64 { - return 0 +func (i *EmptyRuntimeInterface) GenerateUUID() (uint64, error) { + return 0, nil } func (i *EmptyRuntimeInterface) GetComputationLimit() uint64 { @@ -210,16 +212,16 @@ func (i *EmptyRuntimeInterface) DecodeArgument(_ []byte, _ cadence.Type) (cadenc return nil, nil } -func (i *EmptyRuntimeInterface) GetCurrentBlockHeight() uint64 { - return 0 +func (i *EmptyRuntimeInterface) GetCurrentBlockHeight() (uint64, error) { + return 0, nil } func (i *EmptyRuntimeInterface) GetBlockAtHeight(_ uint64) (block Block, exists bool, err error) { return } -func (i *EmptyRuntimeInterface) UnsafeRandom() uint64 { - return 0 +func (i *EmptyRuntimeInterface) UnsafeRandom() (uint64, error) { + return 0, nil } func (i *EmptyRuntimeInterface) VerifySignature( @@ -229,15 +231,15 @@ func (i *EmptyRuntimeInterface) VerifySignature( _ []byte, _ string, _ string, -) bool { - return false +) (bool, error) { + return false, nil } func (i *EmptyRuntimeInterface) Hash( _ []byte, _ string, -) []byte { - return nil +) ([]byte, error) { + return nil, nil } func (i EmptyRuntimeInterface) GetStorageUsed(_ Address) (uint64, error) { diff --git a/runtime/runtime.go b/runtime/runtime.go index d0e904b8b6..e8d16ca09b 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -313,9 +313,11 @@ func (r *interpreterRuntime) ExecuteTransaction( var authorizers []Address wrapPanic(func() { - authorizers = runtimeInterface.GetSigningAccounts() + authorizers, err = runtimeInterface.GetSigningAccounts() }) - + if err != nil { + return newError(err) + } // check parameter count argumentCount := len(arguments) @@ -631,9 +633,9 @@ func (r *interpreterRuntime) newInterpreter( interpreter.WithInjectedCompositeFieldsHandler( r.injectedCompositeFieldsHandler(runtimeInterface, runtimeStorage), ), - interpreter.WithUUIDHandler(func() (uuid uint64) { + interpreter.WithUUIDHandler(func() (uuid uint64, err error) { wrapPanic(func() { - uuid = runtimeInterface.GenerateUUID() + uuid, err = runtimeInterface.GenerateUUID() }) return }), @@ -1312,10 +1314,14 @@ func (r *interpreterRuntime) newLogFunction(runtimeInterface Interface) interpre } } -func (r *interpreterRuntime) getCurrentBlockHeight(runtimeInterface Interface) (currentBlockHeight uint64) { +func (r *interpreterRuntime) getCurrentBlockHeight(runtimeInterface Interface) (currentBlockHeight uint64, err error) { + var er error wrapPanic(func() { - currentBlockHeight = runtimeInterface.GetCurrentBlockHeight() + currentBlockHeight, er = runtimeInterface.GetCurrentBlockHeight() }) + if er != nil { + err = newError(er) + } return } @@ -1343,7 +1349,10 @@ func (r *interpreterRuntime) getBlockAtHeight(height uint64, runtimeInterface In func (r *interpreterRuntime) newGetCurrentBlockFunction(runtimeInterface Interface) interpreter.HostFunction { return func(invocation interpreter.Invocation) trampoline.Trampoline { - height := r.getCurrentBlockHeight(runtimeInterface) + height, err := r.getCurrentBlockHeight(runtimeInterface) + if err != nil { + panic(err) + } block, err := r.getBlockAtHeight(height, runtimeInterface) if err != nil { panic(err) @@ -1372,9 +1381,13 @@ func (r *interpreterRuntime) newGetBlockFunction(runtimeInterface Interface) int func (r *interpreterRuntime) newUnsafeRandomFunction(runtimeInterface Interface) interpreter.HostFunction { return func(invocation interpreter.Invocation) trampoline.Trampoline { var rand uint64 + var err error wrapPanic(func() { - rand = runtimeInterface.UnsafeRandom() + rand, err = runtimeInterface.UnsafeRandom() }) + if err != nil { + panic(err) + } return trampoline.Done{Result: interpreter.UInt64Value(rand)} } } From 1d5e35a10070e4cf3b74230e7f146605c57fa36d Mon Sep 17 00:00:00 2001 From: Ramtin Mehdizadeh Seraj Date: Wed, 25 Nov 2020 14:19:43 -0800 Subject: [PATCH 04/14] panic on new errors --- runtime/runtime.go | 15 +++++++++++++-- runtime/stdlib/crypto.go | 15 +++++++++++---- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/runtime/runtime.go b/runtime/runtime.go index e8d16ca09b..550b22cfcf 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -542,7 +542,14 @@ func (r *interpreterRuntime) parseAndCheckProgram( sema.WithPredeclaredValues(valueDeclarations), sema.WithPredeclaredTypes(typeDeclarations), sema.WithValidTopLevelDeclarationsHandler(validTopLevelDeclarations), - sema.WithLocationHandler(runtimeInterface.ResolveLocation), + sema.WithLocationHandler(func(identifiers []Identifier, location Location) (res []ResolvedLocation) { + var err error + res, err = runtimeInterface.ResolveLocation(identifiers, location) + if err != nil { + panic(err) + } + return + }), sema.WithImportHandler(func(checker *sema.Checker, location ast.Location) (sema.Import, *sema.CheckerError) { switch location { case stdlib.CryptoChecker.Location: @@ -633,9 +640,13 @@ func (r *interpreterRuntime) newInterpreter( interpreter.WithInjectedCompositeFieldsHandler( r.injectedCompositeFieldsHandler(runtimeInterface, runtimeStorage), ), - interpreter.WithUUIDHandler(func() (uuid uint64, err error) { + interpreter.WithUUIDHandler(func() (uuid uint64) { wrapPanic(func() { + var err error uuid, err = runtimeInterface.GenerateUUID() + if err != nil { + panic(err) + } }) return }), diff --git a/runtime/stdlib/crypto.go b/runtime/stdlib/crypto.go index 25ceff0163..a421105fe5 100644 --- a/runtime/stdlib/crypto.go +++ b/runtime/stdlib/crypto.go @@ -21,14 +21,14 @@ type CryptoSignatureVerifier interface { publicKey []byte, signatureAlgorithm string, hashAlgorithm string, - ) bool + ) (bool, error) } type CryptoHasher interface { Hash( data []byte, hashAlgorithm string, - ) []byte + ) ([]byte, error) } var CryptoChecker = func() *sema.Checker { @@ -107,13 +107,16 @@ func newCryptoContractVerifySignatureFunction(signatureVerifier CryptoSignatureV } hashAlgorithm := hashAlgorithmStringValue.Str - isValid := signatureVerifier.VerifySignature(signature, + isValid, err := signatureVerifier.VerifySignature(signature, tag, signedData, publicKey, signatureAlgorithm, hashAlgorithm, ) + if err != nil { + panic(fmt.Errorf("VerifySignature: failed to verify the signature: %w", err)) + } return trampoline.Done{Result: interpreter.BoolValue(isValid)} }, @@ -153,7 +156,11 @@ func newCryptoContractHashFunction(hasher CryptoHasher) interpreter.FunctionValu } hashAlgorithm := hashAlgorithmStringValue.Str - digest := hasher.Hash(data, hashAlgorithm) + digest, err := hasher.Hash(data, hashAlgorithm) + if err != nil { + panic(fmt.Errorf("hash: hashing failed: %w", err)) + + } result := interpreter.ByteSliceToByteArrayValue(digest) From 4d302c170c8a81b8a160e3713c9fd055deea0ccd Mon Sep 17 00:00:00 2001 From: Ramtin Mehdizadeh Seraj Date: Wed, 25 Nov 2020 14:28:53 -0800 Subject: [PATCH 05/14] linkt love --- runtime/runtime_test.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/runtime/runtime_test.go b/runtime/runtime_test.go index 582a1f3518..f9b8a65e63 100644 --- a/runtime/runtime_test.go +++ b/runtime/runtime_test.go @@ -132,7 +132,7 @@ func (i *testRuntimeInterface) ResolveLocation(identifiers []Identifier, locatio { Location: location, Identifiers: identifiers, - } + }, }, nil } return i.resolveLocation(identifiers, location) @@ -261,7 +261,7 @@ func (i *testRuntimeInterface) ValueDecoded(duration time.Duration) { } func (i *testRuntimeInterface) GetCurrentBlockHeight() (uint64, error) { - return 1, nil + return 1, nil } func (i *testRuntimeInterface) GetBlockAtHeight(height uint64) (block Block, exists bool, err error) { @@ -285,7 +285,7 @@ func (i *testRuntimeInterface) GetBlockAtHeight(height uint64) (block Block, exi return block, true, nil } -func (i *testRuntimeInterface) UnsafeRandom() (uint64, error){ +func (i *testRuntimeInterface) UnsafeRandom() (uint64, error) { if i.unsafeRandom == nil { return 0, nil } @@ -2722,7 +2722,7 @@ func TestRuntimeContractNestedResource(t *testing.T) { accountCode = code return nil }, - emitEvent: func(event cadence.Event) error {return nil}, + emitEvent: func(event cadence.Event) error { return nil }, log: func(message string) { loggedMessage = message }, @@ -3891,7 +3891,7 @@ func TestInterpretResourceOwnerFieldUseDictionary(t *testing.T) { accountCodes[key] = code return nil }, - emitEvent: func(event cadence.Event) error{ + emitEvent: func(event cadence.Event) error { events = append(events, event) return nil }, @@ -4279,7 +4279,7 @@ func TestRuntimeContractWriteback(t *testing.T) { accountCode = code return nil }, - emitEvent: func(event cadence.Event) error{ + emitEvent: func(event cadence.Event) error { events = append(events, event) return nil }, @@ -4682,7 +4682,7 @@ func TestRuntimeUpdateCodeCaching(t *testing.T) { accountCodes[key] = code return nil }, - emitEvent: func(event cadence.Event) error{ + emitEvent: func(event cadence.Event) error { events = append(events, event) return nil }, From 58eab312c58f641d42d74d99329c119601d3f0ab Mon Sep 17 00:00:00 2001 From: Ramtin Mehdizadeh Seraj Date: Wed, 25 Nov 2020 14:30:49 -0800 Subject: [PATCH 06/14] add log error --- runtime/runtime_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/runtime/runtime_test.go b/runtime/runtime_test.go index f9b8a65e63..d2856af67d 100644 --- a/runtime/runtime_test.go +++ b/runtime/runtime_test.go @@ -202,8 +202,9 @@ func (i *testRuntimeInterface) GetSigningAccounts() ([]Address, error) { return i.getSigningAccounts() } -func (i *testRuntimeInterface) Log(message string) { +func (i *testRuntimeInterface) Log(message string) error { i.log(message) + return nil } func (i *testRuntimeInterface) EmitEvent(event cadence.Event) error { From b8febab4c759a63b015ac082e12d5fb7bcf9e45f Mon Sep 17 00:00:00 2001 From: Ramtin Mehdizadeh Seraj Date: Wed, 25 Nov 2020 14:47:36 -0800 Subject: [PATCH 07/14] fix tests --- runtime/contract_test.go | 12 +- runtime/crypto_test.go | 8 +- runtime/deferral_test.go | 28 ++-- runtime/runtime_test.go | 190 +++++++++++++------------- runtime/storage_test.go | 8 +- runtime/type_test.go | 4 +- runtime/untitled | 285 +++++++++++++++++++++++++++++++++++++++ 7 files changed, 410 insertions(+), 125 deletions(-) create mode 100644 runtime/untitled diff --git a/runtime/contract_test.go b/runtime/contract_test.go index 8d5bd5fd95..66b1c15466 100644 --- a/runtime/contract_test.go +++ b/runtime/contract_test.go @@ -134,8 +134,8 @@ func TestRuntimeContract(t *testing.T) { runtimeInterface := &testRuntimeInterface{ storage: storage, - getSigningAccounts: func() []Address { - return []Address{signerAddress} + getSigningAccounts: func() ([]Address, error) { + return []Address{signerAddress}, nil }, log: func(message string) { loggedMessages = append(loggedMessages, message) @@ -471,8 +471,8 @@ func TestRuntimeImportMultipleContracts(t *testing.T) { runtimeInterface := &testRuntimeInterface{ storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{common.BytesToAddress([]byte{0x1})} + getSigningAccounts: func() ([]Address, error) { + return []Address{common.BytesToAddress([]byte{0x1})}, nil }, updateAccountContractCode: func(address Address, name string, code []byte) error { key := contractKey{ @@ -498,7 +498,7 @@ func TestRuntimeImportMultipleContracts(t *testing.T) { delete(deployedContracts, key) return nil }, - resolveLocation: func(identifiers []ast.Identifier, location ast.Location) (result []sema.ResolvedLocation) { + resolveLocation: func(identifiers []ast.Identifier, location ast.Location) (result []sema.ResolvedLocation, err error) { // Resolve each identifier as an address location @@ -519,7 +519,7 @@ func TestRuntimeImportMultipleContracts(t *testing.T) { log: func(message string) { loggedMessages = append(loggedMessages, message) }, - emitEvent: func(event cadence.Event) error{ + emitEvent: func(event cadence.Event) error { events = append(events, event) return nil }, diff --git a/runtime/crypto_test.go b/runtime/crypto_test.go index bd995cf1ac..2281aad0be 100644 --- a/runtime/crypto_test.go +++ b/runtime/crypto_test.go @@ -99,7 +99,7 @@ func TestRuntimeCrypto_verify(t *testing.T) { publicKey []byte, signatureAlgorithm string, hashAlgorithm string, - ) bool { + ) (bool, error) { called = true assert.Equal(t, []byte{3, 4}, signature) assert.Equal(t, "user", tag) @@ -107,7 +107,7 @@ func TestRuntimeCrypto_verify(t *testing.T) { assert.Equal(t, []byte{1, 2}, publicKey) assert.Equal(t, "ECDSA_P256", signatureAlgorithm) assert.Equal(t, "SHA3_256", hashAlgorithm) - return true + return true, nil }, } @@ -145,11 +145,11 @@ func TestRuntimeCrypto_hash(t *testing.T) { hash: func( data []byte, hashAlgorithm string, - ) []byte { + ) ([]byte, error) { called = true assert.Equal(t, []byte{1, 2, 3, 4}, data) assert.Equal(t, "SHA3_256", hashAlgorithm) - return []byte{5, 6, 7, 8} + return []byte{5, 6, 7, 8}, nil }, log: func(message string) { loggedMessages = append(loggedMessages, message) diff --git a/runtime/deferral_test.go b/runtime/deferral_test.go index 58ed373b6e..33cad28b97 100644 --- a/runtime/deferral_test.go +++ b/runtime/deferral_test.go @@ -138,8 +138,8 @@ func TestRuntimeStorageDeferredResourceDictionaryValues(t *testing.T) { return accountCode, nil }, storage: newTestStorage(onRead, onWrite), - getSigningAccounts: func() []Address { - return []Address{common.BytesToAddress(addressValue.Bytes())} + getSigningAccounts: func() ([]Address, error) { + return []Address{common.BytesToAddress(addressValue.Bytes())}, nil }, updateAccountContractCode: func(_ Address, _ string, code []byte) error { accountCode = code @@ -623,8 +623,8 @@ func TestRuntimeStorageDeferredResourceDictionaryValues_Nested(t *testing.T) { return accountCode, nil }, storage: newTestStorage(onRead, onWrite), - getSigningAccounts: func() []Address { - return []Address{common.BytesToAddress(addressValue.Bytes())} + getSigningAccounts: func() ([]Address, error) { + return []Address{common.BytesToAddress(addressValue.Bytes())}, nil }, updateAccountContractCode: func(_ Address, _ string, code []byte) error { accountCode = code @@ -856,11 +856,11 @@ func TestRuntimeStorageDeferredResourceDictionaryValues_DictionaryTransfer(t *te return accountCode, nil }, storage: newTestStorage(onRead, onWrite), - getSigningAccounts: func() []Address { + getSigningAccounts: func() ([]Address, error) { return []Address{ signer1, signer2, - } + }, nil }, resolveLocation: singleIdentifierLocationResolver(t), getAccountContractCode: func(_ Address, _ string) (code []byte, err error) { @@ -1013,8 +1013,8 @@ func TestRuntimeStorageDeferredResourceDictionaryValues_Removal(t *testing.T) { return accountCode, nil }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{signer} + getSigningAccounts: func() ([]Address, error) { + return []Address{signer}, nil }, resolveLocation: singleIdentifierLocationResolver(t), getAccountContractCode: func(_ Address, _ string) (code []byte, err error) { @@ -1095,8 +1095,8 @@ func TestRuntimeStorageDeferredResourceDictionaryValues_Destruction(t *testing.T return accountCode, nil }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{signer} + getSigningAccounts: func() ([]Address, error) { + return []Address{signer}, nil }, resolveLocation: singleIdentifierLocationResolver(t), getAccountContractCode: func(_ Address, _ string) (code []byte, err error) { @@ -1211,8 +1211,8 @@ func TestRuntimeStorageDeferredResourceDictionaryValues_Insertion(t *testing.T) return accountCode, nil }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{signer} + getSigningAccounts: func() ([]Address, error) { + return []Address{signer}, nil }, resolveLocation: singleIdentifierLocationResolver(t), getAccountContractCode: func(_ Address, _ string) (code []byte, err error) { @@ -1330,8 +1330,8 @@ func TestRuntimeStorageDeferredResourceDictionaryValues_ValueTransferAndDestroy( return accountCode, nil }, storage: testStorage, - getSigningAccounts: func() []Address { - return signers + getSigningAccounts: func() ([]Address, error) { + return signers, nil }, resolveLocation: singleIdentifierLocationResolver(t), getAccountContractCode: func(_ Address, _ string) (code []byte, err error) { diff --git a/runtime/runtime_test.go b/runtime/runtime_test.go index d2856af67d..1f1461f067 100644 --- a/runtime/runtime_test.go +++ b/runtime/runtime_test.go @@ -290,7 +290,7 @@ func (i *testRuntimeInterface) UnsafeRandom() (uint64, error) { if i.unsafeRandom == nil { return 0, nil } - return i.unsafeRandom(), nil + return i.unsafeRandom() } func (i *testRuntimeInterface) VerifySignature( @@ -311,14 +311,14 @@ func (i *testRuntimeInterface) VerifySignature( publicKey, signatureAlgorithm, hashAlgorithm, - ), nil + ) } func (i *testRuntimeInterface) Hash(data []byte, hashAlgorithm string) ([]byte, error) { if i.hash == nil { return nil, nil } - return i.hash(data, hashAlgorithm), nil + return i.hash(data, hashAlgorithm) } func (i *testRuntimeInterface) HighLevelStorageEnabled() bool { @@ -509,8 +509,8 @@ func TestRuntimeInvalidTransactionArgumentAccount(t *testing.T) { `) runtimeInterface := &testRuntimeInterface{ - getSigningAccounts: func() []Address { - return []Address{{42}} + getSigningAccounts: func() ([]Address, error) { + return []Address{{42}}, nil }, } @@ -537,10 +537,10 @@ func TestRuntimeTransactionWithAccount(t *testing.T) { var loggedMessage string runtimeInterface := &testRuntimeInterface{ - getSigningAccounts: func() []Address { + getSigningAccounts: func() ([]Address, error) { return []Address{ common.BytesToAddress([]byte{42}), - } + }, nil }, log: func(message string) { loggedMessage = message @@ -823,7 +823,7 @@ func TestRuntimeTransactionWithArguments(t *testing.T) { var loggedMessages []string runtimeInterface := &testRuntimeInterface{ - getSigningAccounts: func() []Address { return tt.authorizers }, + getSigningAccounts: func() ([]Address, error) { return tt.authorizers, nil }, decodeArgument: func(b []byte, t cadence.Type) (cadence.Value, error) { return jsoncdc.Decode(b) }, @@ -1273,8 +1273,8 @@ func TestRuntimeStorage(t *testing.T) { } }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{{42}} + getSigningAccounts: func() ([]Address, error) { + return []Address{{42}}, nil }, log: func(message string) { loggedMessages = append(loggedMessages, message) @@ -1368,8 +1368,8 @@ func TestRuntimeStorageMultipleTransactionsResourceWithArray(t *testing.T) { } }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{{42}} + getSigningAccounts: func() ([]Address, error) { + return []Address{{42}}, nil }, log: func(message string) { loggedMessages = append(loggedMessages, message) @@ -1444,8 +1444,8 @@ func TestRuntimeStorageMultipleTransactionsResourceFunction(t *testing.T) { } }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{{42}} + getSigningAccounts: func() ([]Address, error) { + return []Address{{42}}, nil }, log: func(message string) { loggedMessages = append(loggedMessages, message) @@ -1520,8 +1520,8 @@ func TestRuntimeStorageMultipleTransactionsResourceField(t *testing.T) { } }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{{42}} + getSigningAccounts: func() ([]Address, error) { + return []Address{{42}}, nil }, log: func(message string) { loggedMessages = append(loggedMessages, message) @@ -1597,8 +1597,8 @@ func TestRuntimeCompositeFunctionInvocationFromImportingProgram(t *testing.T) { } }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{{42}} + getSigningAccounts: func() ([]Address, error) { + return []Address{{42}}, nil }, } @@ -1664,8 +1664,8 @@ func TestRuntimeResourceContractUseThroughReference(t *testing.T) { } }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{{42}} + getSigningAccounts: func() ([]Address, error) { + return []Address{{42}}, nil }, log: func(message string) { loggedMessages = append(loggedMessages, message) @@ -1739,8 +1739,8 @@ func TestRuntimeResourceContractUseThroughLink(t *testing.T) { } }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{{42}} + getSigningAccounts: func() ([]Address, error) { + return []Address{{42}}, nil }, log: func(message string) { loggedMessages = append(loggedMessages, message) @@ -1828,8 +1828,8 @@ func TestRuntimeResourceContractWithInterface(t *testing.T) { } }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{{42}} + getSigningAccounts: func() ([]Address, error) { + return []Address{{42}}, nil }, log: func(message string) { loggedMessages = append(loggedMessages, message) @@ -1897,8 +1897,8 @@ func TestScriptReturnTypeNotReturnableError(t *testing.T) { runtime := NewInterpreterRuntime() runtimeInterface := &testRuntimeInterface{ - getSigningAccounts: func() []Address { - return []Address{{42}} + getSigningAccounts: func() ([]Address, error) { + return []Address{{42}}, nil }, } @@ -1979,8 +1979,8 @@ func TestScriptParameterTypeNotStorableError(t *testing.T) { `) runtimeInterface := &testRuntimeInterface{ - getSigningAccounts: func() []Address { - return []Address{{42}} + getSigningAccounts: func() ([]Address, error) { + return []Address{{42}}, nil }, } @@ -2003,8 +2003,8 @@ func TestRuntimeSyntaxError(t *testing.T) { `) runtimeInterface := &testRuntimeInterface{ - getSigningAccounts: func() []Address { - return []Address{{42}} + getSigningAccounts: func() ([]Address, error) { + return []Address{{42}}, nil }, } @@ -2070,8 +2070,8 @@ func TestRuntimeStorageChanges(t *testing.T) { } }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{{42}} + getSigningAccounts: func() ([]Address, error) { + return []Address{{42}}, nil }, log: func(message string) { loggedMessages = append(loggedMessages, message) @@ -2108,8 +2108,8 @@ func TestRuntimeAccountAddress(t *testing.T) { address := common.BytesToAddress([]byte{42}) runtimeInterface := &testRuntimeInterface{ - getSigningAccounts: func() []Address { - return []Address{address} + getSigningAccounts: func() ([]Address, error) { + return []Address{address}, nil }, log: func(message string) { loggedMessages = append(loggedMessages, message) @@ -2143,8 +2143,8 @@ func TestRuntimePublicAccountAddress(t *testing.T) { address := interpreter.NewAddressValueFromBytes([]byte{0x42}) runtimeInterface := &testRuntimeInterface{ - getSigningAccounts: func() []Address { - return nil + getSigningAccounts: func() ([]Address, error) { + return nil, nil }, log: func(message string) { loggedMessages = append(loggedMessages, message) @@ -2218,8 +2218,8 @@ func TestRuntimeAccountPublishAndAccess(t *testing.T) { } }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{address} + getSigningAccounts: func() ([]Address, error) { + return []Address{address}, nil }, log: func(message string) { loggedMessages = append(loggedMessages, message) @@ -2255,8 +2255,8 @@ func TestRuntimeTransaction_CreateAccount(t *testing.T) { runtimeInterface := &testRuntimeInterface{ storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{{42}} + getSigningAccounts: func() ([]Address, error) { + return []Address{{42}}, nil }, createAccount: func(payer Address) (address Address, err error) { return Address{42}, nil @@ -2342,8 +2342,8 @@ func TestRuntimeTransaction_AddPublicKey(t *testing.T) { runtimeInterface := &testRuntimeInterface{ storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{{42}} + getSigningAccounts: func() ([]Address, error) { + return []Address{{42}}, nil }, createAccount: func(payer Address) (address Address, err error) { return Address{42}, nil @@ -2541,8 +2541,8 @@ func TestRuntimeTransactionWithContractDeployment(t *testing.T) { runtimeInterface := &testRuntimeInterface{ storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{{42}} + getSigningAccounts: func() ([]Address, error) { + return []Address{{42}}, nil }, getAccountContractCode: func(_ Address, _ string) (code []byte, err error) { return accountCode, nil @@ -2625,8 +2625,8 @@ func TestRuntimeContractAccount(t *testing.T) { return accountCode, nil }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{common.BytesToAddress(addressValue.Bytes())} + getSigningAccounts: func() ([]Address, error) { + return []Address{common.BytesToAddress(addressValue.Bytes())}, nil }, resolveLocation: singleIdentifierLocationResolver(t), getAccountContractCode: func(_ Address, _ string) (code []byte, err error) { @@ -2712,8 +2712,8 @@ func TestRuntimeContractNestedResource(t *testing.T) { return accountCode, nil }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{addressValue} + getSigningAccounts: func() ([]Address, error) { + return []Address{addressValue}, nil }, resolveLocation: singleIdentifierLocationResolver(t), getAccountContractCode: func(_ Address, _ string) (code []byte, err error) { @@ -2908,8 +2908,8 @@ func TestRuntimeFungibleTokenUpdateAccountCode(t *testing.T) { return accountCodes[key], nil }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{signerAccount} + getSigningAccounts: func() ([]Address, error) { + return []Address{signerAccount}, nil }, resolveLocation: singleIdentifierLocationResolver(t), getAccountContractCode: func(address Address, name string) (code []byte, err error) { @@ -3032,8 +3032,8 @@ func TestRuntimeFungibleTokenCreateAccount(t *testing.T) { createAccount: func(payer Address) (address Address, err error) { return address2Value, nil }, - getSigningAccounts: func() []Address { - return []Address{signerAccount} + getSigningAccounts: func() ([]Address, error) { + return []Address{signerAccount}, nil }, resolveLocation: singleIdentifierLocationResolver(t), getAccountContractCode: func(address Address, name string) (code []byte, err error) { @@ -3174,8 +3174,8 @@ func TestRuntimeInvokeStoredInterfaceFunction(t *testing.T) { nextAccount++ return result.ToAddress(), nil }, - getSigningAccounts: func() []Address { - return []Address{{0x1}} + getSigningAccounts: func() ([]Address, error) { + return []Address{{0x1}}, nil }, resolveLocation: singleIdentifierLocationResolver(t), getAccountContractCode: func(address Address, name string) (code []byte, err error) { @@ -3280,8 +3280,8 @@ func TestRuntimeBlock(t *testing.T) { var loggedMessages []string runtimeInterface := &testRuntimeInterface{ - getSigningAccounts: func() []Address { - return nil + getSigningAccounts: func() ([]Address, error) { + return nil, nil }, log: func(message string) { loggedMessages = append(loggedMessages, message) @@ -3328,8 +3328,8 @@ func TestUnsafeRandom(t *testing.T) { var loggedMessages []string runtimeInterface := &testRuntimeInterface{ - unsafeRandom: func() uint64 { - return 7558174677681708339 + unsafeRandom: func() (uint64, error) { + return 7558174677681708339, nil }, log: func(message string) { loggedMessages = append(loggedMessages, message) @@ -3363,8 +3363,8 @@ func TestRuntimeTransactionTopLevelDeclarations(t *testing.T) { `) runtimeInterface := &testRuntimeInterface{ - getSigningAccounts: func() []Address { - return nil + getSigningAccounts: func() ([]Address, error) { + return nil, nil }, } @@ -3384,8 +3384,8 @@ func TestRuntimeTransactionTopLevelDeclarations(t *testing.T) { `) runtimeInterface := &testRuntimeInterface{ - getSigningAccounts: func() []Address { - return nil + getSigningAccounts: func() ([]Address, error) { + return nil, nil }, } @@ -3445,8 +3445,8 @@ func TestRuntimeStoreIntegerTypes(t *testing.T) { return accountCode, nil }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{addressValue.ToAddress()} + getSigningAccounts: func() ([]Address, error) { + return []Address{addressValue.ToAddress()}, nil }, getAccountContractCode: func(_ Address, _ string) (code []byte, err error) { return accountCode, nil @@ -3554,8 +3554,8 @@ func TestInterpretResourceOwnerFieldUseComposite(t *testing.T) { return accountCodes[key], nil }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{address} + getSigningAccounts: func() ([]Address, error) { + return []Address{address}, nil }, resolveLocation: singleIdentifierLocationResolver(t), getAccountContractCode: func(address Address, name string) (code []byte, err error) { @@ -3710,8 +3710,8 @@ func TestInterpretResourceOwnerFieldUseArray(t *testing.T) { return accountCodes[key], nil }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{address} + getSigningAccounts: func() ([]Address, error) { + return []Address{address}, nil }, getAccountContractCode: func(address Address, name string) (code []byte, err error) { location := AddressLocation{ @@ -3871,8 +3871,8 @@ func TestInterpretResourceOwnerFieldUseDictionary(t *testing.T) { return accountCodes[key], nil }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{address} + getSigningAccounts: func() ([]Address, error) { + return []Address{address}, nil }, resolveLocation: singleIdentifierLocationResolver(t), getAccountContractCode: func(address Address, name string) (code []byte, err error) { @@ -4002,8 +4002,8 @@ func TestRuntimeComputationLimit(t *testing.T) { runtime := NewInterpreterRuntime() runtimeInterface := &testRuntimeInterface{ - getSigningAccounts: func() []Address { - return nil + getSigningAccounts: func() ([]Address, error) { + return nil, nil }, computationLimit: computationLimit, } @@ -4097,8 +4097,8 @@ func TestRuntimeMetrics(t *testing.T) { runtimeInterface = &testRuntimeInterface{ storage: storage, - getSigningAccounts: func() []Address { - return []Address{{42}} + getSigningAccounts: func() ([]Address, error) { + return []Address{{42}}, nil }, getCode: func(location Location) (bytes []byte, err error) { switch location { @@ -4269,8 +4269,8 @@ func TestRuntimeContractWriteback(t *testing.T) { return accountCode, nil }, storage: newTestStorage(nil, onWrite), - getSigningAccounts: func() []Address { - return []Address{common.BytesToAddress(addressValue.Bytes())} + getSigningAccounts: func() ([]Address, error) { + return []Address{common.BytesToAddress(addressValue.Bytes())}, nil }, resolveLocation: singleIdentifierLocationResolver(t), getAccountContractCode: func(_ Address, _ string) (code []byte, err error) { @@ -4367,8 +4367,8 @@ func TestRuntimeStorageWriteback(t *testing.T) { return accountCode, nil }, storage: newTestStorage(nil, onWrite), - getSigningAccounts: func() []Address { - return []Address{common.BytesToAddress(addressValue.Bytes())} + getSigningAccounts: func() ([]Address, error) { + return []Address{common.BytesToAddress(addressValue.Bytes())}, nil }, resolveLocation: singleIdentifierLocationResolver(t), getAccountContractCode: func(_ Address, _ string) (code []byte, err error) { @@ -4452,8 +4452,8 @@ func TestRuntimeExternalError(t *testing.T) { type logPanic struct{} runtimeInterface := &testRuntimeInterface{ - getSigningAccounts: func() []Address { - return nil + getSigningAccounts: func() ([]Address, error) { + return nil, nil }, log: func(message string) { panic(logPanic{}) @@ -4539,8 +4539,8 @@ func TestRuntimeDeployCodeCaching(t *testing.T) { return cachedPrograms[location.ID()], nil }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return signerAddresses + getSigningAccounts: func() ([]Address, error) { + return signerAddresses, nil }, resolveLocation: singleIdentifierLocationResolver(t), getAccountContractCode: func(address Address, name string) (code []byte, err error) { @@ -4662,8 +4662,8 @@ func TestRuntimeUpdateCodeCaching(t *testing.T) { return cachedPrograms[location.ID()], nil }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return signerAddresses + getSigningAccounts: func() ([]Address, error) { + return signerAddresses, nil }, resolveLocation: singleIdentifierLocationResolver(t), getAccountContractCode: func(address Address, name string) (code []byte, err error) { @@ -4804,8 +4804,8 @@ func TestRuntimeNoCacheHitForToplevelPrograms(t *testing.T) { return cachedPrograms[location.ID()], nil }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return signerAddresses + getSigningAccounts: func() ([]Address, error) { + return signerAddresses, nil }, resolveLocation: singleIdentifierLocationResolver(t), getAccountContractCode: func(address Address, name string) (code []byte, err error) { @@ -4950,13 +4950,13 @@ func TestRuntimeTransaction_ContractUpdate(t *testing.T) { runtimeInterface := &testRuntimeInterface{ storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{common.BytesToAddress([]byte{0x42})} + getSigningAccounts: func() ([]Address, error) { + return []Address{common.BytesToAddress([]byte{0x42})}, nil }, getCode: func(_ Location) (bytes []byte, err error) { return accountCode, nil }, - resolveLocation: func(identifiers []Identifier, location Location) []ResolvedLocation { + resolveLocation: func(identifiers []Identifier, location Location) ([]ResolvedLocation, error) { require.Empty(t, identifiers) require.IsType(t, AddressLocation{}, location) @@ -4972,7 +4972,7 @@ func TestRuntimeTransaction_ContractUpdate(t *testing.T) { }, }, }, - } + }, nil }, getAccountContractCode: func(_ Address, _ string) (code []byte, err error) { return accountCode, nil @@ -5104,8 +5104,8 @@ func TestRuntime(t *testing.T) { } } -func singleIdentifierLocationResolver(t *testing.T) func(identifiers []Identifier, location Location) []ResolvedLocation { - return func(identifiers []Identifier, location Location) []ResolvedLocation { +func singleIdentifierLocationResolver(t *testing.T) func(identifiers []Identifier, location Location) ([]ResolvedLocation, error) { + return func(identifiers []Identifier, location Location) ([]ResolvedLocation, error) { require.Len(t, identifiers, 1) require.IsType(t, AddressLocation{}, location) @@ -5117,7 +5117,7 @@ func singleIdentifierLocationResolver(t *testing.T) func(identifiers []Identifie }, Identifiers: identifiers, }, - } + }, nil } } @@ -5134,8 +5134,8 @@ func TestPanics(t *testing.T) { `) runtimeInterface := &testRuntimeInterface{ - getSigningAccounts: func() []Address { - return []Address{{42}} + getSigningAccounts: func() ([]Address, error) { + return []Address{{42}}, nil }, } diff --git a/runtime/storage_test.go b/runtime/storage_test.go index 2a8239cc1d..1586eb06f1 100644 --- a/runtime/storage_test.go +++ b/runtime/storage_test.go @@ -102,8 +102,8 @@ func TestRuntimeHighLevelStorage(t *testing.T) { return accountCode, nil }, storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { - return []Address{address} + getSigningAccounts: func() ([]Address, error) { + return []Address{address}, nil }, resolveLocation: singleIdentifierLocationResolver(t), getAccountContractCode: func(_ Address, _ string) (code []byte, err error) { @@ -258,8 +258,8 @@ func TestRuntimeMagic(t *testing.T) { runtimeInterface := &testRuntimeInterface{ storage: newTestStorage(nil, onWrite), - getSigningAccounts: func() []Address { - return []Address{address} + getSigningAccounts: func() ([]Address, error) { + return []Address{address}, nil }, } diff --git a/runtime/type_test.go b/runtime/type_test.go index 90e1be67ed..3f0b7f0025 100644 --- a/runtime/type_test.go +++ b/runtime/type_test.go @@ -54,10 +54,10 @@ func TestRuntimeTypeStorage(t *testing.T) { runtimeInterface := &testRuntimeInterface{ storage: newTestStorage(nil, nil), - getSigningAccounts: func() []Address { + getSigningAccounts: func() ([]Address, error) { return []Address{ common.BytesToAddress([]byte{42}), - } + }, nil }, log: func(message string) { loggedMessage = message diff --git a/runtime/untitled b/runtime/untitled new file mode 100644 index 0000000000..b856fe3618 --- /dev/null +++ b/runtime/untitled @@ -0,0 +1,285 @@ +hostEnv + + Set limits on these + + + events + how to compute size of cadence.Size ? + logs + + + + Add Size to Value + - for operation size + + or Size of Encoded event (bytes) ? + + + +External errors are reported by the runtime but originate from the VM. + - ExternalError? + + +Issues +- before we used to panic for not supported methods +- GetSigningAccounts needs to return error +- GetCurrentBlockHeight needs to return error +- UnsafeRandom needs to return error + + +User Level errors + - MethodNotSupportedError + - AccountNotFoundError + - "account not found" + - AccountAlreadyExist + - account with address %s already exists + - AccountCodeNotFoundError + + + + - AuthorizationFailed (requires some authorization) + - code deployment requires authorization from the service account + + + + - ContractNotExistError + + + - AccountPublicKeyNotFoundError + "account public key not found" + - AccountPublicKeyIsRevokedError + - CorruptedAccountError (parsing a value like key counts) + - decoding values from ledger + + - InvalidPublicKeyError + + - BlockNotFound + + + - cannot decode runtime public account key + + + + + // key index must be positve, received %d -> we should change it to unsigned int + +|---------| +| | +|_________| + + +Panic and recover? + + TODO add CBOR errors (max limits) + +fatal errors (Failure) + LedgerFailure + -> - e.g. state not found (is not a failure for scripts ) + - cannot retreive previous contract: %w + - cannot retrieve current contract names: + + - UUIDGeneratorFailure + + + - BadgerFailure + - unexpected failure of GetBlockAtHeight, height %v: %w + + + + - CBOREncodingError + cannot encode contract names + + - CBORDecodeError + cannot decode deployed contract names %x: %w + + - RLPEncodingFailed (rlp.EncodeToBytes(&w)) + + + - cache error ? + + - DataDecodingFailed + expectedType + value + + e.g. retrieved public key account count bytes (hex-encoded): %x do not represent valid uint64 + + + + + + + + +Unknown + - can only get code for an account contract (an AddressLocation) + + + + + + +Interface Errors (user errors) + + // transaction data + - ResolveLocation ??? + - GetCode ??? / resolveImport + - (user errors) account error + - invalid address + - account not exists + - register not exist (no code deployed at address %d) + + - failure errors + - failed to read key %s on account %s: %w + - ledger error / trie not found + + - GetSigningAccounts + - (user level) not supported by this environment + - no fatal error is defined + + - GetComputationLimit() + - it returns tx level limit if non set it uses the global one + - no error needed + + // Cache + - CacheProgram error + - GetCachedProgram error + - ASTCache errors + + // ledger interactions + - SetValue + - same here + + - GetValue + - leger.Get errors needs to be translated + + - ValueExists + + + + // account managment + - CreateAccount + - (User Error) CreateAccount is not supported by this environment + - failures ?CreateAccount + - invokeMetaTransaction ???? + + + - AddAccountKey + - user error - account not exist + - user error - cannot decode runtime public account key: %w + - user error - invalid public key + - user error - max limit on keys + - user error - storage exceeded + - user error - CorruptedAccount (key count parsing) + + - fatal - ledger error + + + - failed to add public key to account: %w + + - RemoveAccountKey + - user error - account not exist + - user error - key not exist + - user error - key is already revoked + + - UpdateAccountContractCode + - cannot retreive previous code + + - GetAccountContractCode + - cannot retreive previous code + + - RemoveAccountContractCode + + + + - ResolveImport ??? + GetCode + no code deployed at address %s + + + - GetStorageUsed + - GetStorageCapacity + + // log + Log + - LogLimitError (user) + Logs() + - same as events + + Events returns errors + - only fatal ones if needed + + EmitEvent(cadence.Event) + - EventLimitError (user) + - EncodingError (user) - can we set limits ???? + + // env helper methods + GenerateUUID + - panic, cannot generate UUID + - no user errors + + DecodeArgument + - (user level) DecodeError is needed , TODO look at jsoncdc.Decode errors + GetCurrentBlockHeight + - Panic - BlockHeader == nil (GetCurrentBlockHeight is not supported by this environment) + - TODO should ^ be panic ? what about this call in scripts + + GetBlockAtHeight + - (user error) not supported + - what if it doesn't exist ??? + + -> GetBlockAtHeight do we really need this? + - should it be parents allowed only ? + + + + UnsafeRandom + + + VerifySignature + - this is the big one + - TODO look at errors return from the verifySignatureFromRuntime + + + > User errors + > DecodePublicKey + > Invalid Hash function (error) + > false, error : invalid domain tag + > verify results + + + Hash + + + HighLevelStorageEnabled ??? + SetCadenceValue ??? + + +hostEnv + + +Address generator errors + + + +What to measure as event size ? + - Cadence Values + - Encoded event + + + + +Cadence errors + - RunTimeErrors + - ComputationLimitExceededError + + +Transaction Errors + - ????? + + Can have a cadence error + - wrap an account error / sign verify error + + Execution Failed + + +VM Fatal errors () \ No newline at end of file From 1adf02ccf20ebf5f4ae065b0be16b62694291d78 Mon Sep 17 00:00:00 2001 From: Ramtin Mehdizadeh Seraj Date: Wed, 25 Nov 2020 14:49:51 -0800 Subject: [PATCH 08/14] clean up --- runtime/untitled | 285 ----------------------------------------------- 1 file changed, 285 deletions(-) delete mode 100644 runtime/untitled diff --git a/runtime/untitled b/runtime/untitled deleted file mode 100644 index b856fe3618..0000000000 --- a/runtime/untitled +++ /dev/null @@ -1,285 +0,0 @@ -hostEnv - - Set limits on these - - - events - how to compute size of cadence.Size ? - logs - - - - Add Size to Value - - for operation size - - or Size of Encoded event (bytes) ? - - - -External errors are reported by the runtime but originate from the VM. - - ExternalError? - - -Issues -- before we used to panic for not supported methods -- GetSigningAccounts needs to return error -- GetCurrentBlockHeight needs to return error -- UnsafeRandom needs to return error - - -User Level errors - - MethodNotSupportedError - - AccountNotFoundError - - "account not found" - - AccountAlreadyExist - - account with address %s already exists - - AccountCodeNotFoundError - - - - - AuthorizationFailed (requires some authorization) - - code deployment requires authorization from the service account - - - - - ContractNotExistError - - - - AccountPublicKeyNotFoundError - "account public key not found" - - AccountPublicKeyIsRevokedError - - CorruptedAccountError (parsing a value like key counts) - - decoding values from ledger - - - InvalidPublicKeyError - - - BlockNotFound - - - - cannot decode runtime public account key - - - - - // key index must be positve, received %d -> we should change it to unsigned int - -|---------| -| | -|_________| - - -Panic and recover? - - TODO add CBOR errors (max limits) - -fatal errors (Failure) - LedgerFailure - -> - e.g. state not found (is not a failure for scripts ) - - cannot retreive previous contract: %w - - cannot retrieve current contract names: - - - UUIDGeneratorFailure - - - - BadgerFailure - - unexpected failure of GetBlockAtHeight, height %v: %w - - - - - CBOREncodingError - cannot encode contract names - - - CBORDecodeError - cannot decode deployed contract names %x: %w - - - RLPEncodingFailed (rlp.EncodeToBytes(&w)) - - - - cache error ? - - - DataDecodingFailed - expectedType - value - - e.g. retrieved public key account count bytes (hex-encoded): %x do not represent valid uint64 - - - - - - - - -Unknown - - can only get code for an account contract (an AddressLocation) - - - - - - -Interface Errors (user errors) - - // transaction data - - ResolveLocation ??? - - GetCode ??? / resolveImport - - (user errors) account error - - invalid address - - account not exists - - register not exist (no code deployed at address %d) - - - failure errors - - failed to read key %s on account %s: %w - - ledger error / trie not found - - - GetSigningAccounts - - (user level) not supported by this environment - - no fatal error is defined - - - GetComputationLimit() - - it returns tx level limit if non set it uses the global one - - no error needed - - // Cache - - CacheProgram error - - GetCachedProgram error - - ASTCache errors - - // ledger interactions - - SetValue - - same here - - - GetValue - - leger.Get errors needs to be translated - - - ValueExists - - - - // account managment - - CreateAccount - - (User Error) CreateAccount is not supported by this environment - - failures ?CreateAccount - - invokeMetaTransaction ???? - - - - AddAccountKey - - user error - account not exist - - user error - cannot decode runtime public account key: %w - - user error - invalid public key - - user error - max limit on keys - - user error - storage exceeded - - user error - CorruptedAccount (key count parsing) - - - fatal - ledger error - - - - failed to add public key to account: %w - - - RemoveAccountKey - - user error - account not exist - - user error - key not exist - - user error - key is already revoked - - - UpdateAccountContractCode - - cannot retreive previous code - - - GetAccountContractCode - - cannot retreive previous code - - - RemoveAccountContractCode - - - - - ResolveImport ??? - GetCode - no code deployed at address %s - - - - GetStorageUsed - - GetStorageCapacity - - // log - Log - - LogLimitError (user) - Logs() - - same as events - - Events returns errors - - only fatal ones if needed - - EmitEvent(cadence.Event) - - EventLimitError (user) - - EncodingError (user) - can we set limits ???? - - // env helper methods - GenerateUUID - - panic, cannot generate UUID - - no user errors - - DecodeArgument - - (user level) DecodeError is needed , TODO look at jsoncdc.Decode errors - GetCurrentBlockHeight - - Panic - BlockHeader == nil (GetCurrentBlockHeight is not supported by this environment) - - TODO should ^ be panic ? what about this call in scripts - - GetBlockAtHeight - - (user error) not supported - - what if it doesn't exist ??? - - -> GetBlockAtHeight do we really need this? - - should it be parents allowed only ? - - - - UnsafeRandom - - - VerifySignature - - this is the big one - - TODO look at errors return from the verifySignatureFromRuntime - - - > User errors - > DecodePublicKey - > Invalid Hash function (error) - > false, error : invalid domain tag - > verify results - - - Hash - - - HighLevelStorageEnabled ??? - SetCadenceValue ??? - - -hostEnv - - -Address generator errors - - - -What to measure as event size ? - - Cadence Values - - Encoded event - - - - -Cadence errors - - RunTimeErrors - - ComputationLimitExceededError - - -Transaction Errors - - ????? - - Can have a cadence error - - wrap an account error / sign verify error - - Execution Failed - - -VM Fatal errors () \ No newline at end of file From bcdbe3d0c611313fd9c817b4a5b76ca329e0cd67 Mon Sep 17 00:00:00 2001 From: Ramtin Mehdizadeh Seraj Date: Wed, 25 Nov 2020 14:57:43 -0800 Subject: [PATCH 09/14] check log method errors --- runtime/runtime.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/runtime/runtime.go b/runtime/runtime.go index 550b22cfcf..e0231ff63a 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -1318,7 +1318,10 @@ func (r *interpreterRuntime) newLogFunction(runtimeInterface Interface) interpre return func(invocation interpreter.Invocation) trampoline.Trampoline { message := fmt.Sprint(invocation.Arguments[0]) wrapPanic(func() { - runtimeInterface.Log(message) + err := runtimeInterface.Log(message) + if err != nil { + panic(err) + } }) result := interpreter.VoidValue{} return trampoline.Done{Result: result} From ed53bdc42d0a829834d74f8d92268f3ceae814ae Mon Sep 17 00:00:00 2001 From: Ramtin Mehdizadeh Seraj Date: Wed, 25 Nov 2020 15:32:35 -0800 Subject: [PATCH 10/14] add SetComputationUsed to the interace --- runtime/interface.go | 6 ++++++ runtime/runtime.go | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/runtime/interface.go b/runtime/interface.go index 55c0097c74..399b060f06 100644 --- a/runtime/interface.go +++ b/runtime/interface.go @@ -76,6 +76,8 @@ type Interface interface { GenerateUUID() (uint64, error) // GetComputationLimit returns the computation limit. A value <= 0 means there is no limit GetComputationLimit() uint64 + // SetComputationUsed reports the amount of computation used. + SetComputationUsed(used uint64) error // DecodeArgument decodes a transaction argument against the given type. DecodeArgument(argument []byte, argumentType cadence.Type) (cadence.Value, error) // GetCurrentBlockHeight returns the current block height. @@ -208,6 +210,10 @@ func (i *EmptyRuntimeInterface) GetComputationLimit() uint64 { return 0 } +func (i *EmptyRuntimeInterface) SetComputationUsed(uint64) error { + return nil +} + func (i *EmptyRuntimeInterface) DecodeArgument(_ []byte, _ cadence.Type) (cadence.Value, error) { return nil, nil } diff --git a/runtime/runtime.go b/runtime/runtime.go index e0231ff63a..a5fb1d5eba 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -794,6 +794,10 @@ func (r *interpreterRuntime) meteringInterpreterOptions(runtimeInterface Interfa return } + err := runtimeInterface.SetComputationUsed(used) + if err != nil { + panic(err) + } panic(ComputationLimitExceededError{ Limit: limit, }) From f90b352630449485609583bd0192e4beb4a86937 Mon Sep 17 00:00:00 2001 From: Ramtin Mehdizadeh Seraj Date: Wed, 25 Nov 2020 15:37:07 -0800 Subject: [PATCH 11/14] fix tests --- runtime/runtime_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/runtime/runtime_test.go b/runtime/runtime_test.go index 1f1461f067..038400968d 100644 --- a/runtime/runtime_test.go +++ b/runtime/runtime_test.go @@ -222,6 +222,10 @@ func (i *testRuntimeInterface) GetComputationLimit() uint64 { return i.computationLimit } +func (i *testRuntimeInterface) SetComputationUsed(uint64) error { + return nil +} + func (i *testRuntimeInterface) DecodeArgument(b []byte, t cadence.Type) (cadence.Value, error) { return i.decodeArgument(b, t) } From 7b3aa0e49ba279d3a1ef2799d1fa405611a57612 Mon Sep 17 00:00:00 2001 From: Ramtin Mehdizadeh Seraj Date: Fri, 27 Nov 2020 10:46:22 -0800 Subject: [PATCH 12/14] apply changes requested by review --- runtime/runtime.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/runtime/runtime.go b/runtime/runtime.go index a5fb1d5eba..cd1c3a8bfd 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -641,13 +641,13 @@ func (r *interpreterRuntime) newInterpreter( r.injectedCompositeFieldsHandler(runtimeInterface, runtimeStorage), ), interpreter.WithUUIDHandler(func() (uuid uint64) { + var err error wrapPanic(func() { - var err error uuid, err = runtimeInterface.GenerateUUID() - if err != nil { - panic(err) - } }) + if err != nil { + panic(err) + } return }), interpreter.WithContractValueHandler( @@ -1321,12 +1321,13 @@ func (r *interpreterRuntime) newGetAccountFunction(runtimeInterface Interface) i func (r *interpreterRuntime) newLogFunction(runtimeInterface Interface) interpreter.HostFunction { return func(invocation interpreter.Invocation) trampoline.Trampoline { message := fmt.Sprint(invocation.Arguments[0]) + var err error wrapPanic(func() { - err := runtimeInterface.Log(message) - if err != nil { - panic(err) - } + err = runtimeInterface.Log(message) }) + if err != nil { + panic(err) + } result := interpreter.VoidValue{} return trampoline.Done{Result: result} } From 8771879189c54723cd58e5a4c43986bcf3320a8a Mon Sep 17 00:00:00 2001 From: Ramtin Mehdizadeh Seraj Date: Fri, 27 Nov 2020 10:42:34 -0800 Subject: [PATCH 13/14] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Müller --- runtime/runtime.go | 17 +++++++++++++---- runtime/stdlib/crypto.go | 4 ++-- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/runtime/runtime.go b/runtime/runtime.go index cd1c3a8bfd..596d7471e0 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -544,7 +544,9 @@ func (r *interpreterRuntime) parseAndCheckProgram( sema.WithValidTopLevelDeclarationsHandler(validTopLevelDeclarations), sema.WithLocationHandler(func(identifiers []Identifier, location Location) (res []ResolvedLocation) { var err error - res, err = runtimeInterface.ResolveLocation(identifiers, location) + wrapPanic(func() { + res, err = runtimeInterface.ResolveLocation(identifiers, location) + }) if err != nil { panic(err) } @@ -794,7 +796,10 @@ func (r *interpreterRuntime) meteringInterpreterOptions(runtimeInterface Interfa return } - err := runtimeInterface.SetComputationUsed(used) + var err error + wrapPanic(func() { + err = runtimeInterface.SetComputationUsed(used) + }) if err != nil { panic(err) } @@ -1339,7 +1344,7 @@ func (r *interpreterRuntime) getCurrentBlockHeight(runtimeInterface Interface) ( currentBlockHeight, er = runtimeInterface.GetCurrentBlockHeight() }) if er != nil { - err = newError(er) + return 0, newError(er) } return } @@ -1368,7 +1373,11 @@ func (r *interpreterRuntime) getBlockAtHeight(height uint64, runtimeInterface In func (r *interpreterRuntime) newGetCurrentBlockFunction(runtimeInterface Interface) interpreter.HostFunction { return func(invocation interpreter.Invocation) trampoline.Trampoline { - height, err := r.getCurrentBlockHeight(runtimeInterface) + var height uint64 + var err error + wrapPanic(func() { + height, err = r.getCurrentBlockHeight(runtimeInterface) + }) if err != nil { panic(err) } diff --git a/runtime/stdlib/crypto.go b/runtime/stdlib/crypto.go index a421105fe5..81701c7c7c 100644 --- a/runtime/stdlib/crypto.go +++ b/runtime/stdlib/crypto.go @@ -115,7 +115,7 @@ func newCryptoContractVerifySignatureFunction(signatureVerifier CryptoSignatureV hashAlgorithm, ) if err != nil { - panic(fmt.Errorf("VerifySignature: failed to verify the signature: %w", err)) + panic(err) } return trampoline.Done{Result: interpreter.BoolValue(isValid)} @@ -158,7 +158,7 @@ func newCryptoContractHashFunction(hasher CryptoHasher) interpreter.FunctionValu digest, err := hasher.Hash(data, hashAlgorithm) if err != nil { - panic(fmt.Errorf("hash: hashing failed: %w", err)) + panic(err) } From d37c9f353ffb9fec628e1d3333b347356d4cdcf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Fri, 27 Nov 2020 15:11:18 -0800 Subject: [PATCH 14/14] add error return value to interpreter and checker handlers - interpreter UUID handler - interpreter event emission handler - checker location handler --- runtime/cmd/cmd.go | 4 +- runtime/interpreter/errors.go | 34 ++++++-- runtime/interpreter/interpreter.go | 28 +++++- runtime/repl.go | 4 +- runtime/runtime.go | 86 +++++++++---------- runtime/sema/check_import_declaration.go | 11 ++- runtime/sema/checker.go | 2 +- runtime/tests/checker/import_test.go | 4 +- runtime/tests/interpreter/import_test.go | 2 +- runtime/tests/interpreter/interpreter_test.go | 14 +-- runtime/tests/interpreter/uuid_test.go | 4 +- 11 files changed, 116 insertions(+), 77 deletions(-) diff --git a/runtime/cmd/cmd.go b/runtime/cmd/cmd.go index bcba6c1a94..5a76ea8bfc 100644 --- a/runtime/cmd/cmd.go +++ b/runtime/cmd/cmd.go @@ -188,9 +188,9 @@ func PrepareInterpreter(filename string) (*interpreter.Interpreter, *sema.Checke inter, err := interpreter.NewInterpreter( checker, interpreter.WithPredefinedValues(valueDeclarations.ToValues()), - interpreter.WithUUIDHandler(func() uint64 { + interpreter.WithUUIDHandler(func() (uint64, error) { defer func() { uuid++ }() - return uuid + return uuid, nil }), ) must(err) diff --git a/runtime/interpreter/errors.go b/runtime/interpreter/errors.go index aec8486424..80aeb84cf2 100644 --- a/runtime/interpreter/errors.go +++ b/runtime/interpreter/errors.go @@ -196,7 +196,7 @@ func (e DestroyedCompositeError) Error() string { } // ForceAssignmentToNonNilResourceError - +// type ForceAssignmentToNonNilResourceError struct { LocationRange } @@ -206,7 +206,7 @@ func (e ForceAssignmentToNonNilResourceError) Error() string { } // ForceNilError - +// type ForceNilError struct { LocationRange } @@ -216,7 +216,7 @@ func (e ForceNilError) Error() string { } // TypeMismatchError - +// type TypeMismatchError struct { ExpectedType sema.Type LocationRange @@ -230,7 +230,7 @@ func (e TypeMismatchError) Error() string { } // InvalidPathDomainError - +// type InvalidPathDomainError struct { ActualDomain common.PathDomain ExpectedDomains []common.PathDomain @@ -257,7 +257,7 @@ func (e InvalidPathDomainError) SecondaryError() string { } // OverwriteError - +// type OverwriteError struct { Address AddressValue Path PathValue @@ -273,7 +273,7 @@ func (e OverwriteError) Error() string { } // CyclicLinkError - +// type CyclicLinkError struct { Address AddressValue Paths []PathValue @@ -298,7 +298,7 @@ func (e CyclicLinkError) Error() string { } // ArrayIndexOutOfBoundsError - +// type ArrayIndexOutOfBoundsError struct { Index int MaxIndex int @@ -312,3 +312,23 @@ func (e ArrayIndexOutOfBoundsError) Error() string { e.MaxIndex, ) } + +// EventEmissionUnavailableError +// +type EventEmissionUnavailableError struct { + LocationRange +} + +func (e EventEmissionUnavailableError) Error() string { + return "cannot emit event: unavailable" +} + +// UUIDUnavailableError +// +type UUIDUnavailableError struct { + LocationRange +} + +func (e UUIDUnavailableError) Error() string { + return "cannot get UUID: unavailable" +} diff --git a/runtime/interpreter/interpreter.go b/runtime/interpreter/interpreter.go index 96da865d33..fe721d24ff 100644 --- a/runtime/interpreter/interpreter.go +++ b/runtime/interpreter/interpreter.go @@ -78,7 +78,7 @@ type OnEventEmittedFunc func( inter *Interpreter, event *CompositeValue, eventType *sema.CompositeType, -) +) error // OnStatementFunc is a function that is triggered when a statement is about to be executed. // @@ -160,7 +160,7 @@ type ImportLocationHandlerFunc func( ) Import // UUIDHandlerFunc is a function that handles the generation of UUIDs. -type UUIDHandlerFunc func() uint64 +type UUIDHandlerFunc func() (uint64, error) // CompositeTypeCode contains the the "prepared" / "callable" "code" // for the functions and the destructor of a composite @@ -2557,7 +2557,18 @@ func (interpreter *Interpreter) declareNonEnumCompositeValue( fields := map[string]Value{} if declaration.CompositeKind == common.CompositeKindResource { - uuid := interpreter.uuidHandler() + + if interpreter.uuidHandler == nil { + panic(UUIDUnavailableError{ + LocationRange: invocation.LocationRange, + }) + } + + uuid, err := interpreter.uuidHandler() + if err != nil { + panic(err) + } + fields[sema.ResourceUUIDFieldName] = UInt64Value(uuid) } @@ -3489,7 +3500,16 @@ func (interpreter *Interpreter) VisitEmitStatement(statement *ast.EmitStatement) eventType := interpreter.Checker.Elaboration.EmitStatementEventTypes[statement] - interpreter.onEventEmitted(interpreter, event, eventType) + if interpreter.onEventEmitted == nil { + panic(EventEmissionUnavailableError{ + LocationRange: interpreter.locationRange(statement), + }) + } + + err := interpreter.onEventEmitted(interpreter, event, eventType) + if err != nil { + panic(err) + } // NOTE: no result, so it does *not* act like a return-statement return Done{} diff --git a/runtime/repl.go b/runtime/repl.go index f0200f6bfb..c464dc68fd 100644 --- a/runtime/repl.go +++ b/runtime/repl.go @@ -69,9 +69,9 @@ func NewREPL(onError func(error), onResult func(interpreter.Value), checkerOptio inter, err := interpreter.NewInterpreter( checker, interpreter.WithPredefinedValues(values), - interpreter.WithUUIDHandler(func() uint64 { + interpreter.WithUUIDHandler(func() (uint64, error) { defer func() { uuid++ }() - return uuid + return uuid, nil }), ) if err != nil { diff --git a/runtime/runtime.go b/runtime/runtime.go index 596d7471e0..84aac01ff4 100644 --- a/runtime/runtime.go +++ b/runtime/runtime.go @@ -542,44 +542,44 @@ func (r *interpreterRuntime) parseAndCheckProgram( sema.WithPredeclaredValues(valueDeclarations), sema.WithPredeclaredTypes(typeDeclarations), sema.WithValidTopLevelDeclarationsHandler(validTopLevelDeclarations), - sema.WithLocationHandler(func(identifiers []Identifier, location Location) (res []ResolvedLocation) { - var err error - wrapPanic(func() { - res, err = runtimeInterface.ResolveLocation(identifiers, location) - }) - if err != nil { - panic(err) - } - return - }), - sema.WithImportHandler(func(checker *sema.Checker, location ast.Location) (sema.Import, *sema.CheckerError) { - switch location { - case stdlib.CryptoChecker.Location: - return sema.CheckerImport{ - Checker: stdlib.CryptoChecker, - }, nil - - default: - var program *ast.Program - var err error - checker, checkerErr := checker.EnsureLoaded(location, func() *ast.Program { - program, err = importResolver(location) - return program + sema.WithLocationHandler( + func(identifiers []Identifier, location Location) (res []ResolvedLocation, err error) { + wrapPanic(func() { + res, err = runtimeInterface.ResolveLocation(identifiers, location) }) - // TODO: improve - if err != nil { - return nil, &sema.CheckerError{ - Errors: []error{err}, + return + }, + ), + sema.WithImportHandler( + func(checker *sema.Checker, location ast.Location) (sema.Import, *sema.CheckerError) { + switch location { + case stdlib.CryptoChecker.Location: + return sema.CheckerImport{ + Checker: stdlib.CryptoChecker, + }, nil + + default: + var program *ast.Program + var err error + checker, checkerErr := checker.EnsureLoaded(location, func() *ast.Program { + program, err = importResolver(location) + return program + }) + // TODO: improve + if err != nil { + return nil, &sema.CheckerError{ + Errors: []error{err}, + } } + if checkerErr != nil { + return nil, checkerErr + } + return sema.CheckerImport{ + Checker: checker, + }, nil } - if checkerErr != nil { - return nil, checkerErr - } - return sema.CheckerImport{ - Checker: checker, - }, nil - } - }), + }, + ), sema.WithCheckHandler(func(location ast.Location, check func()) { reportMetric( func() { @@ -630,8 +630,8 @@ func (r *interpreterRuntime) newInterpreter( inter *interpreter.Interpreter, eventValue *interpreter.CompositeValue, eventType *sema.CompositeType, - ) { - r.emitEvent(inter, runtimeInterface, eventValue, eventType) + ) error { + return r.emitEvent(inter, runtimeInterface, eventValue, eventType) }, ), interpreter.WithStorageKeyHandler( @@ -642,14 +642,10 @@ func (r *interpreterRuntime) newInterpreter( interpreter.WithInjectedCompositeFieldsHandler( r.injectedCompositeFieldsHandler(runtimeInterface, runtimeStorage), ), - interpreter.WithUUIDHandler(func() (uuid uint64) { - var err error + interpreter.WithUUIDHandler(func() (uuid uint64, err error) { wrapPanic(func() { uuid, err = runtimeInterface.GenerateUUID() }) - if err != nil { - panic(err) - } return }), interpreter.WithContractValueHandler( @@ -923,7 +919,7 @@ func (r *interpreterRuntime) emitEvent( runtimeInterface Interface, event *interpreter.CompositeValue, eventType *sema.CompositeType, -) { +) error { fields := make([]exportableValue, len(eventType.ConstructorParameters)) for i, parameter := range eventType.ConstructorParameters { @@ -940,9 +936,7 @@ func (r *interpreterRuntime) emitEvent( wrapPanic(func() { err = runtimeInterface.EmitEvent(exportedEvent) }) - if err != nil { - panic(err) - } + return err } func (r *interpreterRuntime) emitAccountEvent( diff --git a/runtime/sema/check_import_declaration.go b/runtime/sema/check_import_declaration.go index 4e46c6666d..3bca4230d8 100644 --- a/runtime/sema/check_import_declaration.go +++ b/runtime/sema/check_import_declaration.go @@ -50,7 +50,11 @@ func (checker *Checker) declareImportDeclaration(declaration *ast.ImportDeclarat EndPos: declaration.LocationPos, } - resolvedLocations := checker.resolveLocation(declaration.Identifiers, declaration.Location) + resolvedLocations, err := checker.resolveLocation(declaration.Identifiers, declaration.Location) + if err != nil { + checker.report(err) + return nil + } checker.Elaboration.ImportDeclarationsResolvedLocations[declaration] = resolvedLocations @@ -61,7 +65,7 @@ func (checker *Checker) declareImportDeclaration(declaration *ast.ImportDeclarat return nil } -func (checker *Checker) resolveLocation(identifiers []ast.Identifier, location ast.Location) []ResolvedLocation { +func (checker *Checker) resolveLocation(identifiers []ast.Identifier, location ast.Location) ([]ResolvedLocation, error) { // If no location handler is available, // default to resolving to a single location that declares all identifiers @@ -72,12 +76,11 @@ func (checker *Checker) resolveLocation(identifiers []ast.Identifier, location a Location: location, Identifiers: identifiers, }, - } + }, nil } // A location handler is available, // use it to resolve the location / identifiers - return checker.locationHandler(identifiers, location) } diff --git a/runtime/sema/checker.go b/runtime/sema/checker.go index 6de9a60990..e20a191e26 100644 --- a/runtime/sema/checker.go +++ b/runtime/sema/checker.go @@ -72,7 +72,7 @@ type ResolvedLocation struct { Identifiers []ast.Identifier } -type LocationHandlerFunc func(identifiers []ast.Identifier, location ast.Location) []ResolvedLocation +type LocationHandlerFunc func(identifiers []ast.Identifier, location ast.Location) ([]ResolvedLocation, error) type ImportHandlerFunc func(checker *Checker, location ast.Location) (Import, *CheckerError) diff --git a/runtime/tests/checker/import_test.go b/runtime/tests/checker/import_test.go index f0ca09ee8a..5e38c22ecb 100644 --- a/runtime/tests/checker/import_test.go +++ b/runtime/tests/checker/import_test.go @@ -131,7 +131,7 @@ func TestCheckRepeatedImportResolution(t *testing.T) { ParseAndCheckOptions{ Options: []sema.Option{ sema.WithLocationHandler( - func(identifiers []ast.Identifier, location ast.Location) (result []sema.ResolvedLocation) { + func(identifiers []ast.Identifier, location ast.Location) (result []sema.ResolvedLocation, err error) { for _, identifier := range identifiers { result = append(result, sema.ResolvedLocation{ Location: ast.AddressLocation{ @@ -253,7 +253,7 @@ func TestCheckImportResolutionSplit(t *testing.T) { ParseAndCheckOptions{ Options: []sema.Option{ sema.WithLocationHandler( - func(identifiers []ast.Identifier, location ast.Location) (result []sema.ResolvedLocation) { + func(identifiers []ast.Identifier, location ast.Location) (result []sema.ResolvedLocation, err error) { for _, identifier := range identifiers { result = append(result, sema.ResolvedLocation{ Location: ast.AddressLocation{ diff --git a/runtime/tests/interpreter/import_test.go b/runtime/tests/interpreter/import_test.go index 167f8de3b8..b385dd1e42 100644 --- a/runtime/tests/interpreter/import_test.go +++ b/runtime/tests/interpreter/import_test.go @@ -183,7 +183,7 @@ func TestInterpretImportMultipleProgramsFromLocation(t *testing.T) { checker.ParseAndCheckOptions{ Options: []sema.Option{ sema.WithLocationHandler( - func(identifiers []ast.Identifier, location ast.Location) (result []sema.ResolvedLocation) { + func(identifiers []ast.Identifier, location ast.Location) (result []sema.ResolvedLocation, err error) { require.Equal(t, ast.AddressLocation{ diff --git a/runtime/tests/interpreter/interpreter_test.go b/runtime/tests/interpreter/interpreter_test.go index 78b1cba4d8..4086b4b2b9 100644 --- a/runtime/tests/interpreter/interpreter_test.go +++ b/runtime/tests/interpreter/interpreter_test.go @@ -77,9 +77,9 @@ func parseCheckAndInterpretWithOptions( interpreterOptions := append( []interpreter.Option{ - interpreter.WithUUIDHandler(func() uint64 { + interpreter.WithUUIDHandler(func() (uint64, error) { uuid++ - return uuid + return uuid, nil }), }, options.Options..., @@ -3714,8 +3714,8 @@ func TestInterpretInitializerWithInterfacePreCondition(t *testing.T) { } } - uuidHandler := interpreter.WithUUIDHandler(func() uint64 { - return 0 + uuidHandler := interpreter.WithUUIDHandler(func() (uint64, error) { + return 0, nil }) if compositeKind == common.CompositeKindContract { @@ -5701,8 +5701,9 @@ func TestInterpretEmitEvent(t *testing.T) { ) inter.SetOnEventEmittedHandler( - func(_ *interpreter.Interpreter, event *interpreter.CompositeValue, eventType *sema.CompositeType) { + func(_ *interpreter.Interpreter, event *interpreter.CompositeValue, eventType *sema.CompositeType) error { actualEvents = append(actualEvents, event) + return nil }, ) @@ -5901,8 +5902,9 @@ func TestInterpretEmitEventParameterTypes(t *testing.T) { var actualEvents []*interpreter.CompositeValue inter.SetOnEventEmittedHandler( - func(_ *interpreter.Interpreter, event *interpreter.CompositeValue, eventType *sema.CompositeType) { + func(_ *interpreter.Interpreter, event *interpreter.CompositeValue, eventType *sema.CompositeType) error { actualEvents = append(actualEvents, event) + return nil }, ) diff --git a/runtime/tests/interpreter/uuid_test.go b/runtime/tests/interpreter/uuid_test.go index 5ddfde88ca..6341ece3a4 100644 --- a/runtime/tests/interpreter/uuid_test.go +++ b/runtime/tests/interpreter/uuid_test.go @@ -93,9 +93,9 @@ func TestInterpretResourceUUID(t *testing.T) { inter, err := interpreter.NewInterpreter( importingChecker, interpreter.WithUUIDHandler( - func() uint64 { + func() (uint64, error) { defer func() { uuid++ }() - return uuid + return uuid, nil }, ), interpreter.WithImportLocationHandler(