Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rearchitecting the Sharding Node, its Lifecycle, and Services #127

Merged
merged 18 commits into from
May 23, 2018
Merged

Rearchitecting the Sharding Node, its Lifecycle, and Services #127

merged 18 commits into from
May 23, 2018

Conversation

rauljordan
Copy link
Contributor

@rauljordan rauljordan commented May 22, 2018

Hi all,

This is a PR referencing the recent issues #126 #122. The idea is to make our sharding implementation have a single entry point that kicks off an independent node responsible for handling services and protocols related to sharding. Specifically, we consider Notary and Proposer to be protocols that can be registered to a sharding node upon startup, alongside shardp2p, and SMC contract bindings. This design is meant to abstract responsibilities into a more modular fashion and make the node be responsible for the lifecycle of each service, which is something each service should not be concerned with.

Design Rationale

TODO: rauljordan

Requirements for Merge

  • All tests passing
  • Notary/Proposer services as they used to before but with the new architecture
  • Allow for sharding node to manage lifecycle of notaries and proposers
  • A single place for configuration of this sharding node dependent on cli flags

@rauljordan rauljordan added this to the Ruby milestone May 22, 2018
@rauljordan rauljordan self-assigned this May 22, 2018
@rauljordan rauljordan added this to To do in Validator Client via automation May 22, 2018
// Stop the main loop for proposing collations.
func (p *Proposer) Stop() error {
log.Info("Stopping proposer service")
// TODO: Propose collations.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why

// Stop the main loop for notarizing collations.
func (n *Notary) Stop() error {
log.Info("Stopping notary service")
// TODO: Propose collations.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eliminated this

if protocolFlag == "notary" {
return notary.NewNotary(n.Context(), n)
}
return proposer.NewProposer(n.Context(), n)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (protocolFlag == "proposer") ?

The default behavior would be just an observer right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, added a TODO for default behavior assigned to @terenc3t if the flag is not passed in

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fine, I can open another PR to handle the default behavior

}
ProtocolFlag = cli.StringFlag{
Name: "protocol",
Usage: "notary | proposer",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add more of a description than this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 on more descriptions

Usage: "To become a notary in a sharding node, " + new(big.Int).Div(sharding.NotaryDeposit, new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil)).String() + " ETH will be deposited into SMC",
}
ProtocolFlag = cli.StringFlag{
Name: "protocol",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is protocol the correct flag name? What about actor or role?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actor sounds good to me

func notaryClient(ctx *cli.Context) error {
c := notary.NewNotary(ctx)
return c.Start()
func shardingClient(ctx *cli.Context) error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add an overall comment on what shardingClient is?

if protocolFlag == "notary" {
return notary.NewNotary(n.Context(), n)
}
return proposer.NewProposer(n.Context(), n)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fine, I can open another PR to handle the default behavior

}
ProtocolFlag = cli.StringFlag{
Name: "protocol",
Usage: "notary | proposer",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 on more descriptions

- Ability to deposit ETH into the SMC through the command line and to be selected as a notary by the local **SMC** in addition to the ability to withdraw the ETH staked
- A **proposer client** that listens for pending tx’s, creates collations, and submits them to the SMC
- A **proposer protocol** that listens for pending tx’s, creates collations, and submits them to the SMC
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

protocol sounds funny. Should we change it to node or actor? for the rest of the files too


## Running a Collation Proposal Client
## Running a Collation Proposal Node

```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you can put a short para explaining that if they launch the sharding node without the protocol flag, an observer node is launched instead geth sharding --datadir /path/to/your/datadir --password /path/to/your/password.txt --networkid 12345

func notaryClient(ctx *cli.Context) error {
c := notary.NewNotary(ctx)
return c.Start()
func shardingClient(ctx *cli.Context) error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't it be named shardingNode instead now ?

// TODO(terenc3t): handle case when we just want to start an observer node.
if protocolFlag == "notary" {
return notary.NewNotary(n.Context(), n)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make this instead if we will be having observer nodes

else if protocolFlag == "proposer" {
		return notary.NewProposer(n.Context(), n)
		}
return proposer.NewObserver(n.Context(), n)

@@ -183,15 +183,15 @@ Our Ruby Release requires users to start a local geth node running a localized,

geth sharding-notary --deposit --datadir /path/to/your/datadir --password /path/to/your/password.txt --networkid 12345
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change this to geth sharding --protocol "notary" . Same thing below for proposer

@nisdas
Copy link
Member

nisdas commented May 22, 2018

LGTM

func sharding(ctx *cli.Context) error {
// configures a sharding-enabled node using the cli's context.
shardingNode := node.NewNode(ctx)
registerShardingServices(shardingNode)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

registerShardingServices returns an error. Do we want to check for if err != nil?

func registerShardingServices(n node.Node) error {
actorFlag := n.Context().GlobalString(utils.ActorFlag.Name)

err := n.Register(func(ctx *cli.Context) (sharding.Service, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ctx is not used here

Copy link
Member

@terencechain terencechain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work @rauljordan! I'm a fan of this architecture. I see Notary interface and Proposer interface are no longer needed, because the specific actor methods are part service within serviceFuncs

}

// NewNotary creates a new notary instance.
func NewNotary(ctx *cli.Context, node node.Node) (*Notary, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ctx is unused here, same for NewProposer

Copy link
Member

@terencechain terencechain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Just one last comment then we can merge

@@ -103,7 +103,7 @@ func (n *shardingNode) Start() error {
// Starts every service attached to the sharding node.
for _, serviceFunc := range n.serviceFuncs {
// Initializes each service by passing in the node's cli context.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// Initializes each service by passing in the node's cli context
We are not passing in the cli context anymore

Copy link
Member

@prestonvanloon prestonvanloon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not too sure about those .String()s since they were already there. Consider those comments optional.

Thanks

}
ActorFlag = cli.StringFlag{
Name: "actor",
Usage: `use the --actor "notary" or --actor "proposer" to start a notary or proposer service in the sharding node. If omitted, the sharding node registers an Observer service that simply observes the activity in the sharded network`,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You shouldn't need the quotes for a flag value. It's fine but FYI.


scryptN, scryptP, keydir, err := config.AccountConfig()
if err != nil {
panic(err) // TODO(prestonvanloon): handle this.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method returns an error, just return the error instead of panic. I had a panic somewhere because I needed to refactor it.

ctx *cli.Context // Command line context.
smc *contracts.SMC // The deployed sharding management contract.
rpcClient *rpc.Client // The RPC client connection to the main geth node.
lock sync.RWMutex // Mutex lock for concurrency management.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why RWMutex vs Mutex if you don't have any RLock / readers?

Do you need this mutex at all if only one method is calling lock? Is it being called multiple times?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Im assuming the register function can be called in various scenarios concurrently, and I'd rather take care of potential concurrency problems now. I'll replace with a simple sync.Mutex.

}

// Context returns the cli context.
func (n *shardingNode) Context() *cli.Context {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to expose this or would it better to provide a helper method to return the actor flag value? Kind of like DepositFlagSet

I'm just wondering if we can reduce the number of references to cli.Context.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This occurs in various place where we only have access to a Node interface, and I believe we are passing in the context to several other functions that will use this cli context to configure certain options.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we can explore this as an issue after merge?


contract, err := contracts.NewSMC(sharding.ShardingManagerAddress, n.client)
if err != nil {
// TODO(terenc3t): handle this
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please return the error. What is there to handle here?

return contracts.NewSMC(...)

// TODO: Separate contract deployment from the sharding node. It would only need to be deployed
// once on the mainnet, so this code would not need to ship with the node.
if len(b) == 0 {
log.Info(fmt.Sprintf("No sharding manager contract found at %s. Deploying new contract.", sharding.ShardingManagerAddress.String()))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not call String()


txOps, err := n.CreateTXOpts(big.NewInt(0))
if err != nil {
return nil, fmt.Errorf("unable to intiate the transaction: %v", err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo

return nil, fmt.Errorf("unable to deploy sharding manager contract: %v", err)
}

for pending := true; pending; _, pending, err = n.client.TransactionByHash(context.Background(), tx.Hash()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for the pending conditional to make a while loop

		for {
			if err = n.client.TransactionByHash(context.Background(), tx.Hash()); err != nil {
				return nil, fmt.Errorf("unable to get transaction by hash: %v", err)
			}
			time.Sleep(1 * time.Second)
		}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting: unreachable code right below it

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I misunderstood the code here.

time.Sleep(1 * time.Second)
}

log.Info(fmt.Sprintf("New contract deployed at %s", addr.String()))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need to call String()? The formatter should call this.

Copy link
Member

@prestonvanloon prestonvanloon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Look good to me. I still disagree with the node interface returning access to a cli.Context object for consumers but I’m happy to explore after merge.

return nil, fmt.Errorf("unable to deploy sharding manager contract: %v", err)
}

for pending := true; pending; _, pending, err = n.client.TransactionByHash(context.Background(), tx.Hash()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I misunderstood the code here.

@rauljordan rauljordan merged commit 9db6161 into prysmaticlabs:master May 23, 2018
Validator Client automation moved this from To do to Done May 23, 2018
prestonvanloon pushed a commit that referenced this pull request Jul 22, 2018
Rearchitecting the Sharding Node, its Lifecycle, and Services
prestonvanloon pushed a commit that referenced this pull request Jul 22, 2018
Rearchitecting the Sharding Node, its Lifecycle, and Services

Former-commit-id: f3cda01
prestonvanloon pushed a commit that referenced this pull request Jul 22, 2018
Rearchitecting the Sharding Node, its Lifecycle, and Services

Former-commit-id: a19a24106107c24b665c2a76240c7841fb270109 [formerly f3cda01]
Former-commit-id: 6932c93
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
No open projects
Development

Successfully merging this pull request may close these issues.

None yet

4 participants