From 5e8494707ba9d4c9872b1396111b0dabcabbe89a Mon Sep 17 00:00:00 2001 From: Federico Gimenez Date: Sat, 24 Mar 2018 18:54:33 +0100 Subject: [PATCH 01/16] Fix block ids in raft doc --- raft/doc.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/raft/doc.md b/raft/doc.md index 7e291fff0..ae7c85257 100644 --- a/raft/doc.md +++ b/raft/doc.md @@ -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.) From 1b7a3d971042d9b0ff5796effd8de7f22c5b5580 Mon Sep 17 00:00:00 2001 From: tsuzukit Date: Thu, 31 May 2018 21:39:51 +0900 Subject: [PATCH 02/16] Fix TestChainTxReorgs --- core/blockchain_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 33cbd1e35..899acf461 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -753,7 +753,7 @@ func TestChainTxReorgs(t *testing.T) { db, _ = ethdb.NewMemDatabase() gspec = &Genesis{ Config: params.TestChainConfig, - GasLimit: 3141592, + GasLimit: 700000000, Alloc: GenesisAlloc{ addr1: {Balance: big.NewInt(1000000)}, addr2: {Balance: big.NewInt(1000000)}, From 52f137c850d5099c542fe2dfcfd0b016ff2a9391 Mon Sep 17 00:00:00 2001 From: Tomoaki Tsuzuki Date: Tue, 5 Jun 2018 05:02:09 +0900 Subject: [PATCH 03/16] Feature/fix_some_tests (#387) * same fix as ethereum/go-ethereum#15783 * Fix insufficient balance for transfer * change chainId of QuorumTestChainConfig --- cmd/geth/misccmd.go | 3 +-- core/blockchain_test.go | 4 ++-- params/config.go | 4 ++-- whisper/whisperv2/whisper.go | 4 ++-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/cmd/geth/misccmd.go b/cmd/geth/misccmd.go index 63c02438f..a98c9f079 100644 --- a/cmd/geth/misccmd.go +++ b/cmd/geth/misccmd.go @@ -134,7 +134,6 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with geth. If not, see . -`) +along with geth. If not, see .`) return nil } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 33cbd1e35..902070959 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -1037,7 +1037,7 @@ func TestEIP155Transition(t *testing.T) { funds = big.NewInt(1000000000) deleteAddr = common.Address{1} gspec = &Genesis{ - Config: ¶ms.ChainConfig{ChainId: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}, + Config: ¶ms.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) @@ -1142,7 +1142,7 @@ func TestEIP161AccountRemoval(t *testing.T) { theAddr = common.Address{1} gspec = &Genesis{ Config: ¶ms.ChainConfig{ - ChainId: big.NewInt(1), + ChainId: big.NewInt(10), HomesteadBlock: new(big.Int), EIP155Block: new(big.Int), EIP158Block: big.NewInt(2), diff --git a/params/config.go b/params/config.go index 4983870d9..9af86d89f 100644 --- a/params/config.go +++ b/params/config.go @@ -110,10 +110,10 @@ var ( // 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), nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil, false} - TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, 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(1), big.NewInt(0), nil, false, nil, common.Hash{}, 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. diff --git a/whisper/whisperv2/whisper.go b/whisper/whisperv2/whisper.go index 61c36918d..e111a3414 100644 --- a/whisper/whisperv2/whisper.go +++ b/whisper/whisperv2/whisper.go @@ -262,7 +262,7 @@ func (self *Whisper) add(envelope *Envelope) error { // Insert the message into the tracked pool hash := envelope.Hash() if _, ok := self.messages[hash]; ok { - log.Trace(fmt.Sprintf("whisper envelope already cached: %x\n", envelope)) + log.Trace(fmt.Sprintf("whisper envelope already cached: %x\n", hash)) return nil } self.messages[hash] = envelope @@ -277,7 +277,7 @@ func (self *Whisper) add(envelope *Envelope) error { // Notify the local node of a message arrival go self.postEvent(envelope) } - log.Trace(fmt.Sprintf("cached whisper envelope %x\n", envelope)) + log.Trace(fmt.Sprintf("cached whisper envelope %x\n", hash)) return nil } From 7608c1c9b8a4ec35f96b1e2af3c03885fee7f7d5 Mon Sep 17 00:00:00 2001 From: jpmsam Date: Thu, 7 Jun 2018 15:45:24 -0400 Subject: [PATCH 04/16] validate input before calling evm --- core/state_transition.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/state_transition.go b/core/state_transition.go index 19caf3c5f..08b7b13f2 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -279,6 +279,10 @@ func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big } else { to = st.to().Address() } + //if input is empty for the smart contract call, return + if len(data) == 0 { + 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 { From 31598781f426659497f4a3ffcc069d54c3668cb1 Mon Sep 17 00:00:00 2001 From: fixanoid Date: Wed, 13 Jun 2018 14:53:54 -0400 Subject: [PATCH 05/16] quorum-maker master link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5518dc1a7..0f5ce6b35 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,7 @@ The following Quorum-related libraries/applications have been created by Third P * [Quorum Blockchain Explorer](https://github.com/blk-io/blk-explorer-free) - a Blockchain Explorer for Quorum which supports viewing private transactions * [Quorum-Genesis](https://github.com/davebryson/quorum-genesis) - A simple CL utility for Quorum to help populate the genesis file with voters and makers -* [Quorum Maker](https://github.com/synechron-finlabs/quorum-maker/tree/development) - a utility to create Quorum nodes +* [Quorum Maker](https://github.com/synechron-finlabs/quorum-maker/) - a utility to create Quorum nodes * [QuorumNetworkManager](https://github.com/ConsenSys/QuorumNetworkManager) - makes creating & managing Quorum networks easy * [ERC20 REST service](https://github.com/blk-io/erc20-rest-service) - a Quorum-supported RESTful service for creating and managing ERC-20 tokens * [Nethereum Quorum](https://github.com/Nethereum/Nethereum/tree/master/src/Nethereum.Quorum) - a .NET Quorum adapter From f3d1315269df2e4ff749d987cc119eb82d5bacb0 Mon Sep 17 00:00:00 2001 From: Samer Falah Date: Wed, 13 Jun 2018 16:48:16 -0400 Subject: [PATCH 06/16] Fixes eth.hashrate panic #393 (#409) --- consensus/ethash/ethash.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go index b5cb7227a..57905237f 100644 --- a/consensus/ethash/ethash.go +++ b/consensus/ethash/ethash.go @@ -583,6 +583,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() } From 87d7c906e9eba93b618651ab5a427746506e2f30 Mon Sep 17 00:00:00 2001 From: Qvintvs Date: Sat, 30 Jun 2018 04:17:32 +0800 Subject: [PATCH 07/16] Use eip155 signer for public transactions (#375) Use eip155 for public transaction --- accounts/keystore/keystore.go | 2 +- core/types/transaction.go | 4 +--- internal/ethapi/api.go | 25 ++++++++++++------------- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/accounts/keystore/keystore.go b/accounts/keystore/keystore.go index 10c0db70f..fa04214c2 100644 --- a/accounts/keystore/keystore.go +++ b/accounts/keystore/keystore.go @@ -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) diff --git a/core/types/transaction.go b/core/types/transaction.go index 80335f1da..31f88ff14 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -133,9 +133,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 diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index e2106bd27..2e3e154c7 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -27,6 +27,9 @@ import ( "bytes" "encoding/hex" "encoding/json" + "net/http" + "sync" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/common" @@ -45,8 +48,6 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/util" - "net/http" - "sync" ) const ( @@ -378,7 +379,7 @@ func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs tx := args.toTransaction() var chainID *big.Int - if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) { + if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) && !isPrivate { chainID = config.ChainId } signed, err := wallet.SignTxWithPassphrase(account, passwd, tx, chainID) @@ -835,7 +836,7 @@ type RPCTransaction struct { func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber uint64, index uint64) *RPCTransaction { 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() { + if tx.Protected() && !tx.IsPrivate() { signer = types.NewEIP155Signer(tx.ChainId()) } from, _ := types.Sender(signer, tx) @@ -1005,7 +1006,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(hash common.Hash) (map[ receipt, _, _, _ := core.GetReceipt(s.b.ChainDb(), hash) // Old receipts don't have the lookup data available var signer types.Signer = types.HomesteadSigner{} - if tx.Protected() { + if tx.Protected() && !tx.IsPrivate() { signer = types.NewEIP155Signer(tx.ChainId()) } from, _ := types.Sender(signer, tx) @@ -1051,10 +1052,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()) { + isQuorum := tx.IsPrivate() + if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) && !tx.IsPrivate() { chainID = config.ChainId - isQuorum = true } return wallet.SignTx(account, tx, chainID, isQuorum) } @@ -1169,10 +1169,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()) { + isQuorum := tx.IsPrivate() + if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) && !isPrivate { chainID = config.ChainId - isQuorum = true } signed, err := wallet.SignTx(account, tx, chainID, isQuorum) if err != nil { @@ -1257,7 +1256,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) @@ -1285,7 +1284,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) From 01195280b4d8d9c91df7c500c74898f01c38209e Mon Sep 17 00:00:00 2001 From: Samer Falah Date: Thu, 5 Jul 2018 13:59:33 -0400 Subject: [PATCH 08/16] Fixes value transfer (#430) --- core/state_transition.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/state_transition.go b/core/state_transition.go index 08b7b13f2..0580195cb 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -279,8 +279,8 @@ func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big } else { to = st.to().Address() } - //if input is empty for the smart contract call, return - if len(data) == 0 { + //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) From d71daf324590d0033d0fc0ad255cadb702cf2b3b Mon Sep 17 00:00:00 2001 From: Nguyen Kien Trung Date: Thu, 12 Jul 2018 12:44:32 +0800 Subject: [PATCH 09/16] expose leader enode id to console (#426) * exposed leader enode id to console --- internal/web3ext/web3ext.go | 4 ++++ raft/api.go | 8 ++++++++ raft/handler.go | 28 ++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+) mode change 100644 => 100755 internal/web3ext/web3ext.go mode change 100644 => 100755 raft/api.go mode change 100644 => 100755 raft/handler.go diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go old mode 100644 new mode 100755 index 6d78d7f85..7102419fa --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -618,6 +618,10 @@ web3._extend({ name: 'removePeer', call: 'raft_removePeer', params: 1 + }), + new web3._extend.Property({ + name: 'leader', + getter: 'raft_leader' }) ] }) diff --git a/raft/api.go b/raft/api.go old mode 100644 new mode 100755 index fe8e5701b..4fec8e17d --- a/raft/api.go +++ b/raft/api.go @@ -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 +} diff --git a/raft/handler.go b/raft/handler.go old mode 100644 new mode 100755 index 7778d2604..91d4e823a --- a/raft/handler.go +++ b/raft/handler.go @@ -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") +} From e8f0ee91620fbd14385d56658da249c22a9704a2 Mon Sep 17 00:00:00 2001 From: Satpal Date: Mon, 23 Jul 2018 15:34:36 +0100 Subject: [PATCH 10/16] Prevent private transaction with ether value from becoming stuck in pending (#451) --- core/tx_pool.go | 14 +++++++-- core/tx_pool_test.go | 66 +++++++++++++++++++++++++++++++++++------- core/vm/evm.go | 2 +- internal/ethapi/api.go | 1 + 4 files changed, 70 insertions(+), 13 deletions(-) diff --git a/core/tx_pool.go b/core/tx_pool.go index c4d79c43c..14bec574b 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -80,6 +80,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 ( @@ -206,7 +210,7 @@ type TxPool struct { } // NewTxPool creates a new transaction pool to gather, sort and filter inbound -// trnsactions from the network. +// transactions from the network. func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain blockChain) *TxPool { // Sanitize the input to ensure no vulnerable gas prices are set config = (&config).sanitize() @@ -273,6 +277,7 @@ func (pool *TxPool) loop() { // Keep waiting for and reacting to the various events for { select { + // Handle ChainHeadEvent case ev := <-pool.chainHeadCh: if ev.Block != nil { @@ -285,6 +290,7 @@ func (pool *TxPool) loop() { pool.mu.Unlock() } + // Be unsubscribed due to system stopped case <-pool.chainHeadSub.Err(): return @@ -578,6 +584,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 { @@ -796,7 +806,7 @@ 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 + // Add the batch of transactions, tracking the accepted ones dirty := make(map[common.Address]struct{}) for _, tx := range txs { if replace, err := pool.add(tx, local); err == nil { diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index bf2a18288..fa8e36799 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -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() @@ -200,38 +210,74 @@ func TestStateChangeDuringPoolReset(t *testing.T) { } } +//Test for transactions that are invalid on Ethereum func TestInvalidTransactions(t *testing.T) { pool, key := setupTxPool() defer pool.Stop() tx := transaction(0, big.NewInt(100), key) + from, _ := deriveSender(tx) 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(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, big.NewInt(100000), key) if err := pool.AddRemote(tx); err != ErrNonceTooLow { - t.Error("expected", ErrNonceTooLow) + t.Error("expected", ErrNonceTooLow, "; got", err) } tx = transaction(1, big.NewInt(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) { diff --git a/core/vm/evm.go b/core/vm/evm.go index 20247d2c1..0269c4165 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -403,7 +403,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I } // initialise a new contract and set the code that is to be used by the - // E The contract is a scoped evmironment for this execution context + // E The contract is a scoped environment for this execution context // only. contract := NewContract(caller, AccountRef(contractAddr), value, gas) contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 2e3e154c7..65a644e22 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1152,6 +1152,7 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen isPrivate := args.PrivateFor != nil if isPrivate { + //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) From ad7c031e85a8405c80fa842a3745fa6cd2d5fd35 Mon Sep 17 00:00:00 2001 From: Sai V Date: Fri, 27 Jul 2018 20:37:29 +0800 Subject: [PATCH 11/16] eth - Storage root retrieval for accounts (#436) re-enabling eth_storagRoot call --- core/state/state_object.go | 4 ++++ core/state/statedb.go | 9 +++++++++ core/state/statedb_test.go | 31 +++++++++++++++++++++++++++++++ eth/api.go | 27 +++++++++++++++++++++++++++ internal/web3ext/web3ext.go | 6 ++++++ 5 files changed, 77 insertions(+) diff --git a/core/state/state_object.go b/core/state/state_object.go index b2378c69c..c787e11eb 100644 --- a/core/state/state_object.go +++ b/core/state/state_object.go @@ -169,6 +169,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] diff --git a/core/state/statedb.go b/core/state/statedb.go index 002fa6249..64f6ad5b8 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -255,6 +255,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 */ diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index b2bd18e65..f9a5df629 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -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) + } +} + func TestSnapshotRandom(t *testing.T) { config := &quick.Config{MaxCount: 1000} err := quick.Check((*snapshotTest).run, config) diff --git a/eth/api.go b/eth/api.go index de9305180..b75f85023 100644 --- a/eth/api.go +++ b/eth/api.go @@ -66,6 +66,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()) diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 7102419fa..b85e0ecbb 100755 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -402,6 +402,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({ From 5765a6a331472667c44110e4c36551ae673d8ee0 Mon Sep 17 00:00:00 2001 From: Joel Burget Date: Mon, 30 Jul 2018 06:58:00 -0700 Subject: [PATCH 12/16] Make sure to update speculative chain head in `accept.` Fixes #428 The scenario is covered in https://github.com/jpmorganchase/quorum/issues/428, but in short, if we're mining but two new blocks come in over the network: (1) The first will clear the speculative chain. (2) The second previously would have been a noop here -- `removeProposedTxes` does nothing in this case, but we need to update the speculative chain head to the new block. The important invariant identified by @guojian1234 that this now maintains is `minter.speculativeChain.head.blockNumber >= minter.chain.head.blockNumber`. --- raft/speculative_chain.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/raft/speculative_chain.go b/raft/speculative_chain.go index 6818d5b8e..1db68cee9 100644 --- a/raft/speculative_chain.go +++ b/raft/speculative_chain.go @@ -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 { From 228a7d93d697708cf76040131d08ecb29aaf71b8 Mon Sep 17 00:00:00 2001 From: Peter Fox <31221824+prd-fox@users.noreply.github.com> Date: Wed, 1 Aug 2018 15:06:47 +0100 Subject: [PATCH 13/16] Istanbul events not firing & logs not showing on some nodes (#460) * keep merging of public and private receipts inline with other processing flows * added private state prepare in commitTransaction for missed private events --- miner/worker.go | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index f433dfde5..4a86f4a38 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -314,19 +314,19 @@ 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() } // write private transacions privateStateRoot, _ := work.privateState.CommitTo(self.chainDb, self.config.IsEIP158(block.Number())) core.WritePrivateStateRoot(self.chainDb, block.Root(), privateStateRoot) - allReceipts := append(work.receipts, work.privateReceipts...) + allReceipts := mergeReceipts(work.receipts, work.privateReceipts) stat, err := self.chain.WriteBlockAndState(block, allReceipts, work.state) if err != nil { @@ -342,7 +342,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 { @@ -360,6 +360,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 { @@ -553,6 +574,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, gp) switch err { From 58f291f8ffd42869eb12800a59cf55ed99a6f525 Mon Sep 17 00:00:00 2001 From: Samer Falah Date: Wed, 1 Aug 2018 11:13:29 -0400 Subject: [PATCH 14/16] Reject transactions with not enough gas from being sent (#443) Fixes #309 --- core/tx_pool.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/tx_pool.go b/core/tx_pool.go index 14bec574b..2ebc03532 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -594,7 +594,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { return ErrInsufficientFunds } intrGas := IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead) - if !isQuorum && tx.Gas().Cmp(intrGas) < 0 { + if tx.Gas().Cmp(intrGas) < 0 { return ErrIntrinsicGas } return nil From f593667dde0b5c3a4ea210087807cd6e600360eb Mon Sep 17 00:00:00 2001 From: apratt3377 Date: Fri, 3 Aug 2018 09:51:50 -0400 Subject: [PATCH 15/16] Allow for optional disablement of privacy config (#462) Added through a PRIVACY_CONFIG-ignore keyword, as described in #300 --- private/constellation/constellation.go | 30 ++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/private/constellation/constellation.go b/private/constellation/constellation.go index 570a92de7..69afcde68 100644 --- a/private/constellation/constellation.go +++ b/private/constellation/constellation.go @@ -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)) From 43424382f29ec3472941fa9de014a41344e5ec55 Mon Sep 17 00:00:00 2001 From: fixanoid Date: Fri, 3 Aug 2018 12:03:46 -0400 Subject: [PATCH 16/16] Updating slack refs --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0f5ce6b35..6509b245a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Quorum -Quorum Slack +Quorum Slack Quorum is an Ethereum-based distributed ledger protocol with transaction/contract privacy and new consensus mechanisms. @@ -128,6 +128,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