Skip to content

Commit def6a7b

Browse files
Merge #4056
4056: Change program dependencies to cadence location r=janezpodhostnik a=janezpodhostnik ref: onflow/cadence#1684 This is now possible that account freezing is removed, and will be needed to remove double counting of imports. Co-authored-by: Janez Podhostnik <[email protected]>
2 parents d352e86 + ba21a40 commit def6a7b

14 files changed

+467
-149
lines changed

fvm/derived/dependencies.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package derived
2+
3+
import (
4+
"github.com/onflow/cadence/runtime/common"
5+
)
6+
7+
// ProgramDependencies are the locations of programs that a program depends on.
8+
type ProgramDependencies struct {
9+
locations map[common.Location]struct{}
10+
addresses map[common.Address]struct{}
11+
}
12+
13+
func NewProgramDependencies() ProgramDependencies {
14+
return ProgramDependencies{
15+
locations: map[common.Location]struct{}{},
16+
addresses: map[common.Address]struct{}{},
17+
}
18+
}
19+
20+
// Count returns the number of locations dependencies of this program.
21+
func (d ProgramDependencies) Count() int {
22+
return len(d.locations)
23+
}
24+
25+
// Add adds the location as a dependency.
26+
func (d ProgramDependencies) Add(location common.Location) ProgramDependencies {
27+
d.locations[location] = struct{}{}
28+
29+
if addressLocation, ok := location.(common.AddressLocation); ok {
30+
d.addresses[addressLocation.Address] = struct{}{}
31+
}
32+
33+
return d
34+
}
35+
36+
// Merge merges current dependencies with other dependencies.
37+
func (d ProgramDependencies) Merge(other ProgramDependencies) {
38+
for loc := range other.locations {
39+
d.locations[loc] = struct{}{}
40+
}
41+
for address := range other.addresses {
42+
d.addresses[address] = struct{}{}
43+
}
44+
}
45+
46+
// ContainsAddress returns true if the address is a dependency.
47+
func (d ProgramDependencies) ContainsAddress(address common.Address) bool {
48+
_, ok := d.addresses[address]
49+
return ok
50+
}
51+
52+
// ContainsLocation returns true if the location is a dependency.
53+
func (d ProgramDependencies) ContainsLocation(location common.Location) bool {
54+
_, ok := d.locations[location]
55+
return ok
56+
}

fvm/derived/dependencies_test.go

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package derived_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/require"
7+
8+
"github.com/onflow/cadence/runtime/common"
9+
10+
"github.com/onflow/flow-go/fvm/derived"
11+
)
12+
13+
func TestProgramDependencies_Count(t *testing.T) {
14+
d := derived.NewProgramDependencies()
15+
16+
require.Equal(t, 0, d.Count())
17+
18+
d.Add(common.StringLocation("test"))
19+
require.Equal(t, 1, d.Count())
20+
}
21+
22+
func TestProgramDependencies_Add(t *testing.T) {
23+
d := derived.NewProgramDependencies()
24+
25+
d.Add(common.StringLocation("test"))
26+
require.Equal(t, 1, d.Count())
27+
28+
address, _ := common.HexToAddress("0xa")
29+
addressLocation := common.AddressLocation{Address: address}
30+
d.Add(addressLocation)
31+
require.True(t, d.ContainsAddress(address))
32+
}
33+
34+
func TestProgramDependencies_Merge(t *testing.T) {
35+
d1 := derived.NewProgramDependencies()
36+
d1.Add(common.StringLocation("test1"))
37+
38+
d2 := derived.NewProgramDependencies()
39+
d2.Add(common.StringLocation("test2"))
40+
41+
d1.Merge(d2)
42+
require.Equal(t, 2, d1.Count())
43+
}
44+
45+
func TestProgramDependencies_ContainsAddress(t *testing.T) {
46+
d := derived.NewProgramDependencies()
47+
48+
address, _ := common.HexToAddress("0xa")
49+
addressLocation := common.AddressLocation{Address: address}
50+
d.Add(addressLocation)
51+
52+
require.True(t, d.ContainsAddress(address))
53+
}
54+
55+
func TestProgramDependencies_ContainsLocation(t *testing.T) {
56+
d := derived.NewProgramDependencies()
57+
location := common.StringLocation("test")
58+
d.Add(location)
59+
60+
require.True(t, d.ContainsLocation(location))
61+
}

fvm/derived/derived_block_data.go

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"github.com/onflow/cadence/runtime/interpreter"
88

99
"github.com/onflow/flow-go/fvm/state"
10-
"github.com/onflow/flow-go/model/flow"
1110
)
1211

1312
type DerivedTransaction interface {
@@ -38,21 +37,6 @@ type DerivedTransactionCommitter interface {
3837
Commit() error
3938
}
4039

41-
// ProgramDependencies are the programs' addresses used by this program.
42-
type ProgramDependencies map[flow.Address]struct{}
43-
44-
// AddDependency adds the address as a dependency.
45-
func (d ProgramDependencies) AddDependency(address flow.Address) {
46-
d[address] = struct{}{}
47-
}
48-
49-
// Merge merges current dependencies with other dependencies.
50-
func (d ProgramDependencies) Merge(other ProgramDependencies) {
51-
for address := range other {
52-
d[address] = struct{}{}
53-
}
54-
}
55-
5640
type Program struct {
5741
*interpreter.Program
5842

fvm/environment/contract_updater.go

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ type ContractUpdater interface {
7575
// OperationNotSupportedError.
7676
RemoveAccountContractCode(location common.AddressLocation) error
7777

78-
Commit() ([]ContractUpdateKey, error)
78+
Commit() (ContractUpdates, error)
7979

8080
Reset()
8181
}
@@ -118,7 +118,7 @@ func (updater ParseRestrictedContractUpdater) RemoveAccountContractCode(
118118
}
119119

120120
func (updater ParseRestrictedContractUpdater) Commit() (
121-
[]ContractUpdateKey,
121+
ContractUpdates,
122122
error,
123123
) {
124124
return updater.impl.Commit()
@@ -143,8 +143,8 @@ func (NoContractUpdater) RemoveAccountContractCode(
143143
return errors.NewOperationNotSupportedError("RemoveAccountContractCode")
144144
}
145145

146-
func (NoContractUpdater) Commit() ([]ContractUpdateKey, error) {
147-
return nil, nil
146+
func (NoContractUpdater) Commit() (ContractUpdates, error) {
147+
return ContractUpdates{}, nil
148148
}
149149

150150
func (NoContractUpdater) Reset() {
@@ -428,26 +428,49 @@ func (updater *ContractUpdaterImpl) RemoveContract(
428428
return nil
429429
}
430430

431-
func (updater *ContractUpdaterImpl) Commit() ([]ContractUpdateKey, error) {
432-
updatedKeys, updateList := updater.updates()
431+
func (updater *ContractUpdaterImpl) Commit() (ContractUpdates, error) {
432+
updateList := updater.updates()
433433
updater.Reset()
434434

435+
contractUpdates := ContractUpdates{
436+
Updates: make([]ContractUpdateKey, 0, len(updateList)),
437+
Deploys: make([]ContractUpdateKey, 0, len(updateList)),
438+
Deletions: make([]ContractUpdateKey, 0, len(updateList)),
439+
}
440+
435441
var err error
436442
for _, v := range updateList {
437-
if len(v.Code) > 0 {
438-
err = updater.accounts.SetContract(v.Name, v.Address, v.Code)
443+
var currentlyExists bool
444+
currentlyExists, err = updater.accounts.ContractExists(v.Name, v.Address)
445+
if err != nil {
446+
return ContractUpdates{}, err
447+
}
448+
shouldDelete := len(v.Code) == 0
449+
450+
if shouldDelete {
451+
// this is a removal
452+
contractUpdates.Deletions = append(contractUpdates.Deletions, v.ContractUpdateKey)
453+
err = updater.accounts.DeleteContract(v.Name, v.Address)
439454
if err != nil {
440-
return nil, err
455+
return ContractUpdates{}, err
441456
}
442457
} else {
443-
err = updater.accounts.DeleteContract(v.Name, v.Address)
458+
if !currentlyExists {
459+
// this is a deployment
460+
contractUpdates.Deploys = append(contractUpdates.Deploys, v.ContractUpdateKey)
461+
} else {
462+
// this is an update
463+
contractUpdates.Updates = append(contractUpdates.Updates, v.ContractUpdateKey)
464+
}
465+
466+
err = updater.accounts.SetContract(v.Name, v.Address, v.Code)
444467
if err != nil {
445-
return nil, err
468+
return ContractUpdates{}, err
446469
}
447470
}
448471
}
449472

450-
return updatedKeys, nil
473+
return contractUpdates, nil
451474
}
452475

453476
func (updater *ContractUpdaterImpl) Reset() {
@@ -458,12 +481,9 @@ func (updater *ContractUpdaterImpl) HasUpdates() bool {
458481
return len(updater.draftUpdates) > 0
459482
}
460483

461-
func (updater *ContractUpdaterImpl) updates() (
462-
[]ContractUpdateKey,
463-
[]ContractUpdate,
464-
) {
484+
func (updater *ContractUpdaterImpl) updates() []ContractUpdate {
465485
if len(updater.draftUpdates) == 0 {
466-
return nil, nil
486+
return nil
467487
}
468488
keys := make([]ContractUpdateKey, 0, len(updater.draftUpdates))
469489
updates := make([]ContractUpdate, 0, len(updater.draftUpdates))
@@ -473,7 +493,7 @@ func (updater *ContractUpdaterImpl) updates() (
473493
}
474494

475495
sort.Sort(&sortableContractUpdates{keys: keys, updates: updates})
476-
return keys, updates
496+
return updates
477497
}
478498

479499
func (updater *ContractUpdaterImpl) isAuthorizedForDeployment(

fvm/environment/contract_updater_test.go

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -336,17 +336,21 @@ func TestContract_ContractRemoval(t *testing.T) {
336336
require.NoError(t, err)
337337
require.True(t, contractUpdater.HasUpdates())
338338

339-
contractUpdateKeys, err := contractUpdater.Commit()
339+
contractUpdates, err := contractUpdater.Commit()
340340
require.NoError(t, err)
341341
require.Equal(
342342
t,
343-
[]environment.ContractUpdateKey{
344-
{
345-
Address: flowAddress,
346-
Name: "TestContract",
343+
environment.ContractUpdates{
344+
Updates: []environment.ContractUpdateKey{},
345+
Deploys: []environment.ContractUpdateKey{
346+
{
347+
Address: flowAddress,
348+
Name: "TestContract",
349+
},
347350
},
351+
Deletions: []environment.ContractUpdateKey{},
348352
},
349-
contractUpdateKeys,
353+
contractUpdates,
350354
)
351355

352356
// update should work
@@ -394,11 +398,15 @@ func TestContract_ContractRemoval(t *testing.T) {
394398
require.NoError(t, err)
395399
require.Equal(
396400
t,
397-
[]environment.ContractUpdateKey{
398-
{
399-
Address: flowAddress,
400-
Name: "TestContract",
401+
environment.ContractUpdates{
402+
Updates: []environment.ContractUpdateKey{
403+
{
404+
Address: flowAddress,
405+
Name: "TestContract",
406+
},
401407
},
408+
Deploys: []environment.ContractUpdateKey{},
409+
Deletions: []environment.ContractUpdateKey{},
402410
},
403411
contractUpdateKeys,
404412
)
@@ -426,5 +434,21 @@ func TestContract_ContractRemoval(t *testing.T) {
426434
require.NoError(t, err)
427435
require.True(t, contractUpdater.HasUpdates())
428436

437+
contractUpdateKeys, err = contractUpdater.Commit()
438+
require.NoError(t, err)
439+
require.Equal(
440+
t,
441+
environment.ContractUpdates{
442+
Updates: []environment.ContractUpdateKey{},
443+
Deploys: []environment.ContractUpdateKey{},
444+
Deletions: []environment.ContractUpdateKey{
445+
{
446+
Address: flowAddress,
447+
Name: "TestContract",
448+
},
449+
},
450+
},
451+
contractUpdateKeys,
452+
)
429453
})
430454
}

0 commit comments

Comments
 (0)