diff --git a/npm-packages/cadence-parser/package.json b/npm-packages/cadence-parser/package.json index b69b2e839e..0f40146391 100644 --- a/npm-packages/cadence-parser/package.json +++ b/npm-packages/cadence-parser/package.json @@ -1,6 +1,6 @@ { "name": "@onflow/cadence-parser", - "version": "1.0.0-preview.20", + "version": "1.0.0-preview.21", "description": "The Cadence parser", "homepage": "https://github.com/onflow/cadence", "repository": { diff --git a/runtime/interpreter/value.go b/runtime/interpreter/value.go index b892759963..ce22b22c4d 100644 --- a/runtime/interpreter/value.go +++ b/runtime/interpreter/value.go @@ -19262,14 +19262,14 @@ func (v *DictionaryValue) SetKey( locationRange, ) + var existingValue Value switch value := value.(type) { case *SomeValue: innerValue := value.InnerValue(interpreter, locationRange) - existingValue := v.Insert(interpreter, locationRange, keyValue, innerValue) - interpreter.checkResourceLoss(existingValue, locationRange) + existingValue = v.Insert(interpreter, locationRange, keyValue, innerValue) case NilValue: - _ = v.Remove(interpreter, locationRange, keyValue) + existingValue = v.Remove(interpreter, locationRange, keyValue) case placeholderValue: // NO-OP @@ -19277,6 +19277,10 @@ func (v *DictionaryValue) SetKey( default: panic(errors.NewUnreachableError()) } + + if existingValue != nil { + interpreter.checkResourceLoss(existingValue, locationRange) + } } func (v *DictionaryValue) String() string { diff --git a/runtime/runtime_test.go b/runtime/runtime_test.go index 0736207888..58fa416a59 100644 --- a/runtime/runtime_test.go +++ b/runtime/runtime_test.go @@ -10501,3 +10501,156 @@ func TestRuntimeValueTransferResourceLoss(t *testing.T) { require.Equal(t, `A.0000000000000001.Foo.R.ResourceDestroyed(id: "dummy resource")`, events[1].String()) require.Equal(t, `A.0000000000000001.Foo.R.ResourceDestroyed(id: "victim resource")`, events[2].String()) } + +func TestRuntimeNonPublicAccessModifierInInterface(t *testing.T) { + + t.Parallel() + + runtime := NewTestInterpreterRuntimeWithAttachments() + + address1 := common.MustBytesToAddress([]byte{0x1}) + address2 := common.MustBytesToAddress([]byte{0x2}) + + contract1 := []byte(` + access(all) + contract C1 { + + access(all) + struct interface SI { + + access(contract) + fun contractTest() + + access(account) + fun accountTest() + } + + access(all) + fun test(_ si: {SI}) { + si.contractTest() + si.accountTest() + } + } + `) + + contract2 := []byte(` + import C1 from 0x1 + + access(all) + contract C2 { + + access(all) + struct S1: C1.SI { + access(contract) + fun contractTest() {} + + access(account) + fun accountTest() {} + } + + access(all) + struct S2: C1.SI { + access(all) + fun contractTest() {} + + access(all) + fun accountTest() {} + } + + access(all) + fun test() { + S1().contractTest() + S1().accountTest() + S2().contractTest() + S2().accountTest() + } + } + `) + + tx := []byte(` + import C1 from 0x1 + import C2 from 0x2 + + transaction { + prepare(acct: &Account) { + C1.test(C2.S1()) + C1.test(C2.S2()) + C2.test() + } + } + `) + + deploy1 := DeploymentTransaction("C1", contract1) + deploy2 := DeploymentTransaction("C2", contract2) + + var signer Address + + accountCodes := map[Location][]byte{} + var events []cadence.Event + + runtimeInterface := &TestRuntimeInterface{ + OnGetCode: func(location Location) (bytes []byte, err error) { + return accountCodes[location], nil + }, + Storage: NewTestLedger(nil, nil), + OnGetSigningAccounts: func() ([]Address, error) { + return []Address{signer}, nil + }, + OnResolveLocation: NewSingleIdentifierLocationResolver(t), + OnGetAccountContractCode: func(location common.AddressLocation) (code []byte, err error) { + return accountCodes[location], nil + }, + OnUpdateAccountContractCode: func(location common.AddressLocation, code []byte) error { + accountCodes[location] = code + return nil + }, + OnEmitEvent: func(event cadence.Event) error { + events = append(events, event) + return nil + }, + } + + nextTransactionLocation := NewTransactionLocationGenerator() + + // Deploy first contract to first account + + signer = address1 + + err := runtime.ExecuteTransaction( + Script{ + Source: deploy1, + }, + Context{ + Interface: runtimeInterface, + Location: nextTransactionLocation(), + }, + ) + require.NoError(t, err) + + // Deploy second contract to second account + + signer = address2 + + err = runtime.ExecuteTransaction( + Script{ + Source: deploy2, + }, + Context{ + Interface: runtimeInterface, + Location: nextTransactionLocation(), + }, + ) + require.NoError(t, err) + + // Run test transaction + + err = runtime.ExecuteTransaction( + Script{ + Source: tx, + }, + Context{ + Interface: runtimeInterface, + Location: nextTransactionLocation(), + }) + require.NoError(t, err) +} diff --git a/runtime/tests/interpreter/resources_test.go b/runtime/tests/interpreter/resources_test.go index 03875b7fbb..333a87547f 100644 --- a/runtime/tests/interpreter/resources_test.go +++ b/runtime/tests/interpreter/resources_test.go @@ -2927,7 +2927,11 @@ func TestInterpretResourceLoss(t *testing.T) { t.Parallel() - inter, _, err := parseCheckAndInterpretWithLogs(t, ` + t.Run("in callback", func(t *testing.T) { + + t.Parallel() + + inter := parseCheckAndInterpret(t, ` access(all) resource R { access(all) let id: String @@ -2970,11 +2974,36 @@ func TestInterpretResourceLoss(t *testing.T) { destroy rl } `) - require.NoError(t, err) - _, err = inter.Invoke("main") - RequireError(t, err) - require.ErrorAs(t, err, &interpreter.ResourceLossError{}) + _, err := inter.Invoke("main") + RequireError(t, err) + require.ErrorAs(t, err, &interpreter.ResourceLossError{}) + }) + + t.Run("force nil assignment", func(t *testing.T) { + + t.Parallel() + + inter := parseCheckAndInterpret(t, ` + access(all) resource R { + access(all) event ResourceDestroyed() + } + + access(all) fun loseResource(_ victim: @R) { + var dict <- { 0: <- victim} + dict[0] <-! nil + destroy dict + } + + access(all) fun main() { + loseResource(<- create R()) + } + `) + + _, err := inter.Invoke("main") + RequireError(t, err) + require.ErrorAs(t, err, &interpreter.ResourceLossError{}) + }) } func TestInterpretPreConditionResourceMove(t *testing.T) { diff --git a/tools/staged-contracts-report-printer/main.go b/tools/staged-contracts-report-printer/main.go index f469a8feb8..00bba0e0d4 100644 --- a/tools/staged-contracts-report-printer/main.go +++ b/tools/staged-contracts-report-printer/main.go @@ -54,7 +54,7 @@ func main() { markdownBuilder := strings.Builder{} markdownBuilder.WriteString("## Cadence 1.0 staged contracts migration results\n") markdownBuilder.WriteString(fmt.Sprintf("Date: %s\n", now.Format("02 January, 2006"))) - markdownBuilder.WriteString("|Address | Name | Status |\n") + markdownBuilder.WriteString("|Account Address | Contract Name | Status |\n") markdownBuilder.WriteString("| --- | --- | --- | \n") for _, entry := range reportEntries { @@ -96,7 +96,7 @@ func main() { } type contractUpdateStatus struct { - AccountAddress string `json:"address"` - ContractName string `json:"name"` + AccountAddress string `json:"account_address"` + ContractName string `json:"contract_name"` Error string `json:"error"` } diff --git a/tools/storage-explorer/go.mod b/tools/storage-explorer/go.mod index 3de28388ae..1301d141c8 100644 --- a/tools/storage-explorer/go.mod +++ b/tools/storage-explorer/go.mod @@ -4,7 +4,7 @@ go 1.20 require ( github.com/gorilla/mux v1.8.1 - github.com/onflow/atree v0.6.1-0.20240314011440-92714cac03fb + github.com/onflow/atree v0.6.1-0.20240417191405-e11f55fa33a3 github.com/onflow/cadence v1.0.0-M8 github.com/onflow/flow-go v0.34.0-crescendo-preview.5.0.20240229164931-a67398875618 github.com/rs/zerolog v1.32.0 diff --git a/tools/storage-explorer/go.sum b/tools/storage-explorer/go.sum index de37f702ad..a781896cfc 100644 --- a/tools/storage-explorer/go.sum +++ b/tools/storage-explorer/go.sum @@ -1775,8 +1775,8 @@ github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onflow/atree v0.6.1-0.20230711151834-86040b30171f/go.mod h1:xvP61FoOs95K7IYdIYRnNcYQGf4nbF/uuJ0tHf4DRuM= -github.com/onflow/atree v0.6.1-0.20240314011440-92714cac03fb h1:9w+8wseSv7TZ9ikGfKSZ6yJifgYLhm717Zo0SVKpGEQ= -github.com/onflow/atree v0.6.1-0.20240314011440-92714cac03fb/go.mod h1:7YNAyCd5JENq+NzH+fR1ABUZVzbSq9dkt0+5fZH3L2A= +github.com/onflow/atree v0.6.1-0.20240417191405-e11f55fa33a3 h1:K8LKxRn1rRdDXLCvYlDNdlQyB28b+fx2doYiIaNGnQU= +github.com/onflow/atree v0.6.1-0.20240417191405-e11f55fa33a3/go.mod h1:7YNAyCd5JENq+NzH+fR1ABUZVzbSq9dkt0+5fZH3L2A= github.com/onflow/crypto v0.25.0 h1:BeWbLsh3ZD13Ej+Uky6kg1PL1ZIVBDVX+2MVBNwqddg= github.com/onflow/crypto v0.25.0/go.mod h1:C8FbaX0x8y+FxWjbkHy0Q4EASCDR9bSPWZqlpCLYyVI= github.com/onflow/flow-core-contracts/lib/go/contracts v0.15.2-0.20240227190927-0e6ce7e3222b h1:oXHQft30sElpK7G3xWB5tEizI2G+S4p64iVh0LtX4E0= diff --git a/version.go b/version.go index 577aaf533c..4f97c1aaec 100644 --- a/version.go +++ b/version.go @@ -21,4 +21,4 @@ package cadence -const Version = "v1.0.0-preview.20" +const Version = "v1.0.0-preview.21"