Skip to content

Commit 0576385

Browse files
committed
Fix createValidator logic
1 parent e50fdbe commit 0576385

File tree

10 files changed

+163
-403
lines changed

10 files changed

+163
-403
lines changed

driver/executor/executor.go

+13-6
Original file line numberDiff line numberDiff line change
@@ -193,12 +193,19 @@ func scheduleNodeEvents(node *parser.Node, queue *eventQueue, net driver.Network
193193
name := fmt.Sprintf("%s-%d", node.Name, i)
194194
var instance = new(driver.Node)
195195
queue.add(toSingleEvent(startTime, fmt.Sprintf("starting node %s", name), func() error {
196-
newNode, err := net.CreateNode(&driver.NodeConfig{
197-
Name: name,
198-
Validator: node.IsValidator(),
199-
})
200-
*instance = newNode
201-
return err
196+
if node.IsValidator() {
197+
newNode, err := net.CreateValidatorNode(&driver.NodeConfig{
198+
Name: name,
199+
})
200+
*instance = newNode
201+
return err
202+
} else {
203+
newNode, err := net.CreateNode(&driver.NodeConfig{
204+
Name: name,
205+
})
206+
*instance = newNode
207+
return err
208+
}
202209
}))
203210

204211
if &node.Genesis != nil {

driver/network.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ type Network interface {
3434
// nodes to the network as needed.
3535
CreateNode(config *NodeConfig) (Node, error)
3636

37+
CreateValidatorNode(config *NodeConfig) (Node, error)
38+
3739
// RemoveNode removes node from the network
3840
RemoveNode(Node) error
3941

@@ -87,8 +89,7 @@ type NetworkListener interface {
8789
}
8890

8991
type NodeConfig struct {
90-
Name string
91-
Validator bool
92+
Name string
9293
// TODO: add other parameters as needed
9394
// - features to include on the node
9495
// - state DB configuration

driver/network/local/local.go

+58-54
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ type LocalNetwork struct {
5555
// validators lists the validator nodes in the network. Validators
5656
// are created during network startup and run for the full duration
5757
// of the network.
58+
// TODO dynamically created validators are not added to this list. Can't be added without old epoch is sealed, because method randomValidatorRPC could return a non validator node.
5859
validators []*node.OperaNode
5960

6061
// nodes provide a register for all nodes in the network, including
@@ -180,58 +181,65 @@ func (n *LocalNetwork) createNode(nodeConfig *node.OperaNodeConfig) (*node.Opera
180181

181182
// CreateNode creates nodes in the network during run.
182183
func (n *LocalNetwork) CreateNode(config *driver.NodeConfig) (driver.Node, error) {
184+
return n.createNode(&node.OperaNodeConfig{
185+
Label: config.Name,
186+
NetworkConfig: &n.config,
187+
VmImplementation: n.config.VmImplementation,
188+
})
189+
}
190+
191+
// CreateValidatorNode creates validator non genesis validator node in the network during run.
192+
func (n *LocalNetwork) CreateValidatorNode(config *driver.NodeConfig) (driver.Node, error) {
183193
newValId := 0
184-
if config.Validator {
185-
log.Printf("Creating validator node %s", config.Name)
186-
rpcClient, err := n.DialRandomRpc()
187-
if err != nil {
188-
return nil, err
189-
}
190-
defer rpcClient.Close()
194+
//
195+
rpcClient, err := n.dialRandomGenesisValidatorRpc()
196+
if err != nil {
197+
return nil, err
198+
}
199+
defer rpcClient.Close()
191200

192-
// get a representation of the deployed contract
193-
SFCContract, err := contract.NewSFC(common.HexToAddress("0xFC00FACE00000000000000000000000000000000"), rpcClient)
194-
if err != nil {
195-
return nil, fmt.Errorf("failed to get SFC contract representation; %v", err)
196-
}
201+
// get a representation of the deployed contract
202+
SFCContract, err := contract.NewSFC(common.HexToAddress("0xFC00FACE00000000000000000000000000000000"), rpcClient)
203+
if err != nil {
204+
return nil, fmt.Errorf("failed to get SFC contract representation; %v", err)
205+
}
197206

198-
var lastValId *big.Int
199-
lastValId, err = SFCContract.LastValidatorID(nil)
200-
if err != nil {
201-
return nil, fmt.Errorf("failed to get validator count; %v", err)
202-
}
207+
var lastValId *big.Int
208+
lastValId, err = SFCContract.LastValidatorID(nil)
209+
if err != nil {
210+
return nil, fmt.Errorf("failed to get validator count; %v", err)
211+
}
203212

204-
newValId = int(lastValId.Int64()) + 1
205-
fmt.Println("newValId", newValId)
213+
newValId = int(lastValId.Int64()) + 1
214+
log.Printf("Creating validator node %s; %d", config.Name, newValId)
206215

207-
privateKeyECDSA := evmcore.FakeKey(uint32(newValId))
208-
validatorPubKey := validatorpk.PubKey{
209-
Raw: crypto.FromECDSAPub(&privateKeyECDSA.PublicKey),
210-
Type: validatorpk.Types.Secp256k1,
211-
}
216+
privateKeyECDSA := evmcore.FakeKey(uint32(newValId))
217+
validatorPubKey := validatorpk.PubKey{
218+
Raw: crypto.FromECDSAPub(&privateKeyECDSA.PublicKey),
219+
Type: validatorpk.Types.Secp256k1,
220+
}
212221

213-
validatorPrivateKeykHex := strings.TrimPrefix(hexutil.Encode(crypto.FromECDSA(privateKeyECDSA)), "0x")
214-
validatorAccount, err := app.NewAccount(newValId, validatorPrivateKeykHex, validatorPubKey.Raw, 0xfa3)
215-
if err != nil {
216-
return nil, fmt.Errorf("failed to create validator account: %v", err)
217-
}
222+
validatorPrivateKeykHex := strings.TrimPrefix(hexutil.Encode(crypto.FromECDSA(privateKeyECDSA)), "0x")
223+
validatorAccount, err := app.NewAccount(newValId, validatorPrivateKeykHex, validatorPubKey.Bytes(), 0xfa3)
224+
if err != nil {
225+
return nil, fmt.Errorf("failed to create validator account: %v", err)
226+
}
218227

219-
_, err = validatorAccount.CreateValidator(SFCContract, rpcClient)
220-
if err != nil {
221-
return nil, err
222-
}
223-
err = app.WaitUntilAccountNonceIs(crypto.PubkeyToAddress(privateKeyECDSA.PublicKey), 1, rpcClient)
224-
if err != nil {
225-
return nil, fmt.Errorf("createValidator; failed to wait for nonce; %v", err)
226-
}
228+
_, err = validatorAccount.CreateValidator(SFCContract, rpcClient)
229+
if err != nil {
230+
return nil, err
231+
}
232+
err = app.WaitUntilAccountNonceIs(crypto.PubkeyToAddress(privateKeyECDSA.PublicKey), 1, rpcClient)
233+
if err != nil {
234+
return nil, fmt.Errorf("createValidator; failed to wait for nonce; %v", err)
235+
}
227236

228-
lastValId, err = SFCContract.LastValidatorID(nil)
229-
if err != nil {
230-
return nil, fmt.Errorf("failed to get validator count; %v", err)
231-
}
232-
if newValId != int(lastValId.Int64()) {
233-
return nil, fmt.Errorf("failed to create validator %d", newValId)
234-
}
237+
lastValId, err = SFCContract.LastValidatorID(nil)
238+
if err != nil {
239+
return nil, fmt.Errorf("failed to get validator count; %v", err)
240+
}
241+
if newValId != int(lastValId.Int64()) {
242+
return nil, fmt.Errorf("failed to create validator %d", newValId)
235243
}
236244

237245
return n.createNode(&node.OperaNodeConfig{
@@ -276,7 +284,11 @@ func (n *LocalNetwork) DialRandomRpc() (rpc2.RpcClient, error) {
276284
return nodes[rand.Intn(len(nodes))].DialRpc()
277285
}
278286

279-
func (n *LocalNetwork) dialRandomValidatorRpc() (rpc2.RpcClient, error) {
287+
// dialRandomGenesisValidatorRpc dials a random genesis validator node.
288+
// When network starts and still doesn't have any traffic, then first transaction must come from validator node.
289+
// Caused by: the regular nodes even when connected won't send transactions from their txpool,
290+
// because they don't know whether they are on head or not if blockchain is empty.
291+
func (n *LocalNetwork) dialRandomGenesisValidatorRpc() (rpc2.RpcClient, error) {
280292
return n.validators[rand.Intn(len(n.validators))].DialRpc()
281293
}
282294

@@ -336,16 +348,8 @@ func (a *localApplication) GetReceivedTransactions() (uint64, error) {
336348
return a.controller.GetReceivedTransactions()
337349
}
338350

339-
//func (n *LocalNetwork) CreateValidator(config *driver.NodeConfig) (driver.Node, error) {
340-
// return n.createNode(&node.OperaNodeConfig{
341-
// Label: config.Name,
342-
// NetworkConfig: &n.config,
343-
// VmImplementation: n.config.VmImplementation,
344-
// })
345-
//}
346-
347351
func (n *LocalNetwork) CreateApplication(config *driver.ApplicationConfig) (driver.Application, error) {
348-
rpcClient, err := n.dialRandomValidatorRpc()
352+
rpcClient, err := n.dialRandomGenesisValidatorRpc()
349353
if err != nil {
350354
return nil, fmt.Errorf("failed to connect to RPC to initialize the application; %v", err)
351355
}

driver/network_mock.go

+29-25
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

driver/parser/check.go

+36-2
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,11 @@ func (s *Scenario) Check() error {
4040
if s.Duration <= 0 {
4141
errs = append(errs, fmt.Errorf("scenario duration must be > 0"))
4242
}
43-
if s.NumValidators != nil && *s.NumValidators <= 0 {
44-
errs = append(errs, fmt.Errorf("invalid number of validators: %d <= 0", *s.NumValidators))
43+
44+
if err := s.checkValidatorConstrains(); err != nil {
45+
errs = append(errs, err)
4546
}
47+
4648
names := map[string]bool{}
4749
for _, node := range s.Nodes {
4850
if err := node.Check(s); err != nil {
@@ -295,3 +297,35 @@ func checkTimeInterval(start, end *float32, duration float32) error {
295297
}
296298
return errors.Join(errs...)
297299
}
300+
301+
// checkValidatorConstrains makes sure that there is correct number of validators
302+
// if during whole run there are just genesis validators, then one validator is enough
303+
// if there is creation of new validators trough sfc, then at all times there has to be at least two validators validating at every time
304+
// note during run validator won't be immediately registered for epoch, because it only happens during epoch seal,
305+
// therefore this check is not sufficient on its own
306+
func (s *Scenario) checkValidatorConstrains() error {
307+
// check genesis validators
308+
if s.NumValidators != nil && *s.NumValidators <= 0 {
309+
return fmt.Errorf("invalid number of validators: %d <= 0", *s.NumValidators)
310+
}
311+
312+
dynamicVals := make([]Node, 0)
313+
// check dynamically created validators
314+
for _, node := range s.Nodes {
315+
if node.IsValidator() {
316+
dynamicVals = append(dynamicVals, node)
317+
}
318+
}
319+
320+
if len(dynamicVals) == 0 {
321+
return nil
322+
}
323+
324+
if *s.NumValidators < 2 {
325+
return fmt.Errorf("invalid number of genesis validators for sfc createValidator scenario: %d < 2", *s.NumValidators)
326+
}
327+
328+
// TODO add check for dynamic validators to have always at least two running at any time
329+
// needs to be implemented before enabling to shut down genesis validators
330+
return nil
331+
}

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ require (
1313
github.com/tyler-smith/go-bip32 v1.0.0
1414
github.com/tyler-smith/go-bip39 v1.1.0
1515
github.com/urfave/cli/v2 v2.25.7
16+
go.uber.org/mock v0.2.0
1617
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
1718
gopkg.in/yaml.v3 v3.0.1
1819
)

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,8 @@ go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
475475
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
476476
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
477477
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
478+
go.uber.org/mock v0.2.0 h1:TaP3xedm7JaAgScZO7tlvlKrqT0p7I6OsdGB5YNSMDU=
479+
go.uber.org/mock v0.2.0/go.mod h1:J0y0rp9L3xiff1+ZBfKxlC1fz2+aO16tw0tsDOixfuM=
478480
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
479481
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
480482
golang.org/x/crypto v0.0.0-20170613210332-850760c427c5/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=

0 commit comments

Comments
 (0)