merge 1.8.12 with upstream/master to apply the fixes/changes added newly

This commit is contained in:
amalraj.manigmail.com 2018-08-06 19:03:51 +08:00
commit e6773756fb
21 changed files with 357 additions and 125 deletions

View File

@ -1,6 +1,6 @@
# Quorum
<a href="https://quorumslack.azurewebsites.net" target="_blank" rel="noopener"><img title="Quorum Slack" src="https://quorumslack.azurewebsites.net/badge.svg" alt="Quorum Slack" /></a>
<a href="https://clh7rniov2.execute-api.us-east-1.amazonaws.com/Express/" target="_blank" rel="noopener"><img title="Quorum Slack" src="https://clh7rniov2.execute-api.us-east-1.amazonaws.com/Express/badge.svg" alt="Quorum Slack" /></a>
Quorum is an Ethereum-based distributed ledger protocol with transaction/contract privacy and new consensus mechanisms.
@ -143,6 +143,7 @@ Further documentation can be found in the [docs](docs/) folder and on the [wiki]
* [quorum-examples](https://github.com/jpmorganchase/quorum-examples): example quorum clusters
* [quorum-tools](https://github.com/jpmorganchase/quorum-tools): local cluster orchestration, and integration testing tool
* [Quorum Wiki](https://github.com/jpmorganchase/quorum/wiki)
* [Quorum Community Slack Inviter](https://clh7rniov2.execute-api.us-east-1.amazonaws.com/Express/): Quorum Slack community entry point
## Third Party Tools/Libraries

View File

@ -278,7 +278,7 @@ func (ks *KeyStore) SignTx(a accounts.Account, tx *types.Transaction, chainID *b
return nil, ErrLocked
}
// Depending on the presence of the chain ID, sign with EIP155 or homestead
if chainID != nil && !isQuorum {
if chainID != nil && !tx.IsPrivate() {
return types.SignTx(tx, types.NewEIP155Signer(chainID), unlockedKey.PrivateKey)
}
return types.SignTx(tx, types.HomesteadSigner{}, unlockedKey.PrivateKey)

View File

@ -562,6 +562,9 @@ func (ethash *Ethash) SetThreads(threads int) {
// Hashrate implements PoW, returning the measured rate of the search invocations
// per second over the last minute.
func (ethash *Ethash) Hashrate() float64 {
if(ethash.hashrate == nil){
return 0
}
return ethash.hashrate.Rate1()
}

View File

@ -781,7 +781,7 @@ func TestChainTxReorgs(t *testing.T) {
db = ethdb.NewMemDatabase()
gspec = &Genesis{
Config: params.TestChainConfig,
GasLimit: 31415920,
GasLimit: 700000000,
Alloc: GenesisAlloc{
addr1: {Balance: big.NewInt(1000000)},
addr2: {Balance: big.NewInt(1000000)},
@ -1068,7 +1068,7 @@ func TestEIP155Transition(t *testing.T) {
funds = big.NewInt(1000000000)
deleteAddr = common.Address{1}
gspec = &Genesis{
Config: &params.ChainConfig{ChainID: big.NewInt(10), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)},
Config: &params.ChainConfig{ChainId: big.NewInt(10), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)},
Alloc: GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}},
}
genesis = gspec.MustCommit(db)
@ -1139,7 +1139,7 @@ func TestEIP155Transition(t *testing.T) {
}
// generate an invalid chain id transaction
config := &params.ChainConfig{ChainID: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
config := &params.ChainConfig{ChainId: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
blocks, _ = GenerateChain(config, blocks[len(blocks)-1], ethash.NewFaker(), db, 4, func(i int, block *BlockGen) {
var (
tx *types.Transaction
@ -1173,7 +1173,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
theAddr = common.Address{1}
gspec = &Genesis{
Config: &params.ChainConfig{
ChainID: big.NewInt(10),
ChainId: big.NewInt(10),
HomesteadBlock: new(big.Int),
EIP155Block: new(big.Int),
EIP158Block: big.NewInt(2),
@ -1189,7 +1189,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
var (
tx *types.Transaction
err error
signer = types.NewEIP155Signer(gspec.Config.ChainID)
signer = types.NewEIP155Signer(gspec.Config.ChainId)
)
switch i {
case 0:

View File

@ -161,6 +161,10 @@ func (c *stateObject) getTrie(db Database) Trie {
return c.trie
}
func (so *stateObject) storageRoot(db Database) common.Hash {
return so.getTrie(db).Hash()
}
// GetState returns a value in account storage.
func (self *stateObject) GetState(db Database, key common.Hash) common.Hash {
value, exists := self.cachedStorage[key]

View File

@ -268,6 +268,15 @@ func (self *StateDB) HasSuicided(addr common.Address) bool {
return false
}
// GetStorageRoot returns the root of the storage associated with the given address.
func (self *StateDB) GetStorageRoot(addr common.Address) (common.Hash, error) {
so := self.getStateObject(addr)
if so == nil {
return common.Hash{}, fmt.Errorf("can't find state object")
}
return so.storageRoot(self.db), nil
}
/*
* SETTERS
*/

View File

@ -117,6 +117,37 @@ func TestIntermediateLeaks(t *testing.T) {
}
}
func TestStorageRoot(t *testing.T) {
var (
mem, _ = ethdb.NewMemDatabase()
db = NewDatabase(mem)
state, _ = New(common.Hash{}, db)
addr = common.Address{1}
key = common.Hash{1}
value = common.Hash{42}
empty = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
)
so := state.GetOrNewStateObject(addr)
emptyRoot := so.storageRoot(db)
if emptyRoot != empty {
t.Errorf("Invalid empty storage root, expected %x, got %x", empty, emptyRoot)
}
// add a bit of state
so.SetState(db, key, value)
state.CommitTo(mem, false)
root := so.storageRoot(db)
expected := common.HexToHash("63511abd258fa907afa30cb118b53744a4f49055bb3f531da512c6b866fc2ffb")
if expected != root {
t.Errorf("Invalid storage root, expected %x, got %x", expected, root)
}
}
// TestCopy tests that copying a statedb object indeed makes the original and
// the copy independent of each other. This test is a regression test against
// https://github.com/ethereum/go-ethereum/pull/15549.

View File

@ -253,6 +253,10 @@ func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bo
if len(data) == 0 && isPrivate {
return nil, 0, false, nil
}
//if input is empty for a private smart contract call, return
if len(data) == 0 && isPrivate{
return nil, new(big.Int), new(big.Int), false, nil
}
ret, st.gas, vmerr = evm.Call(sender, to, data, st.gas, st.value)
}
if vmerr != nil {

View File

@ -78,6 +78,10 @@ var (
ErrOversizedData = errors.New("oversized data")
ErrInvalidGasPrice = errors.New("Gas price not 0")
// ErrEtherValueUnsupported is returned if a transaction specifies an Ether Value
// for a private Quorum transaction.
ErrEtherValueUnsupported = errors.New("ether value is not supported for private transactions")
)
var (
@ -587,6 +591,10 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
if pool.currentState.GetNonce(from) > tx.Nonce() {
return ErrNonceTooLow
}
// Ether value is not currently supported on private transactions
if tx.IsPrivate() && (tx.Value().Sign() != 0) {
return ErrEtherValueUnsupported;
}
// Transactor should have enough funds to cover the costs
// cost == V + GP * GL
if pool.currentState.GetBalance(from).Cmp(tx.Cost()) < 0 {
@ -596,7 +604,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
if err != nil {
return err
}
if !isQuorum && tx.Gas() < intrGas {
if tx.Gas() < intrGas {
return ErrIntrinsicGas
}
return nil
@ -626,7 +634,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) {
// If the transaction pool is full, discard underpriced transactions
if uint64(pool.all.Count()) >= pool.config.GlobalSlots+pool.config.GlobalQueue {
// If the new transaction is underpriced, don't accept it
if !pool.chainconfig.IsQuorum && !local && pool.priced.Underpriced(tx, pool.locals) {
if !pool.chainconfig.IsQuorum && pool.priced.Underpriced(tx, pool.locals) {
log.Trace("Discarding underpriced transaction", "hash", hash, "price", tx.GasPrice())
underpricedTxCounter.Inc(1)
return false, ErrUnderpriced
@ -760,7 +768,6 @@ func (pool *TxPool) promoteTx(addr common.Address, hash common.Hash, tx *types.T
return true
}
// AddLocal enqueues a single transaction into the pool if it is valid, marking
// the sender as a local one in the mean time, ensuring it goes around the local
// pricing constraints.
@ -817,8 +824,8 @@ func (pool *TxPool) addTxs(txs []*types.Transaction, local bool) []error {
// addTxsLocked attempts to queue a batch of transactions if they are valid,
// whilst assuming the transaction pool lock is already held.
func (pool *TxPool) addTxsLocked(txs []*types.Transaction, local bool) []error {
// Add the batch of transaction, tracking the accepted ones
func (pool *TxPool) addTxsLocked(txs []*types.Transaction, local bool) error {
// Add the batch of transactions, tracking the accepted ones
dirty := make(map[common.Address]struct{})
errs := make([]error, len(txs))
@ -1120,7 +1127,7 @@ func (pool *TxPool) demoteUnexecutables() {
log.Trace("Demoting pending transaction", "hash", hash)
pool.enqueueTx(hash, tx)
}
// If there's a gap in front, alert (should never happen) and postpone all transactions
// If there's a gap in front, warn (should never happen) and postpone all transactions
if list.Len() > 0 && list.txs.Get(nonce) == nil {
for _, tx := range list.Cap(0) {
hash := tx.Hash()

View File

@ -19,13 +19,8 @@ package core
import (
"crypto/ecdsa"
"fmt"
"io/ioutil"
"math/big"
"math/rand"
"os"
"testing"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
@ -33,6 +28,10 @@ import (
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/params"
"math/rand"
"time"
"io/ioutil"
"os"
)
// testTxPoolConfig is a transaction pool configuration without stateful disk
@ -88,6 +87,17 @@ func setupTxPool() (*TxPool, *ecdsa.PrivateKey) {
return pool, key
}
func setupQuorumTxPool() (*TxPool, *ecdsa.PrivateKey) {
db, _ := ethdb.NewMemDatabase()
statedb, _ := state.New(common.Hash{}, state.NewDatabase(db))
blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)}
key, _ := crypto.GenerateKey()
pool := NewTxPool(testTxPoolConfig, params.QuorumTestChainConfig, blockchain)
return pool, key
}
// validateTxPoolInternals checks various consistency invariants within the pool.
func validateTxPoolInternals(pool *TxPool) error {
pool.mu.RLock()
@ -223,6 +233,7 @@ func TestStateChangeDuringTransactionPoolReset(t *testing.T) {
}
}
//Test for transactions that are invalid on Ethereum
func TestInvalidTransactions(t *testing.T) {
t.Parallel()
@ -234,30 +245,64 @@ func TestInvalidTransactions(t *testing.T) {
pool.currentState.AddBalance(from, big.NewInt(1))
if err := pool.AddRemote(tx); err != ErrInsufficientFunds {
t.Error("expected", ErrInsufficientFunds)
t.Error("expected", ErrInsufficientFunds, "; got", err)
}
balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(new(big.Int).SetUint64(tx.Gas()), tx.GasPrice()))
pool.currentState.AddBalance(from, balance)
if err := pool.AddRemote(tx); err != ErrIntrinsicGas {
t.Error("expected", ErrIntrinsicGas, "got", err)
t.Error("expected", ErrIntrinsicGas, "; got", err)
}
pool.currentState.SetNonce(from, 1)
pool.currentState.AddBalance(from, big.NewInt(0xffffffffffffff))
tx = transaction(0, 100000, key)
if err := pool.AddRemote(tx); err != ErrNonceTooLow {
t.Error("expected", ErrNonceTooLow)
t.Error("expected", ErrNonceTooLow, "; got", err)
}
tx = transaction(1, 100000, key)
pool.gasPrice = big.NewInt(1000)
if err := pool.AddRemote(tx); err != ErrUnderpriced {
t.Error("expected", ErrUnderpriced, "got", err)
t.Error("expected", ErrUnderpriced, "; got", err)
}
if err := pool.AddLocal(tx); err != nil {
t.Error("expected", nil, "got", err)
t.Error("expected", nil, "; got", err)
}
tooMuchGas := big.NewInt(0).Add(pool.currentMaxGas, big.NewInt(1))
tx1 := transaction(2, tooMuchGas, key)
if err := pool.AddRemote(tx1); err != ErrGasLimit {
t.Error("expected", ErrGasLimit, "; got", err)
}
data := make([]byte, (32*1024)+1)
tx2, _ := types.SignTx(types.NewTransaction(2, common.Address{}, big.NewInt(100), big.NewInt(100000), big.NewInt(1), data), types.HomesteadSigner{}, key)
if err := pool.AddRemote(tx2); err != ErrOversizedData {
t.Error("expected", ErrOversizedData, "; got", err)
}
tx3, _ := types.SignTx(types.NewTransaction(1, common.Address{}, big.NewInt(100), common.Big0, big.NewInt(0), nil), types.HomesteadSigner{}, key)
balance = new(big.Int).Add(tx3.Value(), new(big.Int).Mul(tx3.Gas(), tx3.GasPrice()))
from, _ = deriveSender(tx3)
pool.currentState.AddBalance(from, balance)
tx3.SetPrivate()
if err := pool.AddRemote(tx3); err != ErrEtherValueUnsupported {
t.Error("expected", ErrEtherValueUnsupported, "; got", err)
}
}
//Test for transactions that are only invalid on Quorum
func TestQuorumInvalidTransactions(t *testing.T) {
pool, key := setupQuorumTxPool()
defer pool.Stop()
tx := transaction(0, common.Big0, key)
if err := pool.AddRemote(tx); err != ErrInvalidGasPrice {
t.Error("expected", ErrInvalidGasPrice, "; got", err)
}
}
func TestTransactionQueue(t *testing.T) {

View File

@ -129,9 +129,7 @@ func isProtectedV(V *big.Int) bool {
if V.BitLen() <= 8 {
v := V.Uint64()
// 27 / 28 are pre eip 155 -- ie unprotected.
// TODO(joel): this is a hack. Everywhere else we maintain vanilla ethereum
// compatibility and we should figure out how to extend that to here
return !(v == 27 || v == 28 || v == 37 || v == 38)
return !(v == 27 || v == 28)
}
// anything not 27 or 28 are considered unprotected
return true

View File

@ -62,6 +62,33 @@ func (api *PublicEthereumAPI) Coinbase() (common.Address, error) {
return api.Etherbase()
}
// StorageRoot returns the storage root of an account on the the given (optional) block height.
// If block number is not given the latest block is used.
func (s *PublicEthereumAPI) StorageRoot(addr common.Address, blockNr *rpc.BlockNumber) (common.Hash, error) {
var (
pub, priv *state.StateDB
err error
)
if blockNr == nil || blockNr.Int64() == rpc.LatestBlockNumber.Int64() {
pub, priv, err = s.e.blockchain.State()
} else {
if ch := s.e.blockchain.GetHeaderByNumber(uint64(blockNr.Int64())); ch != nil {
pub, priv, err = s.e.blockchain.StateAt(ch.Root)
} else {
return common.Hash{}, fmt.Errorf("invalid block number")
}
}
if err != nil {
return common.Hash{}, err
}
if priv.Exist(addr) {
return priv.GetStorageRoot(addr)
}
return pub.GetStorageRoot(addr)
}
// Hashrate returns the POW hashrate
func (api *PublicEthereumAPI) Hashrate() hexutil.Uint64 {
return hexutil.Uint64(api.e.Miner().HashRate())

View File

@ -361,7 +361,7 @@ func (s *PrivateAccountAPI) signTransaction(ctx context.Context, args SendTxArgs
var chainID *big.Int
if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) {
chainID = config.ChainID
chainID = config.ChainId
}
return wallet.SignTxWithPassphrase(account, passwd, tx, chainID)
}
@ -392,6 +392,18 @@ func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs
args.Data = &d
}
// Set some sanity defaults and terminate on failure
if err := args.setDefaults(ctx, s.b); err != nil {
return common.Hash{}, err
}
// Assemble the transaction and sign with the wallet
tx := args.toTransaction()
var chainID *big.Int
if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) && !isPrivate {
chainID = config.ChainId
}
signed, err := s.signTransaction(ctx, args, passwd)
if err != nil {
return common.Hash{}, err
@ -900,8 +912,9 @@ type RPCTransaction struct {
// newRPCTransaction returns a transaction that will serialize to the RPC
// representation, with the given location metadata set (if available).
func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64) *RPCTransaction {
var signer types.Signer = types.FrontierSigner{}
if tx.Protected() {
var signer types.Signer = types.HomesteadSigner{}
// joel: this is one of the two places we used a wrong signer to print txes
if tx.Protected() && !tx.IsPrivate() {
signer = types.NewEIP155Signer(tx.ChainId())
}
from, _ := types.Sender(signer, tx)
@ -1077,8 +1090,8 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, ha
}
receipt := receipts[index]
var signer types.Signer = types.FrontierSigner{}
if tx.Protected() {
var signer types.Signer = types.HomesteadSigner{}
if tx.Protected() && !tx.IsPrivate() {
signer = types.NewEIP155Signer(tx.ChainId())
}
from, _ := types.Sender(signer, tx)
@ -1124,10 +1137,9 @@ func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transacti
}
// Request the wallet to sign the transaction
var chainID *big.Int
isQuorum := false
if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) {
chainID = config.ChainID
isQuorum = true
isQuorum := tx.IsPrivate()
if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) && !tx.IsPrivate() {
chainID = config.ChainId
}
return wallet.SignTx(account, tx, chainID, isQuorum)
}
@ -1251,6 +1263,7 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
if isPrivate {
data := []byte(*args.Data)
//Send private transaction to local Constellation node
log.Info("sending private tx", "data", fmt.Sprintf("%x", data), "privatefrom", args.PrivateFrom, "privatefor", args.PrivateFor)
data, err = private.P.Send(data, args.PrivateFrom, args.PrivateFor)
log.Info("sent private tx", "data", fmt.Sprintf("%x", data), "privatefrom", args.PrivateFrom, "privatefor", args.PrivateFor)
@ -1271,10 +1284,9 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
tx := args.toTransaction()
var chainID *big.Int
isQuorum := false
if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) {
chainID = config.ChainID
isQuorum = true
isQuorum := tx.IsPrivate()
if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) && !isPrivate {
chainID = config.ChainId
}
signed, err := wallet.SignTx(account, tx, chainID, isQuorum)
if err != nil {
@ -1367,7 +1379,7 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, err
transactions := make([]*RPCTransaction, 0, len(pending))
for _, tx := range pending {
var signer types.Signer = types.HomesteadSigner{}
if tx.Protected() {
if tx.Protected() && !tx.IsPrivate() {
signer = types.NewEIP155Signer(tx.ChainId())
}
from, _ := types.Sender(signer, tx)
@ -1395,7 +1407,7 @@ func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxAr
for _, p := range pending {
var signer types.Signer = types.HomesteadSigner{}
if p.Protected() {
if p.Protected() && !p.IsPrivate() {
signer = types.NewEIP155Signer(p.ChainId())
}
wantSigHash := signer.Hash(matchTx)

10
internal/web3ext/web3ext.go Normal file → Executable file
View File

@ -433,6 +433,12 @@ web3._extend({
params: 2,
inputFormatter: [web3._extend.formatters.inputBlockNumberFormatter, web3._extend.utils.toHex]
}),
new web3._extend.Method({
name: 'storageRoot',
call: 'eth_storageRoot',
params: 2,
inputFormatter: [web3._extend.formatters.inputAddressFormatter, null]
})
],
properties: [
new web3._extend.Property({
@ -655,6 +661,10 @@ web3._extend({
name: 'removePeer',
call: 'raft_removePeer',
params: 1
}),
new web3._extend.Property({
name: 'leader',
getter: 'raft_leader'
})
]
})

View File

@ -193,7 +193,6 @@ func (self *worker) pending() (*types.Block, *state.StateDB, *state.StateDB) {
self.currentMu.Lock()
defer self.currentMu.Unlock()
return self.current.Block, self.current.state.Copy(), self.current.privateState.Copy()
}
func (self *worker) pendingBlock() *types.Block {
@ -209,7 +208,6 @@ func (self *worker) pendingBlock() *types.Block {
return self.current.Block
}
func (self *worker) start() {
self.mu.Lock()
defer self.mu.Unlock()
@ -327,15 +325,22 @@ func (self *worker) wait() {
// Update the block hash in all logs since it is now available and not when the
// receipt/log of individual transactions were created.
for _, r := range work.receipts {
for _, r := range append(work.receipts, work.privateReceipts...) {
for _, l := range r.Logs {
l.BlockHash = block.Hash()
}
}
for _, log := range work.state.Logs() {
for _, log := range append(work.state.Logs(), work.privateState.Logs()...) {
log.BlockHash = block.Hash()
}
stat, err := self.chain.WriteBlockWithState(block, work.receipts, work.state)
// write private transacions
privateStateRoot, _ := work.privateState.CommitTo(self.chainDb, self.config.IsEIP158(block.Number()))
core.WritePrivateStateRoot(self.chainDb, block.Root(), privateStateRoot)
allReceipts := mergeReceipts(work.receipts, work.privateReceipts)
stat, err := self.chain.WriteBlockAndState(block, allReceipts, work.state)
if err != nil {
log.Error("Failed writing block to chain", "err", err)
continue
@ -344,7 +349,7 @@ func (self *worker) wait() {
self.mux.Post(core.NewMinedBlockEvent{Block: block})
var (
events []interface{}
logs = work.state.Logs()
logs = append(work.state.Logs(), work.privateState.Logs()...)
)
events = append(events, core.ChainEvent{Block: block, Hash: block.Hash(), Logs: logs})
if stat == core.CanonStatTy {
@ -358,6 +363,27 @@ func (self *worker) wait() {
}
}
// Given a slice of public receipts and an overlapping (smaller) slice of
// private receipts, return a new slice where the default for each location is
// the public receipt but we take the private receipt in each place we have
// one.
func mergeReceipts(pub, priv types.Receipts) types.Receipts {
m := make(map[common.Hash]*types.Receipt)
for _, receipt := range pub {
m[receipt.TxHash] = receipt
}
for _, receipt := range priv {
m[receipt.TxHash] = receipt
}
ret := make(types.Receipts, 0, len(pub))
for _, pubReceipt := range pub {
ret = append(ret, m[pubReceipt.TxHash])
}
return ret
}
// push sends a new work task to currently live miner agents.
func (self *worker) push(work *Work) {
if atomic.LoadInt32(&self.mining) != 1 {
@ -571,6 +597,7 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB
}
// Start executing the transaction
env.state.Prepare(tx.Hash(), common.Hash{}, env.tcount)
env.privateState.Prepare(tx.Hash(), common.Hash{}, env.tcount)
err, logs := env.commitTransaction(tx, bc, coinbase, env.gasPool)
switch err {
@ -641,6 +668,5 @@ func (env *Work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, c
logs = append(receipt.Logs, privateReceipt.Logs...)
env.privateReceipts = append(env.privateReceipts, privateReceipt)
}
return nil, logs
}

View File

@ -24,55 +24,54 @@ import (
"github.com/ethereum/go-ethereum/common"
)
// Genesis hashes to enforce below configs on.
var (
MainnetGenesisHash = common.HexToHash("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3")
TestnetGenesisHash = common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d")
MainnetGenesisHash = common.HexToHash("0xd4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3") // Mainnet genesis hash to enforce below configs on
TestnetGenesisHash = common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d") // Testnet genesis hash to enforce below configs on
)
var (
// MainnetChainConfig is the chain parameters to run a node on the main network.
MainnetChainConfig = &ChainConfig{
ChainID: big.NewInt(1),
HomesteadBlock: big.NewInt(1150000),
DAOForkBlock: big.NewInt(1920000),
DAOForkSupport: true,
EIP150Block: big.NewInt(2463000),
EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"),
EIP155Block: big.NewInt(2675000),
EIP158Block: big.NewInt(2675000),
ByzantiumBlock: big.NewInt(4370000),
ConstantinopleBlock: nil,
Ethash: new(EthashConfig),
ChainId: big.NewInt(1),
HomesteadBlock: big.NewInt(1150000),
DAOForkBlock: big.NewInt(1920000),
DAOForkSupport: true,
EIP150Block: big.NewInt(2463000),
EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"),
EIP155Block: big.NewInt(2675000),
EIP158Block: big.NewInt(2675000),
ByzantiumBlock: big.NewInt(4370000),
Ethash: new(EthashConfig),
}
// TestnetChainConfig contains the chain parameters to run a node on the Ropsten test network.
TestnetChainConfig = &ChainConfig{
ChainID: big.NewInt(3),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: true,
EIP150Block: big.NewInt(0),
EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"),
EIP155Block: big.NewInt(10),
EIP158Block: big.NewInt(10),
ByzantiumBlock: big.NewInt(1700000),
ConstantinopleBlock: nil,
Ethash: new(EthashConfig),
ChainId: big.NewInt(3),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: true,
EIP150Block: big.NewInt(0),
EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"),
EIP155Block: big.NewInt(10),
EIP158Block: big.NewInt(10),
ByzantiumBlock: big.NewInt(1700000),
Ethash: new(EthashConfig),
}
// RinkebyChainConfig contains the chain parameters to run a node on the Rinkeby test network.
RinkebyChainConfig = &ChainConfig{
ChainID: big.NewInt(4),
HomesteadBlock: big.NewInt(1),
DAOForkBlock: nil,
DAOForkSupport: true,
EIP150Block: big.NewInt(2),
EIP150Hash: common.HexToHash("0x9b095b36c15eaf13044373aef8ee0bd3a382a5abb92e402afa44b8249c3a90e9"),
EIP155Block: big.NewInt(3),
EIP158Block: big.NewInt(3),
ByzantiumBlock: big.NewInt(1035301),
ConstantinopleBlock: nil,
ChainId: big.NewInt(4),
HomesteadBlock: big.NewInt(1),
DAOForkBlock: nil,
DAOForkSupport: true,
EIP150Block: big.NewInt(2),
EIP150Hash: common.HexToHash("0x9b095b36c15eaf13044373aef8ee0bd3a382a5abb92e402afa44b8249c3a90e9"),
EIP155Block: big.NewInt(3),
EIP158Block: big.NewInt(3),
ByzantiumBlock: big.NewInt(1035301),
Clique: &CliqueConfig{
Period: 15,
Epoch: 30000,
@ -81,16 +80,15 @@ var (
// OttomanChainConfig contains the chain parameters to run a node on the Ottoman test network.
OttomanChainConfig = &ChainConfig{
ChainID: big.NewInt(5),
HomesteadBlock: big.NewInt(1),
DAOForkBlock: nil,
DAOForkSupport: true,
EIP150Block: big.NewInt(2),
EIP150Hash: common.HexToHash("0x9b095b36c15eaf13044373aef8ee0bd3a382a5abb92e402afa44b8249c3a90e9"),
EIP155Block: big.NewInt(3),
EIP158Block: big.NewInt(3),
ByzantiumBlock: big.NewInt(math.MaxInt64), // Don't enable yet
ConstantinopleBlock: nil,
ChainId: big.NewInt(5),
HomesteadBlock: big.NewInt(1),
DAOForkBlock: nil,
DAOForkSupport: true,
EIP150Block: big.NewInt(2),
EIP150Hash: common.HexToHash("0x9b095b36c15eaf13044373aef8ee0bd3a382a5abb92e402afa44b8249c3a90e9"),
EIP155Block: big.NewInt(3),
EIP158Block: big.NewInt(3),
ByzantiumBlock: big.NewInt(math.MaxInt64), // Don't enable yet
Istanbul: &IstanbulConfig{
Epoch: 30000,
@ -103,19 +101,19 @@ var (
//
// This configuration is intentionally not using keyed fields to force anyone
// adding flags to the config to also have to set these fields.
AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), new(EthashConfig), nil, nil, false}
AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), new(EthashConfig), nil, nil, false}
// AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
// and accepted by the Ethereum core developers into the Clique consensus.
//
// This configuration is intentionally not using keyed fields to force anyone
// adding flags to the config to also have to set these fields.
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil, false}
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil, false}
TestChainConfig = &ChainConfig{big.NewInt(10), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), new(EthashConfig), nil, nil, false}
TestChainConfig = &ChainConfig{big.NewInt(10), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), new(EthashConfig), nil, nil, false}
TestRules = TestChainConfig.Rules(new(big.Int))
QuorumTestChainConfig = &ChainConfig{big.NewInt(10), big.NewInt(0), nil, false, nil, common.Hash{}, nil, nil, nil, nil, new(EthashConfig), nil, nil, true}
QuorumTestChainConfig = &ChainConfig{big.NewInt(10), big.NewInt(0), nil, false, nil, common.Hash{}, nil, nil, nil, new(EthashConfig), nil, nil, true}
)
// ChainConfig is the core config which determines the blockchain settings.
@ -124,7 +122,7 @@ var (
// that any network, identified by its genesis block, can have its own
// set of configuration options.
type ChainConfig struct {
ChainID *big.Int `json:"chainId"` // chainId identifies the current chain and is used for replay protection
ChainId *big.Int `json:"chainId"` // Chain id identifies the current chain and is used for replay protection
HomesteadBlock *big.Int `json:"homesteadBlock,omitempty"` // Homestead switch block (nil = no fork, 0 = already homestead)
@ -138,8 +136,7 @@ type ChainConfig struct {
EIP155Block *big.Int `json:"eip155Block,omitempty"` // EIP155 HF block
EIP158Block *big.Int `json:"eip158Block,omitempty"` // EIP158 HF block
ByzantiumBlock *big.Int `json:"byzantiumBlock,omitempty"` // Byzantium switch block (nil = no fork, 0 = already on byzantium)
ConstantinopleBlock *big.Int `json:"constantinopleBlock,omitempty"` // Constantinople switch block (nil = no fork, 0 = already activated)
ByzantiumBlock *big.Int `json:"byzantiumBlock,omitempty"` // Byzantium switch block (nil = no fork, 0 = already on byzantium)
// Various consensus engines
Ethash *EthashConfig `json:"ethash,omitempty"`
@ -192,8 +189,8 @@ func (c *ChainConfig) String() string {
default:
engine = "unknown"
}
return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v IsQuorum: %v Constantinople: %v Engine: %v}",
c.ChainID,
return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v IsQuorum: %v Engine: %v}",
c.ChainId,
c.HomesteadBlock,
c.DAOForkBlock,
c.DAOForkSupport,
@ -202,7 +199,6 @@ func (c *ChainConfig) String() string {
c.EIP158Block,
c.ByzantiumBlock,
c.IsQuorum,
c.ConstantinopleBlock,
engine,
)
}
@ -237,11 +233,6 @@ func (c *ChainConfig) IsByzantium(num *big.Int) bool {
return isForked(c.ByzantiumBlock, num)
}
// IsConstantinople returns whether num is either equal to the Constantinople fork block or greater.
func (c *ChainConfig) IsConstantinople(num *big.Int) bool {
return isForked(c.ConstantinopleBlock, num)
}
// GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice).
//
// The returned GasTable's fields shouldn't, under any circumstances, be changed.
@ -296,15 +287,12 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *Confi
if isForkIncompatible(c.EIP158Block, newcfg.EIP158Block, head) {
return newCompatError("EIP158 fork block", c.EIP158Block, newcfg.EIP158Block)
}
if c.IsEIP158(head) && !configNumEqual(c.ChainID, newcfg.ChainID) {
if c.IsEIP158(head) && !configNumEqual(c.ChainId, newcfg.ChainId) {
return newCompatError("EIP158 chain ID", c.EIP158Block, newcfg.EIP158Block)
}
if isForkIncompatible(c.ByzantiumBlock, newcfg.ByzantiumBlock, head) {
return newCompatError("Byzantium fork block", c.ByzantiumBlock, newcfg.ByzantiumBlock)
}
if isForkIncompatible(c.ConstantinopleBlock, newcfg.ConstantinopleBlock, head) {
return newCompatError("Constantinople fork block", c.ConstantinopleBlock, newcfg.ConstantinopleBlock)
}
return nil
}
@ -369,16 +357,16 @@ func (err *ConfigCompatError) Error() string {
// Rules is a one time interface meaning that it shouldn't be used in between transition
// phases.
type Rules struct {
ChainID *big.Int
ChainId *big.Int
IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool
IsByzantium bool
}
// Rules ensures c's ChainID is not nil.
func (c *ChainConfig) Rules(num *big.Int) Rules {
chainID := c.ChainID
if chainID == nil {
chainID = new(big.Int)
chainId := c.ChainId
if chainId == nil {
chainId = new(big.Int)
}
return Rules{ChainID: new(big.Int).Set(chainID), IsHomestead: c.IsHomestead(num), IsEIP150: c.IsEIP150(num), IsEIP155: c.IsEIP155(num), IsEIP158: c.IsEIP158(num), IsByzantium: c.IsByzantium(num)}
return Rules{ChainId: new(big.Int).Set(chainId), IsHomestead: c.IsHomestead(num), IsEIP150: c.IsEIP150(num), IsEIP155: c.IsEIP155(num), IsEIP158: c.IsEIP158(num), IsByzantium: c.IsByzantium(num)}
}

View File

@ -1,19 +1,30 @@
package constellation
import (
"errors"
"fmt"
"github.com/patrickmn/go-cache"
"os"
"path/filepath"
"strings"
"time"
"github.com/patrickmn/go-cache"
)
type Constellation struct {
node *Client
c *cache.Cache
node *Client
c *cache.Cache
isConstellationNotInUse bool
}
var (
ErrConstellationIsntInit = errors.New("Constellation not in use")
)
func (g *Constellation) Send(data []byte, from string, to []string) (out []byte, err error) {
if g.isConstellationNotInUse {
return nil, ErrConstellationIsntInit
}
out, err = g.node.SendPayload(data, from, to)
if err != nil {
return nil, err
@ -23,6 +34,9 @@ func (g *Constellation) Send(data []byte, from string, to []string) (out []byte,
}
func (g *Constellation) Receive(data []byte) ([]byte, error) {
if g.isConstellationNotInUse {
return nil, nil
}
if len(data) == 0 {
return data, nil
}
@ -47,7 +61,7 @@ func New(path string) (*Constellation, error) {
}
// We accept either the socket or a configuration file that points to
// a socket.
isSocket := info.Mode() & os.ModeSocket != 0
isSocket := info.Mode()&os.ModeSocket != 0
if !isSocket {
cfg, err := LoadConfig(path)
if err != nil {
@ -66,10 +80,18 @@ func New(path string) (*Constellation, error) {
return &Constellation{
node: n,
c: cache.New(5*time.Minute, 5*time.Minute),
isConstellationNotInUse: false,
}, nil
}
func MustNew(path string) *Constellation {
if strings.EqualFold(path, "ignore") {
return &Constellation{
node: nil,
c: nil,
isConstellationNotInUse: true,
}
}
g, err := New(path)
if err != nil {
panic(fmt.Sprintf("MustNew: Failed to connect to Constellation (%s): %v", path, err))

8
raft/api.go Normal file → Executable file
View File

@ -29,3 +29,11 @@ func (s *PublicRaftAPI) AddPeer(enodeId string) (uint16, error) {
func (s *PublicRaftAPI) RemovePeer(raftId uint16) {
s.raftService.raftProtocolManager.ProposePeerRemoval(raftId)
}
func (s *PublicRaftAPI) Leader() (string, error) {
addr, err := s.raftService.raftProtocolManager.LeaderAddress()
if nil != err {
return "", err
}
return addr.nodeId.String(), nil
}

View File

@ -75,7 +75,7 @@ Consider the following example where this might occur, where Raft entries attemp
`[ 0xbeda Parent: 0xacaa ]`
Where `0xbeda` is the ID of new block, and `0xaa` is the ID of its parent. Here, the initial minter (node 1) is partitioned, and node 2 takes over as the minter.
Where `0xbeda` is the ID of new block, and `0xacaa` is the ID of its parent. Here, the initial minter (node 1) is partitioned, and node 2 takes over as the minter.
```
time block submissions
@ -89,7 +89,7 @@ Where `0xbeda` is the ID of new block, and `0xaa` is the ID of its parent. Here,
|
| -- 1 rejoins --
|
v [ 0x8b37 Parent: 0x8b37 ]
v [ 0x8b37 Parent: 0x839c ]
```
Once the partition heals, at the Raft layer node1 will resubmit `0x2c52`, and the resulting serialized log might look as follows:
@ -99,7 +99,7 @@ Once the partition heals, at the Raft layer node1 will resubmit `0x2c52`, and th
[ 0xf0ec Parent: 0xbeda - Extends! ] (due to node 2; let's call this the "winner")
[ 0x839c Parent: 0xf0ec - Extends! ] (due to node 2)
[ 0x2c52 Parent: 0xbeda - NO-OP. ] (due to node 1; let's call this the "loser")
[ 0x8b37 Parent: 0x8b37 - Extends! ] (due to node 2)
[ 0x8b37 Parent: 0x839c - Extends! ] (due to node 2)
```
Due to being serialized after the "winner," the "loser" entry will not extend the chain, because its parent (`0xbeda`) is no longer at the head of the chain when we apply the entry. The "winner" extended the same parent (`0xbeda`) earlier (and then `0x839c` extended it further.)

28
raft/handler.go Normal file → Executable file
View File

@ -1,6 +1,7 @@
package raft
import (
"errors"
"fmt"
"net/http"
"net/url"
@ -50,6 +51,7 @@ type ProtocolManager struct {
snapshotIndex uint64 // The index of the latest snapshot.
// Remote peer state (protected by mu vs concurrent access via JS)
leader uint16
peers map[uint16]*Peer
removedPeers *set.Set // *Permanently removed* peers
@ -101,6 +103,7 @@ func NewProtocolManager(raftId uint16, raftPort uint16, blockchain *core.BlockCh
manager := &ProtocolManager{
bootstrapNodes: bootstrapNodes,
peers: make(map[uint16]*Peer),
leader: uint16(etcdRaft.None),
removedPeers: set.New(),
joinExisting: joinExisting,
blockchain: blockchain,
@ -680,6 +683,10 @@ func (pm *ProtocolManager) eventLoop() {
case rd := <-pm.rawNode().Ready():
pm.wal.Save(rd.HardState, rd.Entries)
if rd.SoftState != nil {
pm.updateLeader(rd.SoftState.Lead)
}
if snap := rd.Snapshot; !etcdRaft.IsEmptySnap(snap) {
pm.saveRaftSnapshot(snap)
pm.applyRaftSnapshot(snap)
@ -881,3 +888,24 @@ func (pm *ProtocolManager) advanceAppliedIndex(index uint64) {
pm.appliedIndex = index
pm.mu.Unlock()
}
func (pm *ProtocolManager) updateLeader(leader uint64) {
pm.mu.Lock()
defer pm.mu.Unlock()
pm.leader = uint16(leader)
}
// The Address for the current leader, or an error if no leader is elected.
func (pm *ProtocolManager) LeaderAddress() (*Address, error) {
pm.mu.RLock()
defer pm.mu.RUnlock()
if minterRole == pm.role {
return pm.address, nil
} else if l, ok := pm.peers[pm.leader]; ok {
return l.address, nil
}
// We expect to reach this if pm.leader is 0, which is how etcd denotes the lack of a leader.
return nil, errors.New("no leader is currently elected")
}

View File

@ -55,7 +55,7 @@ func (chain *speculativeChain) setHead(block *types.Block) {
chain.head = block
}
// Accept this block, removing it from the head of the speculative chain
// Accept this block, removing it from the speculative chain
func (chain *speculativeChain) accept(acceptedBlock *types.Block) {
earliestProposedI := chain.unappliedBlocks.Shift()
var earliestProposed *types.Block
@ -63,7 +63,16 @@ func (chain *speculativeChain) accept(acceptedBlock *types.Block) {
earliestProposed = earliestProposedI.(*types.Block)
}
if expectedBlock := earliestProposed == nil || earliestProposed.Hash() == acceptedBlock.Hash(); expectedBlock {
// There are three possible scenarios:
// 1. We don't have a record of this block (or any proposed blocks), meaning someone else minted it and we should
// add it as the new head of our speculative chain. New blocks from the old leader are still coming in.
// 2. This block was the first outstanding one we proposed.
// 3. This block is different from the block we proposed, (also) meaning new blocks are still coming in from the old
// leader, but unlike the first scenario, we need to clear all of the speculative chain state because the
// `acceptedBlock` takes precedence over our speculative state.
if earliestProposed == nil {
chain.head = acceptedBlock
} else if expectedBlock := earliestProposed.Hash() == acceptedBlock.Hash(); expectedBlock {
// Remove the txes in this accepted block from our blacklist.
chain.removeProposedTxes(acceptedBlock)
} else {