adjust code to reviews, abstract funcs, clean up files

Former-commit-id: ec19a9de17ec38c54af49684426345056fa3fb07 [formerly a8533d2bcc036bde18583abc4a157d63e552ee06]
Former-commit-id: b085ecaec184ad2c2370388c2717d1e6f8a2e04f
This commit is contained in:
Raul Jordan
2018-02-06 14:04:45 -06:00
parent a9afdd90ef
commit 6fe43bd446
5 changed files with 65 additions and 75 deletions

View File

@@ -1 +0,0 @@
123456

View File

@@ -1,13 +1,17 @@
package sharding
import (
"context"
"fmt"
"io/ioutil"
"strings"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/node"
@@ -78,7 +82,7 @@ func (c *Client) Start() error {
//
// TODO: this function should store the validator's VMC index as a property
// in the client's struct
if err := initVMCValidator(c); err != nil {
if err := joinValidatorSet(c); err != nil {
return err
}
@@ -95,6 +99,13 @@ func (c *Client) Wait() {
// TODO: Blocking lock.
}
// WatchCollationHeaders checks the logs for add_header func calls
// and updates the head collation of the client. We can probably store
// this as a property of the client struct
func (c *Client) WatchCollationHeaders() {
}
// dialRPC endpoint to node.
func dialRPC(endpoint string) (*rpc.Client, error) {
if endpoint == "" {
@@ -119,9 +130,26 @@ func (c *Client) unlockAccount(account accounts.Account) error {
return c.keystore.Unlock(account, pass)
}
// TODO: Watch logs for add_header func calls and update the head collation
// of the client. We can probably store this as a property of the client
// struct
func (c *Client) watchHeaders() {
func (c *Client) createTXOps() (bind.TransactOpts, error) {
accounts := c.keystore.Accounts()
if len(accounts) == 0 {
return bind.TransactOpts{}, fmt.Errorf("no accounts found")
}
if err := c.unlockAccount(accounts[0]); err != nil {
return bind.TransactOpts{}, fmt.Errorf("unable to unlock account 0: %v", err)
}
return bind.TransactOpts{
From: accounts[0].Address,
Signer: func(signer types.Signer, addr common.Address, tx *types.Transaction) (*types.Transaction, error) {
networkID, err := c.client.NetworkID(context.Background())
if err != nil {
return nil, fmt.Errorf("unable to fetch networkID: %v", err)
}
return c.keystore.SignTx(accounts[0], tx, networkID /* chainID */)
},
}, nil
}

View File

@@ -22,26 +22,27 @@ func subscribeBlockHeaders(c *Client) error {
return fmt.Errorf("unable to subscribe to incoming headers. %v", err)
}
log.Info("listening for new headers...")
log.Info("Listening for new headers...")
for {
// TODO: Error handling for getting disconnected from the client
select {
case head := <-headerChan:
// Query the current state to see if we are an eligible proposer
log.Info(fmt.Sprintf("received new header %v", head.Number.String()))
log.Info(fmt.Sprintf("Received new header: %v", head.Number.String()))
// TODO: Only run this code on certain periods?
err := watchShards(c, head)
if err != nil {
if err := checkShardsForProposal(c, head); err != nil {
return fmt.Errorf("unable to watch shards. %v", err)
}
}
}
}
// watchShards checks if we are an eligible proposer for collation for
// the available shards in the VMC. The function calls getEligibleProposer from
// the VMC and proposes a collation if conditions are met
func watchShards(c *Client, head *types.Header) error {
// checkShardsForProposal checks if we are an eligible proposer for
// collation for the available shards in the VMC. The function calls
// getEligibleProposer from the VMC and proposes a collation if
// conditions are met
func checkShardsForProposal(c *Client, head *types.Header) error {
accounts := c.keystore.Accounts()
if len(accounts) == 0 {
@@ -52,31 +53,29 @@ func watchShards(c *Client, head *types.Header) error {
return fmt.Errorf("cannot unlock account. %v", err)
}
log.Info(fmt.Sprint("watching shards..."))
s := 0
for s < shardCount {
log.Info("Watching shards...")
for s := int64(0); s < shardCount; s++ {
// Checks if we are an eligible proposer according to the VMC
ops := bind.CallOpts{}
period := head.Number.Div(head.Number, big.NewInt(int64(periodLength)))
addr, err := c.vmc.VMCCaller.GetEligibleProposer(&ops, big.NewInt(int64(s)), period)
period := head.Number.Div(head.Number, big.NewInt(periodLength))
addr, err := c.vmc.VMCCaller.GetEligibleProposer(&bind.CallOpts{}, big.NewInt(s), period)
// TODO: When we are not a proposer, we get the error of being unable to
// unmarshal empty output. Open issue to deal with this.
// If output is non-empty and the addr == coinbase
if err == nil && addr == accounts[0].Address {
log.Info(fmt.Sprintf("selected as collator on shard %d", s))
log.Info(fmt.Sprintf("Selected as collator on shard: %d", s))
err := proposeCollation(s)
if err != nil {
return fmt.Errorf("could not propose collation. %v", err)
}
}
s++
}
return nil
}
// proposeCollation interacts with the VMC directly to add a collation header
func proposeCollation(shardID int) error {
func proposeCollation(shardID int64) error {
// TODO: Adds a collation header to the VMC with the following fields:
// [
// shard_id: uint256,
@@ -101,6 +100,6 @@ func proposeCollation(shardID int) error {
// This functions will fetch the transactions in the txpool and and apply
// them to finish up the collation. It will then need to broadcast the
// collation to the main chain using JSON-RPC.
log.Info(fmt.Sprint("propose collation called"))
log.Info("Propose collation function called")
return nil
}

View File

@@ -8,13 +8,13 @@ import (
var (
// Number of network shards
shardCount = 100
shardCount = int64(100)
// Address of the validator management contract
validatorManagerAddress = common.HexToAddress("0x0") // TODO
// Gas limit for verifying signatures
sigGasLimit = 40000
// Number of blocks in a period
periodLength = 5
periodLength = int64(5)
// Number of periods ahead of current period which the contract is able to return the collator of that period.
lookaheadPeriods = 4
// Required deposit size in wei

View File

@@ -5,9 +5,6 @@ import (
"fmt"
"time"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/sharding/contracts"
)
@@ -17,32 +14,18 @@ import (
func initVMC(c *Client) error {
b, err := c.client.CodeAt(context.Background(), validatorManagerAddress, nil)
if err != nil {
return fmt.Errorf("unable to get contract code at %s. %v", validatorManagerAddress, err)
return fmt.Errorf("unable to get contract code at %s: %v", validatorManagerAddress, err)
}
if len(b) == 0 {
log.Info(fmt.Sprintf("No validator management contract found at %s. Deploying new contract.", validatorManagerAddress.String()))
accounts := c.keystore.Accounts()
if len(accounts) == 0 {
return fmt.Errorf("no accounts found")
txOps, err := c.createTXOps()
if err != nil {
return fmt.Errorf("unable to intiate the transaction: %v", err)
}
if err := c.unlockAccount(accounts[0]); err != nil {
return fmt.Errorf("unable to unlock account 0: %v", err)
}
ops := bind.TransactOpts{
From: accounts[0].Address,
Signer: func(signer types.Signer, addr common.Address, tx *types.Transaction) (*types.Transaction, error) {
networkID, err := c.client.NetworkID(context.Background())
if err != nil {
return nil, fmt.Errorf("unable to fetch networkID: %v", err)
}
return c.keystore.SignTx(accounts[0], tx, networkID /* chainID */)
},
}
addr, tx, contract, err := contracts.DeployVMC(&ops, c.client)
addr, tx, contract, err := contracts.DeployVMC(&txOps, c.client)
if err != nil {
return fmt.Errorf("unable to deploy validator management contract: %v", err)
}
@@ -67,41 +50,22 @@ func initVMC(c *Client) error {
return nil
}
// initVMCValidator checks if the account is a validator in the VMC. If
// joinValidatorSet checks if the account is a validator in the VMC. If
// the account is not in the set, it will deposit 100ETH into contract.
func initVMCValidator(c *Client) error {
func joinValidatorSet(c *Client) error {
// TODO: Check if account is already in validator set. Fetch this From
// the VMC contract's validator set
// Unlocks the current account from the keystore
accounts := c.keystore.Accounts()
if len(accounts) == 0 {
return fmt.Errorf("no accounts found")
txOps, err := c.createTXOps()
if err != nil {
return fmt.Errorf("unable to intiate the deposit transaction: %v", err)
}
if err := c.unlockAccount(accounts[0]); err != nil {
return fmt.Errorf("unable to unlock account 0: %v", err)
}
// Deposits 100ETH into the VMC from the current account
ops := bind.TransactOpts{
From: accounts[0].Address,
Value: depositSize,
Signer: func(signer types.Signer, addr common.Address, tx *types.Transaction) (*types.Transaction, error) {
networkID, err := c.client.NetworkID(context.Background())
if err != nil {
return nil, fmt.Errorf("unable to fetch networkID: %v", err)
}
return c.keystore.SignTx(accounts[0], tx, networkID /* chainID */)
},
}
_, err := c.vmc.VMCTransactor.Deposit(&ops)
tx, err := c.vmc.VMCTransactor.Deposit(&txOps)
if err != nil {
return fmt.Errorf("unable to deposit eth and become a validator: %v", err)
}
log.Info(fmt.Sprintf("deposited 100ETH into contract"))
log.Info(fmt.Sprintf("Deposited 100ETH into contract with transaction hash: %v", tx.Hash()))
return nil
}