-
Notifications
You must be signed in to change notification settings - Fork 30
/
manager.go
176 lines (147 loc) · 6.41 KB
/
manager.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
// Package manager manages deployers to make them as simple as possible
package manager
import (
"context"
"github.com/stretchr/testify/require"
"sync"
"testing"
"github.com/stretchr/testify/assert"
"github.com/synapsecns/sanguine/ethergo/backends"
"github.com/synapsecns/sanguine/ethergo/backends/simulated"
"github.com/synapsecns/sanguine/ethergo/contracts"
"github.com/synapsecns/sanguine/ethergo/deployer"
)
// IDeployManager is responsible for deploying contracts.
type IDeployManager interface {
// T returns the testing object.
T() *testing.T
// SetT sets the testing object.
SetT(t *testing.T)
// BulkDeploy deploys all contracts.
BulkDeploy(ctx context.Context, testBackends []backends.SimulatedTestBackend, contracts ...contracts.ContractType)
// GetContractRegistry returns the contract registry for the given backend.
GetContractRegistry(backend backends.SimulatedTestBackend) deployer.ContractRegistry
// Get returns the deployed contract for the given contract type.
Get(ctx context.Context, backend backends.SimulatedTestBackend, contractType contracts.ContractType) contracts.DeployedContract
// GetDeployedContracts returns all deployed contracts.
GetDeployedContracts() (res map[uint32][]contracts.DeployedContract)
}
// DeployerManager is responsible for wrapping contract registry with easy to use getters that correctly cast the handles.
// since ContractRegistry is meant to be kept pure and go does not support generics, the sole function is to provide
// handler wrappers around the registry. This will no longer be required when go supports generics: https://blog.golang.org/generics-proposal
// TODO: go 1.20 supports generics, this can be improved.
type DeployerManager struct {
// t is the testing object
t *testing.T
// registries stores the contract registries
registries map[string]deployer.ContractRegistry
// structMux prevents race conditions
structMux sync.RWMutex
// deployers adds a list of default deployers
deployers []deployer.DeployerFunc
}
// DeployerFunc defines a deployer we can use.
// Deprecated: use deployer.DeployerFunc instead.
type DeployerFunc = deployer.DeployerFunc
// NewDeployerManager creates a new deployment helper.
func NewDeployerManager(t *testing.T, deployers ...deployer.DeployerFunc) (d *DeployerManager) {
t.Helper()
d = &DeployerManager{
t: t,
structMux: sync.RWMutex{},
registries: make(map[string]deployer.ContractRegistry),
deployers: deployers,
}
return d
}
// T is the testing object.
func (d *DeployerManager) T() *testing.T {
return d.t
}
// SetT sets the testing object.
func (d *DeployerManager) SetT(t *testing.T) {
t.Helper()
d.t = t
}
// BulkDeploy synchronously deploys a bunch of contracts as quickly as possible to speed up tests.
// in a future version this will utilize dependency trees. Returns nothing when complete.
func (d *DeployerManager) BulkDeploy(ctx context.Context, testBackends []backends.SimulatedTestBackend, contracts ...contracts.ContractType) {
wg := sync.WaitGroup{}
for _, backend := range testBackends {
wg.Add(1)
go func(backend backends.SimulatedTestBackend) {
defer wg.Done()
cr := d.GetContractRegistry(backend)
for _, contract := range contracts {
cr.Get(ctx, contract)
}
}(backend)
}
wg.Wait()
}
// GetContractRegistry gets a contract registry for a backend and creates it if it does not exist.
func (d *DeployerManager) GetContractRegistry(backend backends.SimulatedTestBackend) deployer.ContractRegistry {
d.structMux.Lock()
defer d.structMux.Unlock()
// if registry exists, return it
contractRegistry, ok := d.registries[backend.GetBigChainID().String()]
if ok {
return contractRegistry
}
contractRegistry = deployer.NewContractRegistry(d.t, backend)
for _, d := range d.deployers {
contractRegistry.RegisterContractDeployer(d(contractRegistry, backend))
}
d.registries[backend.GetBigChainID().String()] = contractRegistry
return contractRegistry
}
// Get gets the contract from the registry.
func (d *DeployerManager) Get(ctx context.Context, backend backends.SimulatedTestBackend, contractType contracts.ContractType) contracts.DeployedContract {
return d.GetContractRegistry(backend).Get(ctx, contractType)
}
// GetDeployedContracts gets all deployed contracts by domain.
func (d *DeployerManager) GetDeployedContracts() (res map[uint32][]contracts.DeployedContract) {
d.structMux.RLock()
defer d.structMux.RUnlock()
res = make(map[uint32][]contracts.DeployedContract)
for _, registry := range d.registries {
for _, contract := range registry.GetDeployedContracts() {
chainID := uint32(contract.ChainID().Uint64())
res[chainID] = append(res[chainID], contract)
}
}
return res
}
// GetContract gets a contract from the registry and casts it to the correct type.
func GetContract[T any](ctx context.Context, tb testing.TB, deployManager IDeployManager, backend backends.SimulatedTestBackend, contractType contracts.ContractType) (contracts.DeployedContract, T) {
tb.Helper()
deployedContract := deployManager.Get(ctx, backend, contractType)
contractHandle, ok := deployedContract.ContractHandle().(T)
require.True(tb, ok)
return deployedContract, contractHandle
}
// DeployManagerFactory is a factory for a deploy manager.
type DeployManagerFactory func() IDeployManager
// AssertDependenciesCorrect asserts that all dependencies of contracts are correct.
func AssertDependenciesCorrect(ctx context.Context, t *testing.T, deployManagerFactory DeployManagerFactory) {
t.Helper()
backend := simulated.NewSimulatedBackend(ctx, t)
deployManager := deployManagerFactory()
registeredContracts := deployManager.GetContractRegistry(backend).RegisteredDeployers()
// test until all contacts are done
for _, contract := range registeredContracts {
deployManager = deployManagerFactory()
contractRegistry := deployManager.GetContractRegistry(backend)
assert.Equal(t, len(contractRegistry.GetDeployedContracts()), 0)
// the contract is currently on the wrong backend, so we need to make it on the right backend
dc := contractRegistry.Get(ctx, contract.ContractType())
assert.Equal(t, dc.ChainID().String(), backend.GetBigChainID().String())
deployedContracts := contractRegistry.GetDeployedContracts()
// make sure dependency count is equal (adding our own contract to their expected amount)
assert.Equal(t, len(deployedContracts), len(contract.Dependencies())+1)
for _, dep := range contract.Dependencies() {
_, hasDep := deployedContracts[dep.ID()]
assert.True(t, hasDep)
}
}
}