Skip to content
This repository has been archived by the owner on Mar 30, 2018. It is now read-only.

Refactor validator into an abstract consensus message handler #108

Closed
binhn opened this issue Oct 22, 2015 · 5 comments
Closed

Refactor validator into an abstract consensus message handler #108

binhn opened this issue Oct 22, 2015 · 5 comments

Comments

@binhn
Copy link
Contributor

binhn commented Oct 22, 2015

Refactor the current code into an abstract consensus message handler to process CONSENSUS messages, and call the function on the payload with the message:

OpenchainMessage {
   type -- CONSENSUS
   payload -- containing the implementor function to receive this message
   ...
}

The payload is an ConsensusMessage object:

type ConsensusMessage struct {
   implementor string // the name of the implementor who has registered with consensus interface
   payload []byte // implementor specific message object
}

The implementor, like PBFT, will implement the following interface:

type Consenter interface {
   init(config)
   receive([]byte) error
}

The 'consensus' package provides public functions for the implementor to interface with the validator, including broadcast messages, execute transactions, and update state.

@binhn
Copy link
Contributor Author

binhn commented Oct 24, 2015

@muralisrini so we can't put the implementor in the payload struct. Another approach is to add a enum subtype into the Consensus struct, and based on the subtype, we call the associated function. However, we can't resolve the function from an enum, so the algorithm implementor would need to change some code in the consensus.go to call its function. For example,

switch(subtype) {
    case pbft:   //call pbft consenter
    case foo:   //call foo consenter
}

@binhn
Copy link
Contributor Author

binhn commented Oct 26, 2015

Murali works out the following pattern:

  1. consensus.go provides interface
  2. registration.go allows a plugin.go to register a key:interface{} pair
  3. plugin.go imports consensus package
  4. registration.go imports plugin package
  5. consensus.go calls the plugin via the interface when msg with key arrives

I updated the issue description.

@kchristidis
Copy link
Contributor

Based on the discussion, @binhn, @muralisrini, and I had today:

consensus.go:

  • Part of the consensus package (obviously).
  • Defines the Consenter interface which should be implemented by every consensus algorithm and consists of the following methods:
    • init(): Automatically run when the package is loaded, this reads a config.yaml file inside the consensus algorithm package (e.g. pbft.) It is used to allow getter methods to be defined (and used by, say, the peer/stream layer).
    • Recv(msg ConsensusMessage) error: unmarshsals the protocol buffer object, does its thing according to what the consensus algorithm dictates, then calls consensus.Broadcast(msg ConsensusMessage).
    • GetParam(param string) string: Allows us to read the config values that were loaded with Init(), e.g. pbft.GetParam(timeout) should give us the timeout value that we want to use for message exchanges.
  • Methods that consensus.go itself should define and expose:
    • SetAlgo(algo Consenter): Sets the local variable currentAlgo equal to algo.
    • HandleMsg(msg OpenchainMessage): Unmarshals the message to extract a ConsensusMessage object, then calls algo.Receive(extractedMsg ConsensusMsg).
    • ExecTx([]TxID) (string, error): Executes a list of transactions, returns the candidate global hash.
    • Broadcast(msg ConsensusMessage) error: Wraps it into an OpenchainMessage object, and then broadcasts the object to all validating peers.

registration.go:

  • Part of the consensus package.
  • Methods that it should define and expose:
    • Register(): A wrapper for consensus.SetAlgo(algo Consenter).

The flow is as follows:

  1. Developers create their own algorithm package, then add an import statement in registration.go for their package, and modify the body of the Register() function so that it runs SetAlgo(own-algorithm-package-goes-here).
  2. When the Openchain network is booted, consensus.go calls the Register() function in register.go, so as to set the currentAlgo variable equal to the Consenter interface variable.
  3. Now whenever an OpenchainMessage is passed on to the consensus layer from the peer/stream layer, the HandleMsg(msg OpenchainMsg) passes it to the Receive(extractedMsg ConsensusMessage) function of the consensus algorithm package we added in step 1.

@binhn
Copy link
Contributor Author

binhn commented Oct 27, 2015

@kchristidis @muralisrini

On the Consenter interface, for the Init(), we can use init() (lower case), which is automatically called by golang when the package is loaded so that it doesn't have to be defined in the interface. This way, we don't have to explicitly call it. Do you see a need that we should call Init() ourselves?

In general, the consensus algo package doesn't have to be under consensus directory. It can be anywhere and may be in a different project. Just need to get the code and build together with obc.

@kchristidis
Copy link
Contributor

@binhn: Both good points.

I don't see a need for us calling Init() ourselves, I just had no idea that Go runs init() when it loads package.

I modified my original post accordingly.

binhn added a commit that referenced this issue Oct 28, 2015
@binhn binhn closed this as completed Oct 30, 2015
@ghost ghost unassigned binhn Aug 25, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Development

No branches or pull requests

2 participants