Skip to content

Commit ba21a40

Browse files
Change dependencies tracker to track both addresses and locations
1 parent decd559 commit ba21a40

14 files changed

+459
-143
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 & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,6 @@ type DerivedTransactionCommitter interface {
3737
Commit() error
3838
}
3939

40-
// ProgramDependencies are the programs' locations used by this program.
41-
type ProgramDependencies map[common.Location]struct{}
42-
43-
// AddDependency adds the location as a dependency.
44-
func (d ProgramDependencies) AddDependency(location common.Location) {
45-
d[location] = struct{}{}
46-
}
47-
48-
// Merge merges current dependencies with other dependencies.
49-
func (d ProgramDependencies) Merge(other ProgramDependencies) {
50-
for address := range other {
51-
d[address] = struct{}{}
52-
}
53-
}
54-
5540
type Program struct {
5641
*interpreter.Program
5742

fvm/environment/contract_updater.go

Lines changed: 38 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ type ContractUpdater interface {
7676
// OperationNotSupportedError.
7777
RemoveAccountContractCode(runtimeAddress common.Address, name string) error
7878

79-
Commit() ([]ContractUpdateKey, error)
79+
Commit() (ContractUpdates, error)
8080

8181
Reset()
8282
}
@@ -123,7 +123,7 @@ func (updater ParseRestrictedContractUpdater) RemoveAccountContractCode(
123123
}
124124

125125
func (updater ParseRestrictedContractUpdater) Commit() (
126-
[]ContractUpdateKey,
126+
ContractUpdates,
127127
error,
128128
) {
129129
return updater.impl.Commit()
@@ -150,8 +150,8 @@ func (NoContractUpdater) RemoveAccountContractCode(
150150
return errors.NewOperationNotSupportedError("RemoveAccountContractCode")
151151
}
152152

153-
func (NoContractUpdater) Commit() ([]ContractUpdateKey, error) {
154-
return nil, nil
153+
func (NoContractUpdater) Commit() (ContractUpdates, error) {
154+
return ContractUpdates{}, nil
155155
}
156156

157157
func (NoContractUpdater) Reset() {
@@ -437,26 +437,49 @@ func (updater *ContractUpdaterImpl) RemoveContract(
437437
return nil
438438
}
439439

440-
func (updater *ContractUpdaterImpl) Commit() ([]ContractUpdateKey, error) {
441-
updatedKeys, updateList := updater.updates()
440+
func (updater *ContractUpdaterImpl) Commit() (ContractUpdates, error) {
441+
updateList := updater.updates()
442442
updater.Reset()
443443

444+
contractUpdates := ContractUpdates{
445+
Updates: make([]ContractUpdateKey, 0, len(updateList)),
446+
Deploys: make([]ContractUpdateKey, 0, len(updateList)),
447+
Deletions: make([]ContractUpdateKey, 0, len(updateList)),
448+
}
449+
444450
var err error
445451
for _, v := range updateList {
446-
if len(v.Code) > 0 {
447-
err = updater.accounts.SetContract(v.Name, v.Address, v.Code)
452+
var currentlyExists bool
453+
currentlyExists, err = updater.accounts.ContractExists(v.Name, v.Address)
454+
if err != nil {
455+
return ContractUpdates{}, err
456+
}
457+
shouldDelete := len(v.Code) == 0
458+
459+
if shouldDelete {
460+
// this is a removal
461+
contractUpdates.Deletions = append(contractUpdates.Deletions, v.ContractUpdateKey)
462+
err = updater.accounts.DeleteContract(v.Name, v.Address)
448463
if err != nil {
449-
return nil, err
464+
return ContractUpdates{}, err
450465
}
451466
} else {
452-
err = updater.accounts.DeleteContract(v.Name, v.Address)
467+
if !currentlyExists {
468+
// this is a deployment
469+
contractUpdates.Deploys = append(contractUpdates.Deploys, v.ContractUpdateKey)
470+
} else {
471+
// this is an update
472+
contractUpdates.Updates = append(contractUpdates.Updates, v.ContractUpdateKey)
473+
}
474+
475+
err = updater.accounts.SetContract(v.Name, v.Address, v.Code)
453476
if err != nil {
454-
return nil, err
477+
return ContractUpdates{}, err
455478
}
456479
}
457480
}
458481

459-
return updatedKeys, nil
482+
return contractUpdates, nil
460483
}
461484

462485
func (updater *ContractUpdaterImpl) Reset() {
@@ -467,12 +490,9 @@ func (updater *ContractUpdaterImpl) HasUpdates() bool {
467490
return len(updater.draftUpdates) > 0
468491
}
469492

470-
func (updater *ContractUpdaterImpl) updates() (
471-
[]ContractUpdateKey,
472-
[]ContractUpdate,
473-
) {
493+
func (updater *ContractUpdaterImpl) updates() []ContractUpdate {
474494
if len(updater.draftUpdates) == 0 {
475-
return nil, nil
495+
return nil
476496
}
477497
keys := make([]ContractUpdateKey, 0, len(updater.draftUpdates))
478498
updates := make([]ContractUpdate, 0, len(updater.draftUpdates))
@@ -482,7 +502,7 @@ func (updater *ContractUpdaterImpl) updates() (
482502
}
483503

484504
sort.Sort(&sortableContractUpdates{keys: keys, updates: updates})
485-
return keys, updates
505+
return updates
486506
}
487507

488508
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)