From e8e44cd60e2d2400dcf892f083cb45f38bceeb05 Mon Sep 17 00:00:00 2001 From: Nathan Aw Date: Sun, 12 Aug 2018 20:38:07 +0800 Subject: [PATCH 01/32] Update tx_pool.go UPDATED to 64KB to support the deployment of bigger contract due to the pressing need for sophisticated/complex contract in financial/capital markets - Nathan Aw --- core/tx_pool.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/tx_pool.go b/core/tx_pool.go index 55c7405af..1531fd13b 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -558,7 +558,8 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { return ErrInvalidGasPrice } // Heuristic limit, reject transactions over 32KB to prevent DOS attacks - if tx.Size() > 32*1024 { + // UPDATED to 64KB to support the deployment of bigger contract due to the pressing need for sophisticated/complex contract in financial/capital markets - Nathan Aw + if tx.Size() > 64*1024 { return ErrOversizedData } // Transactions can't be negative. This may never happen using RLP decoded From 2f1495855906925da688f1244f3cfbec8ba692b9 Mon Sep 17 00:00:00 2001 From: Vinod Damle Date: Wed, 17 Oct 2018 11:47:51 -0400 Subject: [PATCH 02/32] p2p: remove spurious log for denied node permissioning connection is only denied after cycling through entire list, remove confusing and erroneous log in the loop --- p2p/permissions.go | 1 - 1 file changed, 1 deletion(-) diff --git a/p2p/permissions.go b/p2p/permissions.go index 3cbacb2bc..824bb110a 100644 --- a/p2p/permissions.go +++ b/p2p/permissions.go @@ -30,7 +30,6 @@ func isNodePermissioned(nodename string, currentNode string, datadir string, dir log.Debug("isNodePermissioned", "connection", direction, "nodename", nodename[:NODE_NAME_LENGTH], "ALLOWED-BY", currentNode[:NODE_NAME_LENGTH]) return true } - log.Debug("isNodePermissioned", "connection", direction, "nodename", nodename[:NODE_NAME_LENGTH], "DENIED-BY", currentNode[:NODE_NAME_LENGTH]) } log.Debug("isNodePermissioned", "connection", direction, "nodename", nodename[:NODE_NAME_LENGTH], "DENIED-BY", currentNode[:NODE_NAME_LENGTH]) return false From a3ec05d471aad50dc63214b14af2c2b380fc3f02 Mon Sep 17 00:00:00 2001 From: Jitendra Bhurat Date: Fri, 19 Oct 2018 09:56:48 -0400 Subject: [PATCH 03/32] Writing private block bloom for miner --- miner/worker.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/miner/worker.go b/miner/worker.go index c83e4af53..5bfed4152 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -333,6 +333,12 @@ func (self *worker) wait() { log.Error("Failed writing block to chain", "err", err) continue } + + if err := core.WritePrivateBlockBloom(self.chainDb, block.NumberU64(), work.privateReceipts); err != nil { + log.Error("Failed writing private block bloom", "err", err) + continue + } + // check if canon block and write transactions if stat == core.CanonStatTy { // implicit by posting ChainHeadEvent From ea0c1ffd45489e9fb6d64cbeaf56eb0335e6bb1b Mon Sep 17 00:00:00 2001 From: Jitendra Bhurat Date: Wed, 24 Oct 2018 14:44:11 -0400 Subject: [PATCH 04/32] Adding private log blooms to DB in addition to public log bloom --- core/types/bloom9.go | 8 ++++++++ eth/bloombits.go | 10 +++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/core/types/bloom9.go b/core/types/bloom9.go index a76b6f33c..0a028ae1d 100644 --- a/core/types/bloom9.go +++ b/core/types/bloom9.go @@ -63,6 +63,14 @@ func (b *Bloom) Add(d *big.Int) { b.SetBytes(bin.Bytes()) } +// OrBloom executes an Or operation on the bloom +func (b *Bloom) OrBloom(bl []byte) { + bin := new(big.Int).SetBytes(b[:]) + input := new(big.Int).SetBytes(bl[:]) + bin.Or(bin, input) + b.SetBytes(bin.Bytes()) +} + // Big converts b to a big integer. func (b Bloom) Big() *big.Int { return new(big.Int).SetBytes(b[:]) diff --git a/eth/bloombits.go b/eth/bloombits.go index 32f6c7b31..517c858c9 100644 --- a/eth/bloombits.go +++ b/eth/bloombits.go @@ -119,10 +119,14 @@ func (b *BloomIndexer) Reset(section uint64) { b.gen, b.section, b.head = gen, section, common.Hash{} } -// Process implements core.ChainIndexerBackend, adding a new header's bloom into -// the index. +// Process implements core.ChainIndexerBackend, executes an Or operation on header.bloom and private bloom +// (header.bloom | private bloom) and adds to index func (b *BloomIndexer) Process(header *types.Header) { - b.gen.AddBloom(uint(header.Number.Uint64()-b.section*b.size), header.Bloom) + publicBloom := header.Bloom + privateBloom := core.GetPrivateBlockBloom(b.db, header.Number.Uint64()) + publicBloom.OrBloom(privateBloom.Bytes()) + + b.gen.AddBloom(uint(header.Number.Uint64()-b.section*b.size), publicBloom) b.head = header.Hash() } From 4658a1542eaed1f5c719fbf36da5ba8d3e3e7591 Mon Sep 17 00:00:00 2001 From: Puneetha Date: Wed, 7 Nov 2018 17:22:45 +0000 Subject: [PATCH 05/32] Do not reset V value if the tx is already set to private --- core/types/transaction.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/types/transaction.go b/core/types/transaction.go index 31f88ff14..2a9f8f64d 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -486,6 +486,9 @@ func (tx *Transaction) IsPrivate() bool { } func (tx *Transaction) SetPrivate() { + if tx.IsPrivate() { + return + } if tx.data.V.Int64() == 28 { tx.data.V.SetUint64(38) } else { From 99dcc0fd3f5fb8dfa69e6ad6989339533434f4f7 Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Fri, 23 Nov 2018 11:20:31 -0500 Subject: [PATCH 06/32] fix unit test for PR 510 --- core/tx_pool_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index 73fe320bd..58eec4850 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -253,7 +253,7 @@ func TestInvalidTransactions(t *testing.T) { t.Error("expected", ErrGasLimit, "; got", err) } - data := make([]byte, (32*1024)+1) + data := make([]byte, (64*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) From 7c03ee72084805abbe1419ca97bb1d50d81f1d61 Mon Sep 17 00:00:00 2001 From: "amalraj.manigmail.com" Date: Tue, 27 Nov 2018 10:45:11 +0800 Subject: [PATCH 07/32] Merge remote-tracking branch 'quorum/master' into geth-upgrade-1.8.12 # Conflicts: # core/tx_pool_test.go # miner/worker.go --- miner/worker.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/miner/worker.go b/miner/worker.go index 60ba40313..4ddc3b9a4 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -350,11 +350,6 @@ func (self *worker) wait() { continue } - // check if canon block and write transactions - if stat == core.CanonStatTy { - // implicit by posting ChainHeadEvent - mustCommitNewWork = false - } // Broadcast the block and announce chain insertion event self.mux.Post(core.NewMinedBlockEvent{Block: block}) var ( From 7e1aa97d652a77871494bf036247345092fa382a Mon Sep 17 00:00:00 2001 From: "amalraj.manigmail.com" Date: Tue, 27 Nov 2018 11:36:59 +0800 Subject: [PATCH 08/32] core/vm: revert to joel's change to getdualstate. This is a mandatory change for quorum dual state & read only EVM This commit implements a dual state approach. The dual state approach separates public and private state by making the core vm environment context aware. Although not currently implemented it will need to prohibit value transfers and it must initialise all transactions from accounts on the public state. This means that sending transactions increments the account nonce on the public state and contract addresses are derived from the public state when initialised by a transaction. For obvious reasons, contract created by private contracts are still derived from public state. This is required in order to have consensus over the public state at all times as non-private participants would still process the transaction on the public state even though private payload can not be decrypted. This means that participants of a private group must do the same in order to have public consensus. However the creation of the contract and interaction still occurs on the private state. It implements support for the following calling model: S: sender, (X): private, X: public, ->: direction, [ ]: read only mode 1. S -> A -> B 2. S -> (A) -> (B) 3. S -> (A) -> [ B -> C ] It does not support 1. (S) -> A 2. (S) -> (A) 3. S -> (A) -> B Implemented "read only" mode for the EVM. Read only mode is checked during any opcode that could potentially modify the state. If such an opcode is encountered during "read only", it throws an exception. The EVM is flagged "read only" when a private contract calls in to public state. --- core/vm/instructions.go | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 1ec13ba35..ab779ee53 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -391,7 +391,10 @@ func opAddress(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack * func opBalance(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { slot := stack.peek() - slot.Set(evm.StateDB.GetBalance(common.BigToAddress(slot))) + addr := common.BigToAddress(slot) + // Quorum: get public/private state db based on addr + balance := getDualState(evm, addr).GetBalance(addr) + slot.Set(balance) return nil, nil } @@ -457,7 +460,9 @@ func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, func opExtCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { slot := stack.peek() - slot.SetUint64(uint64(evm.StateDB.GetCodeSize(common.BigToAddress(slot)))) + addr := common.BigToAddress(slot) + // Quorum: get public/private state db based on addr + slot.SetUint64(uint64(getDualState(evm, addr).GetCodeSize(addr))) return nil, nil } @@ -489,7 +494,8 @@ func opExtCodeCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory, sta codeOffset = stack.pop() length = stack.pop() ) - codeCopy := getDataBig(evm.StateDB.GetCode(addr), codeOffset, length) + // Quorum: get public/private state db based on addr + codeCopy := getDataBig(getDualState(evm, addr).GetCode(addr), codeOffset, length) memory.Set(memOffset.Uint64(), length.Uint64(), codeCopy) evm.interpreter.intPool.put(memOffset, codeOffset, length) @@ -571,7 +577,8 @@ func opMstore8(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack * func opSload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { loc := stack.peek() - val := evm.StateDB.GetState(contract.Address(), common.BigToHash(loc)) + // Quorum: get public/private state db based on addr + val := getDualState(evm, contract.Address()).GetState(contract.Address(), common.BigToHash(loc)) loc.SetBytes(val.Bytes()) return nil, nil } @@ -579,7 +586,8 @@ func opSload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *St func opSstore(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { loc := common.BigToHash(stack.pop()) val := stack.pop() - evm.StateDB.SetState(contract.Address(), loc, common.BigToHash(val)) + // Quorum: get public/private state db based on addr + getDualState(evm, contract.Address()).SetState(contract.Address(), loc, common.BigToHash(val)) evm.interpreter.intPool.put(val) return nil, nil @@ -794,10 +802,12 @@ func opStop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta } func opSuicide(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - balance := evm.StateDB.GetBalance(contract.Address()) - evm.StateDB.AddBalance(common.BigToAddress(stack.pop()), balance) + // Quorum: get public/private state db based on addr + db := getDualState(evm, contract.Address()) + balance := db.GetBalance(contract.Address()) + db.AddBalance(common.BigToAddress(stack.pop()), balance) - evm.StateDB.Suicide(contract.Address()) + db.Suicide(contract.Address()) return nil, nil } From a913c4cee82e0c0e6700b3eb31c775e6c7982bc6 Mon Sep 17 00:00:00 2001 From: fixanoid Date: Tue, 27 Nov 2018 13:10:02 -0500 Subject: [PATCH 09/32] Update HACKING.md --- HACKING.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/HACKING.md b/HACKING.md index e408d464f..9979309f8 100644 --- a/HACKING.md +++ b/HACKING.md @@ -60,3 +60,53 @@ func (env *EVM) Pop() { Note the invariant that `StateDB` always points to the current state db. The other interesting note is read only mode. Any time we call from the private state into the public state (`env.privateState != statedb`), we require anything deeper to be *read only*. Private state transactions can't affect public state, so we throw an EVM exception on any mutating operation (`SELFDESTRUCT, CREATE, SSTORE, LOG0, LOG1, LOG2, LOG3, LOG4`). Question: have any more mutating operations been added? Question: could we not mutate deeper private state? + + +Original commit explanation: +``` +commit 763f939f4725daa136161868d3b01fa7a84eb71e +Author: Jeffrey Wilcke +Date: Mon Oct 31 12:46:40 2016 +0100 + + core, core/vm: dual state & read only EVM + + This commit implements a dual state approach. The dual state approach + separates public and private state by making the core vm environment + context aware. + + Although not currently implemented it will need to prohibit value + transfers and it must initialise all transactions from accounts on the + public state. This means that sending transactions increments the + account nonce on the public state and contract addresses are derived + from the public state when initialised by a transaction. For obvious + reasons, contract created by private contracts are still derived from + public state. + + This is required in order to have consensus over the public state at all + times as non-private participants would still process the transaction on + the public state even though private payload can not be decrypted. This + means that participants of a private group must do the same in order to + have public consensus. However the creation of the contract and + interaction still occurs on the private state. + + It implements support for the following calling model: + + S: sender, (X): private, X: public, ->: direction, [ ]: read only mode + + 1. S -> A -> B + 2. S -> (A) -> (B) + 3. S -> (A) -> [ B -> C ] + + It does not support + + 1. (S) -> A + 2. (S) -> (A) + 3. S -> (A) -> B + + Implemented "read only" mode for the EVM. Read only mode is checked + during any opcode that could potentially modify the state. If such an + opcode is encountered during "read only", it throws an exception. + + The EVM is flagged "read only" when a private contract calls in to + public state. +``` From 36000ec2a1fe2e7fcab6fb074c52b2e4196eb232 Mon Sep 17 00:00:00 2001 From: vsmk98 Date: Tue, 27 Nov 2018 23:27:07 +0800 Subject: [PATCH 10/32] changes to set readOnlyDepth only once during the entire opCode execution --- core/vm/evm.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index c47836837..55826102c 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -498,7 +498,10 @@ func getDualState(env *EVM, addr common.Address) StateDB { func (env *EVM) PublicState() PublicState { return env.publicState } func (env *EVM) PrivateState() PrivateState { return env.privateState } func (env *EVM) Push(statedb StateDB) { - if env.privateState != statedb { + // Quorum : the read only depth to be set up only once for the entire + // op code execution. This will be set first time transition from + // private state to public state happens + if !env.quorumReadOnly && env.privateState != statedb { env.quorumReadOnly = true env.readOnlyDepth = env.currentStateDepth } From c2a580217fdb7b28d5da030724b2e2f967dcdaf0 Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Wed, 28 Nov 2018 16:17:05 -0500 Subject: [PATCH 11/32] fixed method signature --- core/tx_pool_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index 45330f047..5d085f2f8 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -279,7 +279,7 @@ func TestInvalidTransactions(t *testing.T) { } data := make([]byte, (64*1024)+1) - tx2, _ := types.SignTx(types.NewTransaction(2, common.Address{}, big.NewInt(100), big.NewInt(100000), big.NewInt(1), data), types.HomesteadSigner{}, key) + tx2, _ := types.SignTx(types.NewTransaction(2, common.Address{}, big.NewInt(100), 100000, big.NewInt(1), data), types.HomesteadSigner{}, key) if err := pool.AddRemote(tx2); err != ErrOversizedData { t.Error("expected", ErrOversizedData, "; got", err) } From a916458afff23a4d3eafd20635b1818a1ad9a861 Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Fri, 30 Nov 2018 17:24:50 -0500 Subject: [PATCH 12/32] tests/: minor refactoring to enable Ethereum tests --- params/protocol_params.go | 7 +++++-- tests/init_test.go | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/params/protocol_params.go b/params/protocol_params.go index 1ee477821..c0cb7294a 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -20,13 +20,16 @@ import "math/big" var ( TargetGasLimit = GenesisGasLimit // The artificial target -) -const ( + // the followings are modified by Quorum and purposely moved from `const` section + // so to faclitate the execution of Ethereum Tests + // @see tests/init_test.go#TestMain GasLimitBoundDivisor uint64 = 4096 // The bound divisor of the gas limit, used in update calculations. MinGasLimit uint64 = 700000000 // Minimum the gas limit may ever be. GenesisGasLimit uint64 = 800000000 // Gas limit of the Genesis block. +) +const ( MaximumExtraDataSize uint64 = 32 // Maximum size extra data may be after Genesis. ExpByteGas uint64 = 10 // Times ceil(log256(exponent)) for the EXP instruction. SloadGas uint64 = 50 // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added. diff --git a/tests/init_test.go b/tests/init_test.go index 26e919d24..28a9d9dae 100644 --- a/tests/init_test.go +++ b/tests/init_test.go @@ -261,3 +261,20 @@ func runTestFunc(runTest interface{}, t *testing.T, name string, m reflect.Value m.MapIndex(reflect.ValueOf(key)), }) } + +func TestMain(m *testing.M) { + backupMinGasLimit := params.MinGasLimit + backupGasLimitBoundDivisor := params.GasLimitBoundDivisor + backupGenesisGasLimit := params.GenesisGasLimit + defer func() { + params.GasLimitBoundDivisor = backupGasLimitBoundDivisor + params.MinGasLimit = backupMinGasLimit + params.GenesisGasLimit = backupGenesisGasLimit + }() + params.GasLimitBoundDivisor = 1024 + params.MinGasLimit = 5000 + params.GenesisGasLimit = 4712388 + + retCode := m.Run() + os.Exit(retCode) +} \ No newline at end of file From dd5dafe86582eb260745d6b158987cb583951386 Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Fri, 30 Nov 2018 17:26:05 -0500 Subject: [PATCH 13/32] simplify the setup --- tests/init_test.go | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/tests/init_test.go b/tests/init_test.go index 28a9d9dae..fda1aa82b 100644 --- a/tests/init_test.go +++ b/tests/init_test.go @@ -263,18 +263,10 @@ func runTestFunc(runTest interface{}, t *testing.T, name string, m reflect.Value } func TestMain(m *testing.M) { - backupMinGasLimit := params.MinGasLimit - backupGasLimitBoundDivisor := params.GasLimitBoundDivisor - backupGenesisGasLimit := params.GenesisGasLimit - defer func() { - params.GasLimitBoundDivisor = backupGasLimitBoundDivisor - params.MinGasLimit = backupMinGasLimit - params.GenesisGasLimit = backupGenesisGasLimit - }() params.GasLimitBoundDivisor = 1024 params.MinGasLimit = 5000 params.GenesisGasLimit = 4712388 retCode := m.Run() os.Exit(retCode) -} \ No newline at end of file +} From 9e08c25f2c25835988209d4894a9edf289e52dc0 Mon Sep 17 00:00:00 2001 From: fixanoid Date: Mon, 3 Dec 2018 10:02:59 -0500 Subject: [PATCH 14/32] Rename HACKING.md to NOTES.md --- HACKING.md => NOTES.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename HACKING.md => NOTES.md (100%) diff --git a/HACKING.md b/NOTES.md similarity index 100% rename from HACKING.md rename to NOTES.md From eab8d793f946f292954ff8e150645661ba599164 Mon Sep 17 00:00:00 2001 From: fixanoid Date: Mon, 3 Dec 2018 10:04:37 -0500 Subject: [PATCH 15/32] Update NOTES.md --- NOTES.md | 102 +++++++++++++++++++++++++++---------------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/NOTES.md b/NOTES.md index 9979309f8..e38ff0296 100644 --- a/NOTES.md +++ b/NOTES.md @@ -2,7 +2,57 @@ ## How does private state work? -Let's look at the EVM structure: +Original commit from Jeff explains the dual public and private state with INITIAL restrictions: +``` +commit 763f939f4725daa136161868d3b01fa7a84eb71e +Author: Jeffrey Wilcke +Date: Mon Oct 31 12:46:40 2016 +0100 + + core, core/vm: dual state & read only EVM + + This commit implements a dual state approach. The dual state approach + separates public and private state by making the core vm environment + context aware. + + Although not currently implemented it will need to prohibit value + transfers and it must initialise all transactions from accounts on the + public state. This means that sending transactions increments the + account nonce on the public state and contract addresses are derived + from the public state when initialised by a transaction. For obvious + reasons, contract created by private contracts are still derived from + public state. + + This is required in order to have consensus over the public state at all + times as non-private participants would still process the transaction on + the public state even though private payload can not be decrypted. This + means that participants of a private group must do the same in order to + have public consensus. However the creation of the contract and + interaction still occurs on the private state. + + It implements support for the following calling model: + + S: sender, (X): private, X: public, ->: direction, [ ]: read only mode + + 1. S -> A -> B + 2. S -> (A) -> (B) + 3. S -> (A) -> [ B -> C ] + + It does not support + + 1. (S) -> A + 2. (S) -> (A) + 3. S -> (A) -> B + + Implemented "read only" mode for the EVM. Read only mode is checked + during any opcode that could potentially modify the state. If such an + opcode is encountered during "read only", it throws an exception. + + The EVM is flagged "read only" when a private contract calls in to + public state. +``` + + +Some things have changed since, let's look at the EVM structure in some more detail: ```go type EVM struct { @@ -60,53 +110,3 @@ func (env *EVM) Pop() { Note the invariant that `StateDB` always points to the current state db. The other interesting note is read only mode. Any time we call from the private state into the public state (`env.privateState != statedb`), we require anything deeper to be *read only*. Private state transactions can't affect public state, so we throw an EVM exception on any mutating operation (`SELFDESTRUCT, CREATE, SSTORE, LOG0, LOG1, LOG2, LOG3, LOG4`). Question: have any more mutating operations been added? Question: could we not mutate deeper private state? - - -Original commit explanation: -``` -commit 763f939f4725daa136161868d3b01fa7a84eb71e -Author: Jeffrey Wilcke -Date: Mon Oct 31 12:46:40 2016 +0100 - - core, core/vm: dual state & read only EVM - - This commit implements a dual state approach. The dual state approach - separates public and private state by making the core vm environment - context aware. - - Although not currently implemented it will need to prohibit value - transfers and it must initialise all transactions from accounts on the - public state. This means that sending transactions increments the - account nonce on the public state and contract addresses are derived - from the public state when initialised by a transaction. For obvious - reasons, contract created by private contracts are still derived from - public state. - - This is required in order to have consensus over the public state at all - times as non-private participants would still process the transaction on - the public state even though private payload can not be decrypted. This - means that participants of a private group must do the same in order to - have public consensus. However the creation of the contract and - interaction still occurs on the private state. - - It implements support for the following calling model: - - S: sender, (X): private, X: public, ->: direction, [ ]: read only mode - - 1. S -> A -> B - 2. S -> (A) -> (B) - 3. S -> (A) -> [ B -> C ] - - It does not support - - 1. (S) -> A - 2. (S) -> (A) - 3. S -> (A) -> B - - Implemented "read only" mode for the EVM. Read only mode is checked - during any opcode that could potentially modify the state. If such an - opcode is encountered during "read only", it throws an exception. - - The EVM is flagged "read only" when a private contract calls in to - public state. -``` From 1b543eb0ba09ebe424d802d91d389ab2a0e6b2f9 Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Mon, 3 Dec 2018 11:10:55 -0500 Subject: [PATCH 16/32] separated consts for Quorum and those used in upstream Geth --- consensus/ethash/consensus.go | 6 +++--- params/protocol_params.go | 15 +++++++++------ tests/init_test.go | 9 --------- 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 28950e749..76a865635 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -31,7 +31,7 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" - set "gopkg.in/fatih/set.v0" + "gopkg.in/fatih/set.v0" ) // Ethash proof-of-work protocol constants. @@ -285,9 +285,9 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent * if diff < 0 { diff *= -1 } - limit := parent.GasLimit / params.GasLimitBoundDivisor + limit := parent.GasLimit / params.OriginalGasLimitBoundDivisor - if uint64(diff) >= limit || header.GasLimit < params.MinGasLimit { + if uint64(diff) >= limit || header.GasLimit < params.OriginnalMinGasLimit { return fmt.Errorf("invalid gas limit: have %d, want %d += %d", header.GasLimit, parent.GasLimit, limit) } // Verify that the block number is parent's +1 diff --git a/params/protocol_params.go b/params/protocol_params.go index c0cb7294a..2ba50e967 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -21,15 +21,18 @@ import "math/big" var ( TargetGasLimit = GenesisGasLimit // The artificial target - // the followings are modified by Quorum and purposely moved from `const` section - // so to faclitate the execution of Ethereum Tests - // @see tests/init_test.go#TestMain - GasLimitBoundDivisor uint64 = 4096 // The bound divisor of the gas limit, used in update calculations. - MinGasLimit uint64 = 700000000 // Minimum the gas limit may ever be. - GenesisGasLimit uint64 = 800000000 // Gas limit of the Genesis block. ) const ( + // these are original values from upstream Geth, used in ethash consensus + OriginnalMinGasLimit uint64 = 5000 // The bound divisor of the gas limit, used in update calculations. + OriginalGasLimitBoundDivisor uint64 = 1024 // Minimum the gas limit may ever be. + + // modified values for Quorum + GasLimitBoundDivisor uint64 = 4096 // The bound divisor of the gas limit, used in update calculations. + MinGasLimit uint64 = 700000000 // Minimum the gas limit may ever be. + GenesisGasLimit uint64 = 800000000 // Gas limit of the Genesis block. + MaximumExtraDataSize uint64 = 32 // Maximum size extra data may be after Genesis. ExpByteGas uint64 = 10 // Times ceil(log256(exponent)) for the EXP instruction. SloadGas uint64 = 50 // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added. diff --git a/tests/init_test.go b/tests/init_test.go index fda1aa82b..26e919d24 100644 --- a/tests/init_test.go +++ b/tests/init_test.go @@ -261,12 +261,3 @@ func runTestFunc(runTest interface{}, t *testing.T, name string, m reflect.Value m.MapIndex(reflect.ValueOf(key)), }) } - -func TestMain(m *testing.M) { - params.GasLimitBoundDivisor = 1024 - params.MinGasLimit = 5000 - params.GenesisGasLimit = 4712388 - - retCode := m.Run() - os.Exit(retCode) -} From f83e31a4f5284ac06b42efe1319b823fbf639972 Mon Sep 17 00:00:00 2001 From: fixanoid Date: Mon, 3 Dec 2018 21:59:49 +0000 Subject: [PATCH 17/32] Moving Raft doc into docs --- raft/doc.md => docs/raft.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename raft/doc.md => docs/raft.md (100%) diff --git a/raft/doc.md b/docs/raft.md similarity index 100% rename from raft/doc.md rename to docs/raft.md From 5758e38962f87cd77f24d3512b9ade3527ed346c Mon Sep 17 00:00:00 2001 From: fixanoid Date: Mon, 3 Dec 2018 17:03:04 -0500 Subject: [PATCH 18/32] Updating raft doc location --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0e7515c39..a06698ee0 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ The official docker containers can be found under https://hub.docker.com/u/quoru * [Constellation](https://github.com/jpmorganchase/constellation): Haskell implementation of peer-to-peer encrypted message exchange for transaction privacy * [Tessera](https://github.com/jpmorganchase/tessera): Java implementation of peer-to-peer encrypted message exchange for transaction privacy * Quorum supported consensuses - * [Raft Consensus Documentation](raft/doc.md) + * [Raft Consensus Documentation](docs/raft.md) * [Istanbul BFT Consensus Documentation](https://github.com/ethereum/EIPs/issues/650): [RPC API](https://github.com/getamis/go-ethereum/wiki/RPC-API) and [technical article](https://medium.com/getamis/istanbul-bft-ibft-c2758b7fe6ff) * [Clique POA Consensus Documentation](https://github.com/ethereum/EIPs/issues/225) and a [guide to setup clique json](https://modalduality.org/posts/puppeth/) with [puppeth](https://blog.ethereum.org/2017/04/14/geth-1-6-puppeth-master/) * [ZSL](https://github.com/jpmorganchase/quorum/wiki/ZSL) wiki page and [documentation](https://github.com/jpmorganchase/zsl-q/blob/master/README.md) From 503935ccce96828fe1a35dc1c4240c718d0ae454 Mon Sep 17 00:00:00 2001 From: fixanoid Date: Mon, 3 Dec 2018 17:08:07 -0500 Subject: [PATCH 19/32] Adding istanbul-tools ref --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a06698ee0..ad10fe154 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ The official docker containers can be found under https://hub.docker.com/u/quoru * [Tessera](https://github.com/jpmorganchase/tessera): Java implementation of peer-to-peer encrypted message exchange for transaction privacy * Quorum supported consensuses * [Raft Consensus Documentation](docs/raft.md) - * [Istanbul BFT Consensus Documentation](https://github.com/ethereum/EIPs/issues/650): [RPC API](https://github.com/getamis/go-ethereum/wiki/RPC-API) and [technical article](https://medium.com/getamis/istanbul-bft-ibft-c2758b7fe6ff) + * [Istanbul BFT Consensus Documentation](https://github.com/ethereum/EIPs/issues/650): [RPC API](https://github.com/getamis/go-ethereum/wiki/RPC-API) and [technical article](https://medium.com/getamis/istanbul-bft-ibft-c2758b7fe6ff). Please note that updated istanbul-tools is now hosted in [this](https://github.com/jpmorganchase/istanbul-tools/) repository * [Clique POA Consensus Documentation](https://github.com/ethereum/EIPs/issues/225) and a [guide to setup clique json](https://modalduality.org/posts/puppeth/) with [puppeth](https://blog.ethereum.org/2017/04/14/geth-1-6-puppeth-master/) * [ZSL](https://github.com/jpmorganchase/quorum/wiki/ZSL) wiki page and [documentation](https://github.com/jpmorganchase/zsl-q/blob/master/README.md) * [quorum-tools](https://github.com/jpmorganchase/quorum-tools): local cluster orchestration, and integration testing tool From f5ffeef64b5e15a3f8a0e2368f2faa2a55affd85 Mon Sep 17 00:00:00 2001 From: fixanoid Date: Mon, 3 Dec 2018 17:11:54 -0500 Subject: [PATCH 20/32] Istanbul RPC API --- docs/istanbul-rpc-api.md | 86 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 docs/istanbul-rpc-api.md diff --git a/docs/istanbul-rpc-api.md b/docs/istanbul-rpc-api.md new file mode 100644 index 000000000..baa8302db --- /dev/null +++ b/docs/istanbul-rpc-api.md @@ -0,0 +1,86 @@ +# Istanbul RPC API +This is an up to date copy of original wiki entry located here https://github.com/getamis/go-ethereum/wiki/RPC-API + + +# Getting Started +1. Run Istanbul geth with `--rpcapi "istanbul"` +2. `geth attach` + +## API Reference + +### istanbul.candidates +Candidates returns the current candidates which the node tries to vote in or out. +``` +istanbul.candidates +``` + +#### Returns +`map[string] boolean` - returns the current candidates map. + +### istanbul.discard +Discard drops a currently running candidate, stopping the validator from casting further votes (either for or against). +``` +istanbul.discard(address) +``` + +#### Parameters +`string` - the address of the candidate + +### istanbul.getSnapshot +GetSnapshot retrieves the state snapshot at a given block. +``` +istanbul.getSnapshot(blockHashOrBlockNumber) +``` + +#### Parameters +`String|Number` - The block number, the string "latest" or nil. nil is the same with string "latest" and means the latest block + +#### Returns +`Object` - The snapshot object + +### istanbul.getSnapshotAtHash +GetSnapshotAtHash retrieves the state snapshot at a given block. +``` +istanbul.getSnapshotAtHash(blockHash) +``` + +#### Parameters +`String` - The block hash + +#### Returns +`Object` - The snapshot object + +### istanbul.getValidators +GetValidators retrieves the list of authorized validators at the specified block. +``` +istanbul.getValidators(blockHashOrBlockNumber) +``` + +#### Parameters +`String|Number` - The block number, the string "latest" or nil. nil is the same with string "latest" and means the latest block + +#### Returns +`[]string` - The validator address array + +### istanbul.getValidatorsAtHash +GetValidatorsAtHash retrieves the list of authorized validators at the specified block. +``` +istanbul.getValidatorsAtHash(blockHash) +``` + +#### Parameters +`String` - The block hash + +#### Returns +`[]string` - The validator address array + +### istanbul.propose +Propose injects a new authorization candidate that the validator will attempt to push through. If the number of vote is larger than 1/2 of validators to vote in/out, the candidate will be added/removed in validator set. + +``` +istanbul.propose(address, auth) +``` + +#### Parameters +`String` - The address of candidate +`bool` - `true` votes in and `false` votes out From 119412f75ad3b7f6480dceeddd1635de1e22d5cd Mon Sep 17 00:00:00 2001 From: fixanoid Date: Mon, 3 Dec 2018 17:13:44 -0500 Subject: [PATCH 21/32] Update README.md --- docs/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/README.md b/docs/README.md index cbddd4a82..dd50a04a7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -3,6 +3,8 @@ * [Whitepaper](./Quorum%20Whitepaper%20v0.2.pdf) (PDF) - Quorum Whitepaper [demo video](https://vimeo.com/user5833792/review/210456842/a42d0fcb87) * [Design](./design.md) - Quorum design overview + * [Raft Specific Documentation](./raft.md) - Overview of raft implementation + * [Istanbul RPC API](./istanbul-rpc-api.md) - Overview of Istanbul BFT APIs * [Privacy](./privacy.md) - Sending private transactions [privacy video](https://vimeo.com/user5833792/review/210456729/8f70cfaaa5) * [Running](./running.md) - Detailed instructions for running Quorum nodes (see also [Constellation](https://github.com/jpmorganchase/constellation), [Tessera](https://github.com/jpmorganchase/tessera)) * [API](./api.md) - new privacy API From 55aeeb4135e82f43d7d4066c14ddc3100e1721f1 Mon Sep 17 00:00:00 2001 From: fixanoid Date: Mon, 3 Dec 2018 17:14:27 -0500 Subject: [PATCH 22/32] Updating IBFT API doc location --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ad10fe154..5fa8f8612 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ The official docker containers can be found under https://hub.docker.com/u/quoru * [Tessera](https://github.com/jpmorganchase/tessera): Java implementation of peer-to-peer encrypted message exchange for transaction privacy * Quorum supported consensuses * [Raft Consensus Documentation](docs/raft.md) - * [Istanbul BFT Consensus Documentation](https://github.com/ethereum/EIPs/issues/650): [RPC API](https://github.com/getamis/go-ethereum/wiki/RPC-API) and [technical article](https://medium.com/getamis/istanbul-bft-ibft-c2758b7fe6ff). Please note that updated istanbul-tools is now hosted in [this](https://github.com/jpmorganchase/istanbul-tools/) repository + * [Istanbul BFT Consensus Documentation](https://github.com/ethereum/EIPs/issues/650): [RPC API](https://github.com/jpmorganchase/quorum/blob/master/docs/istanbul-rpc-api.md) and [technical article](https://medium.com/getamis/istanbul-bft-ibft-c2758b7fe6ff). Please note that updated istanbul-tools is now hosted in [this](https://github.com/jpmorganchase/istanbul-tools/) repository * [Clique POA Consensus Documentation](https://github.com/ethereum/EIPs/issues/225) and a [guide to setup clique json](https://modalduality.org/posts/puppeth/) with [puppeth](https://blog.ethereum.org/2017/04/14/geth-1-6-puppeth-master/) * [ZSL](https://github.com/jpmorganchase/quorum/wiki/ZSL) wiki page and [documentation](https://github.com/jpmorganchase/zsl-q/blob/master/README.md) * [quorum-tools](https://github.com/jpmorganchase/quorum-tools): local cluster orchestration, and integration testing tool From 47954d8a559a961f687810f400db73ed63bf4eac Mon Sep 17 00:00:00 2001 From: fixanoid Date: Tue, 4 Dec 2018 11:24:07 -0500 Subject: [PATCH 23/32] Update BUILDING.md --- BUILDING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BUILDING.md b/BUILDING.md index a9e9d8162..57a48572c 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -1,6 +1,8 @@ # Building Quorum +Note: Building Quorum requires both a Go (version 1.9 or later) and a C compiler. You can install them using your favourite package manager. + Clone the repository and build the source: ``` From c49a833eb9341f21983dd18ca4cc78173ad0bcfd Mon Sep 17 00:00:00 2001 From: namtruong Date: Wed, 5 Dec 2018 14:30:42 +0000 Subject: [PATCH 24/32] add support for private sendRawTransaction - merge with latest quorum --- docs/api.md | 51 ++++++++++++++++++++++++++ internal/ethapi/api.go | 39 ++++++++++++++++++-- internal/web3ext/web3ext.go | 6 +++ private/constellation/constellation.go | 12 ++++++ private/constellation/node.go | 24 ++++++++++++ private/private.go | 1 + 6 files changed, 130 insertions(+), 3 deletions(-) diff --git a/docs/api.md b/docs/api.md index d7e2b84d0..143c9a6f3 100644 --- a/docs/api.md +++ b/docs/api.md @@ -3,6 +3,8 @@ ## Privacy APIs +#### eth.sendTransaction + __To support private transactions in Quorum, the `web3.eth.sendTransaction(object)` API method has been modified.__ ```js @@ -50,6 +52,55 @@ web3.eth.sendTransaction({ ``` *** +#### eth.sendRawPrivateTransaction + +__To support sending raw transactions in Quorum, the `web3.eth.sendRawPrivateTransaction(string, object)` API method has been created.__ + +```js +web3.eth.sendRawPrivateTransaction(signedTransactionData [, privateData] [, callback]) +``` + +Sends an already signed transaction. For example can be signed using: https://github.com/SilentCicero/ethereumjs-accounts + +__Important:__ Please note that before calling this API, a `storeraw` api need to be called first to Quorum's private transaction manager. Instructions on how to do this can be found [here](https://github.com/jpmorganchase/tessera/wiki/Interface-&-API). + +##### Parameters + 1. `String` - Signed transaction data in HEX format + 2. `Object` - Private data to send + - `privateFor`: `List` - When sending a private transaction, an array of the recipients' base64-encoded public keys. +3. `Function` - (optional) If you pass a callback the HTTP request is made asynchronous. See [this note](#using-callbacks) for details. + + ##### Returns + `String` - The 32 Bytes transaction hash as HEX string. + If the transaction was a contract creation use [web3.eth.getTransactionReceipt()](#web3ethgettransactionreceipt) to get the contract address, after the transaction was mined. + + + ##### Example + ```js + var Tx = require('ethereumjs-tx'); + var privateKey = new Buffer('e331b6d69882b4cb4ea581d88e0b604039a3de5967688d3dcffdd2270c0fd109', 'hex') + var rawTx = { + nonce: '0x00', + gasPrice: '0x09184e72a000', + gasLimit: '0x2710', + to: '0x0000000000000000000000000000000000000000', + value: '0x00', + // This data should be the hex value of the hash returned by Quorum's privacy transaction manager after invoking storeraw api + data: '0x7f7465737432000000000000000000000000000000000000000000000000000000600057' + } + var tx = new Tx(rawTx); + tx.sign(privateKey); + var serializedTx = tx.serialize(); + //console.log(serializedTx.toString('hex')); + //f889808609184e72a00082271094000000000000000000000000000000000000000080a47f74657374320000000000000000000000000000000000000000000000000000006000571ca08a8bbf888cfa37bbf0bb965423625641fc956967b81d12e23709cead01446075a01ce999b56a8a88504be365442ea61239198e23d1fce7d00fcfc5cd3b44b7215f + web3.eth.sendRawPrivateTransaction('0x' + serializedTx.toString('hex'), {privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}, function(err, hash) { + if (!err) + console.log(hash); // "0x7f9fade1c0d57a7af66ab4ead79fade1c0d57a7af66ab4ead7c2c2eb7b11a91385" + }); + ``` + + + ## JSON RPC Privacy API Reference __In addition to the JSON-RPC provided by Ethereum, Quorum exposes below two API calls.__ diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 567c33cc9..dc0718d36 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1168,12 +1168,17 @@ type SendTxArgs struct { Input *hexutil.Bytes `json:"input"` //Quorum - PrivateFrom string `json:"privateFrom"` - PrivateFor []string `json:"privateFor"` - PrivateTxType string `json:"restriction"` + PrivateFrom string `json:"privateFrom"` + PrivateFor []string `json:"privateFor"` + PrivateTxType string `json:"restriction"` //End-Quorum } +// SendRawTxArgs represents the arguments to submit a new signed private transaction into the transaction pool. +type SendRawTxArgs struct { + PrivateFor []string `json:"privateFor"` +} + // setDefaults is a helper function that fills in default values for unspecified tx fields. func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error { if args.Gas == nil { @@ -1315,6 +1320,33 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod return submitTransaction(ctx, s.b, tx, tx.IsPrivate()) } +// SendRawPrivateTransaction will add the signed transaction to the transaction pool. +// The sender is responsible for signing the transaction and using the correct nonce. +func (s *PublicTransactionPoolAPI) SendRawPrivateTransaction(ctx context.Context, encodedTx hexutil.Bytes, args SendRawTxArgs) (common.Hash, error) { + + tx := new(types.Transaction) + if err := rlp.DecodeBytes(encodedTx, tx); err != nil { + return common.Hash{}, err + } + + txHash := []byte(tx.Data()) + isPrivate := args.PrivateFor != nil + + if isPrivate { + if len(txHash) > 0 { + //Send private transaction to privacy manager + log.Info("sending private tx", "data", fmt.Sprintf("%x", txHash), "privatefor", args.PrivateFor) + result, err := private.P.SendSignedTx(txHash, args.PrivateFor) + log.Info("sent private tx", "result", fmt.Sprintf("%x", result), "privatefor", args.PrivateFor) + if err != nil { + return common.Hash{}, err + } + } + } + + return submitTransaction(ctx, s.b, tx, isPrivate) +} + // Sign calculates an ECDSA signature for: // keccack256("\x19Ethereum Signed Message:\n" + len(message) + message). // @@ -1688,4 +1720,5 @@ func (s *PublicBlockChainAPI) GetQuorumPayload(digestHex string) (string, error) } return fmt.Sprintf("0x%x", data), nil } + //End-Quorum diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 24c9f5297..c4a13593e 100755 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -396,6 +396,12 @@ const Eth_JS = ` web3._extend({ property: 'eth', methods: [ + new web3._extend.Method({ + name: 'sendRawPrivateTransaction', + call: 'eth_sendRawPrivateTransaction', + params: 2, + inputFormatter: [null, null] + }), new web3._extend.Method({ name: 'sign', call: 'eth_sign', diff --git a/private/constellation/constellation.go b/private/constellation/constellation.go index 69afcde68..3cc9aa62c 100644 --- a/private/constellation/constellation.go +++ b/private/constellation/constellation.go @@ -33,6 +33,18 @@ func (g *Constellation) Send(data []byte, from string, to []string) (out []byte, return out, nil } +func (g *Constellation) SendSignedTx(data []byte, to []string) (out []byte, err error) { + if g.isConstellationNotInUse { + return nil, ErrConstellationIsntInit + } + out, err = g.node.SendSignedPayload(data, to) + if err != nil { + return nil, err + } + return out, nil +} + + func (g *Constellation) Receive(data []byte) ([]byte, error) { if g.isConstellationNotInUse { return nil, nil diff --git a/private/constellation/node.go b/private/constellation/node.go index ce4a420eb..50263aae6 100644 --- a/private/constellation/node.go +++ b/private/constellation/node.go @@ -106,6 +106,30 @@ func (c *Client) SendPayload(pl []byte, b64From string, b64To []string) ([]byte, return ioutil.ReadAll(base64.NewDecoder(base64.StdEncoding, res.Body)) } +func (c *Client) SendSignedPayload(signedPayload []byte, b64To []string) ([]byte, error) { + buf := bytes.NewBuffer(signedPayload) + req, err := http.NewRequest("POST", "http+unix://c/sendsignedtx", buf) + if err != nil { + return nil, err + } + + req.Header.Set("c11n-to", strings.Join(b64To, ",")) + req.Header.Set("Content-Type", "application/octet-stream") + res, err := c.httpClient.Do(req) + + if res != nil { + defer res.Body.Close() + } + if err != nil { + return nil, err + } + if res.StatusCode != 200 { + return nil, fmt.Errorf("Non-200 status code: %+v", res) + } + + return ioutil.ReadAll(base64.NewDecoder(base64.StdEncoding, res.Body)) +} + func (c *Client) ReceivePayload(key []byte) ([]byte, error) { req, err := http.NewRequest("GET", "http+unix://c/receiveraw", nil) if err != nil { diff --git a/private/private.go b/private/private.go index 2cf2175bf..bcbad08da 100644 --- a/private/private.go +++ b/private/private.go @@ -8,6 +8,7 @@ import ( type PrivateTransactionManager interface { Send(data []byte, from string, to []string) ([]byte, error) + SendSignedTx(data []byte, to []string) ([]byte, error) Receive(data []byte) ([]byte, error) } From 089841e036cf68aebec026d265e49e68544624e9 Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Wed, 5 Dec 2018 13:47:01 -0500 Subject: [PATCH 25/32] added dual state implementation to StaticCall --- core/dual_state_test.go | 92 +++++++++++++++++++++++++++++++++++++++++ core/vm/evm.go | 4 ++ core/vm/interpreter.go | 1 - 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/core/dual_state_test.go b/core/dual_state_test.go index b091ff04c..4af00ab67 100644 --- a/core/dual_state_test.go +++ b/core/dual_state_test.go @@ -119,3 +119,95 @@ func TestDualStateReadOnly(t *testing.T) { t.Errorf("expected 0 got %x", value) } } + +var ( + calleeAddress = common.Address{2} + calleeContractCode = "600a6000526001601ff300" // a function that returns 10 + callerAddress = common.Address{1} + // a functionn that calls the callee's function at its address and return the same value + //000000: PUSH1 0x01 + //000002: PUSH1 0x00 + //000004: PUSH1 0x00 + //000006: PUSH1 0x00 + //000008: PUSH20 0x0200000000000000000000000000000000000000 + //000029: PUSH3 0x0186a0 + //000033: STATICCALL + //000034: PUSH1 0x01 + //000036: PUSH1 0x00 + //000038: RETURN + //000039: STOP + callerContractCode = "6001600060006000730200000000000000000000000000000000000000620186a0fa60016000f300" +) + +func verifyStaticCall(t *testing.T, privateState *state.StateDB, publicState *state.StateDB, expectedHash common.Hash) { + author := common.Address{} + msg := callmsg{ + addr: author, + to: &callerAddress, + value: big.NewInt(1), + gas: 1000000, + gasPrice: new(big.Int), + data: nil, + } + + ctx := NewEVMContext(msg, &dualStateTestHeader, nil, &author) + env := vm.NewEVM(ctx, publicState, privateState, ¶ms.ChainConfig{ + ByzantiumBlock: new(big.Int), + }, vm.Config{}) + + ret, _, err := env.Call(vm.AccountRef(author), callerAddress, msg.data, msg.gas, new(big.Int)) + + if err != nil { + t.Fatalf("Call error: %s", err) + } + value := common.Hash{ret[0]} + if value != expectedHash { + t.Errorf("expected %x got %x", expectedHash, value) + } +} + +func TestStaticCall_whenPublicToPublic(t *testing.T) { + db := ethdb.NewMemDatabase() + + publicState, _ := state.New(common.Hash{}, state.NewDatabase(db)) + publicState.SetCode(callerAddress, common.Hex2Bytes(callerContractCode)) + publicState.SetCode(calleeAddress, common.Hex2Bytes(calleeContractCode)) + + verifyStaticCall(t, publicState, publicState, common.Hash{10}) +} + +func TestStaticCall_whenPublicToPrivateInTheParty(t *testing.T) { + db := ethdb.NewMemDatabase() + + privateState, _ := state.New(common.Hash{}, state.NewDatabase(db)) + privateState.SetCode(calleeAddress, common.Hex2Bytes(calleeContractCode)) + + publicState, _ := state.New(common.Hash{}, state.NewDatabase(db)) + publicState.SetCode(callerAddress, common.Hex2Bytes(callerContractCode)) + + verifyStaticCall(t, privateState, publicState, common.Hash{10}) +} + +func TestStaticCall_whenPublicToPrivateNotInTheParty(t *testing.T) { + + db := ethdb.NewMemDatabase() + + privateState, _ := state.New(common.Hash{}, state.NewDatabase(db)) + + publicState, _ := state.New(common.Hash{}, state.NewDatabase(db)) + publicState.SetCode(callerAddress, common.Hex2Bytes(callerContractCode)) + + verifyStaticCall(t, privateState, publicState, common.Hash{0}) +} + +func TestStaticCall_whenPrivateToPublic(t *testing.T) { + db := ethdb.NewMemDatabase() + + privateState, _ := state.New(common.Hash{}, state.NewDatabase(db)) + privateState.SetCode(callerAddress, common.Hex2Bytes(callerContractCode)) + + publicState, _ := state.New(common.Hash{}, state.NewDatabase(db)) + publicState.SetCode(calleeAddress, common.Hex2Bytes(calleeContractCode)) + + verifyStaticCall(t, privateState, publicState, common.Hash{10}) +} diff --git a/core/vm/evm.go b/core/vm/evm.go index 55826102c..74077f604 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -334,6 +334,10 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte if evm.vmConfig.NoRecursion && evm.depth > 0 { return nil, gas, nil } + + evm.Push(getDualState(evm, addr)) + defer func() { evm.Pop() }() + // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { return nil, gas, ErrDepth diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 4b8d80caa..be6b1773d 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -173,7 +173,6 @@ func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err er // Get the operation from the jump table and validate the stack to ensure there are // enough stack items available to perform the operation. - op = contract.GetOp(pc) operation := in.cfg.JumpTable[op] if !operation.valid { return nil, fmt.Errorf("invalid opcode 0x%x", int(op)) From 7803a2f7ef1e518623d92250caf04145d20c0ad3 Mon Sep 17 00:00:00 2001 From: Jitendra Bhurat Date: Fri, 30 Nov 2018 13:42:31 -0500 Subject: [PATCH 26/32] Setting the private state to public state if contract address is not present in the private state --- eth/api_backend.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/eth/api_backend.go b/eth/api_backend.go index 2a601d4b6..67b9fb83b 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -149,7 +149,19 @@ func (b *EthAPIBackend) GetEVM(ctx context.Context, msg core.Message, state vm.M vmError := func() error { return nil } context := core.NewEVMContext(msg, header, b.eth.BlockChain(), nil) - return vm.NewEVM(context, statedb.state, statedb.privateState, b.eth.chainConfig, vmCfg), vmError, nil + + // Set the private state to public state if contract address is not present in the private state + to := common.Address{} + if msg.To() != nil { + to = *msg.To() + } + + privateState := statedb.privateState + if !privateState.Exist(to) { + privateState = statedb.state + } + + return vm.NewEVM(context, statedb.state, privateState, b.eth.chainConfig, vmCfg), vmError, nil } func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription { From 67c9b4332f60be942c9db33c35591cbba351c042 Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Tue, 11 Dec 2018 16:54:18 -0500 Subject: [PATCH 27/32] staticcall does not modify states so no need to push to stack --- core/vm/evm.go | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/core/vm/evm.go b/core/vm/evm.go index 74077f604..6eef7fef8 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -335,9 +335,6 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte return nil, gas, nil } - evm.Push(getDualState(evm, addr)) - defer func() { evm.Pop() }() - // Fail if we're trying to execute above the call depth limit if evm.depth > int(params.CallCreateDepth) { return nil, gas, ErrDepth @@ -352,20 +349,21 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte var ( to = AccountRef(addr) - snapshot = evm.StateDB.Snapshot() + stateDb = getDualState(evm, addr) + snapshot = stateDb.Snapshot() ) // Initialise a new contract and set the code that is to be used by the // EVM. The contract is a scoped environment for this execution context // only. contract := NewContract(caller, to, new(big.Int), gas) - contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) + contract.SetCallCode(&addr, stateDb.GetCodeHash(addr), stateDb.GetCode(addr)) // When an error was returned by the EVM or when setting the creation code // above we revert to the snapshot and consume any gas remaining. Additionally // when we're in Homestead this also counts for code storage gas errors. ret, err = run(evm, contract, input) if err != nil { - evm.StateDB.RevertToSnapshot(snapshot) + stateDb.RevertToSnapshot(snapshot) if err != errExecutionReverted { contract.UseGas(contract.Gas) } From 8f678278aab02529cc56d934606e5b275b94f6cf Mon Sep 17 00:00:00 2001 From: jpmsam Date: Wed, 12 Dec 2018 15:27:29 -0500 Subject: [PATCH 28/32] quorum version update --- params/version.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/params/version.go b/params/version.go index 758810dc7..358e50479 100644 --- a/params/version.go +++ b/params/version.go @@ -27,8 +27,8 @@ const ( VersionMeta = "stable" // Version metadata to append to the version string QuorumVersionMajor = 2 - QuorumVersionMinor = 1 - QuorumVersionPatch = 1 + QuorumVersionMinor = 2 + QuorumVersionPatch = 0 ) // Version holds the textual version string. From bd558eff27de780d5061091f118d18bd69350ed3 Mon Sep 17 00:00:00 2001 From: Felix Shnir Date: Thu, 13 Dec 2018 16:32:48 +0000 Subject: [PATCH 29/32] Cherrypicking go-ethereum#18211 pull --- cmd/utils/flags.go | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 349a3a21a..9a9bf7793 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -820,17 +820,12 @@ func setIPC(ctx *cli.Context, cfg *node.Config) { // makeDatabaseHandles raises out the number of allowed file handles per process // for Geth and returns half of the allowance to assign to the database. func makeDatabaseHandles() int { - limit, err := fdlimit.Current() + limit, err := fdlimit.Maximum() if err != nil { Fatalf("Failed to retrieve file descriptor allowance: %v", err) } - if limit < 2048 { - if err := fdlimit.Raise(2048); err != nil { - Fatalf("Failed to raise file descriptor allowance: %v", err) - } - } - if limit > 2048 { // cap database file descriptors even if more is available - limit = 2048 + if err := fdlimit.Raise(uint64(limit)); err != nil { + Fatalf("Failed to raise file descriptor allowance: %v", err) } return limit / 2 // Leave half for networking and other stuff } From aea11d53a8066fed2a1302394645d1a2a20d1a4e Mon Sep 17 00:00:00 2001 From: Jitendra Bhurat Date: Thu, 13 Dec 2018 12:31:50 -0500 Subject: [PATCH 30/32] calling unlock using defer, preventing deadlock when miner.setEtherbase() returns an error --- eth/backend.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/eth/backend.go b/eth/backend.go index 44ebc6e2d..e401242a2 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -356,12 +356,13 @@ func (s *Ethereum) Etherbase() (eb common.Address, err error) { // set in js console via admin interface or wrapper from cli flags func (s *Ethereum) SetEtherbase(etherbase common.Address) { s.lock.Lock() + defer s.lock.Unlock() if _, ok := s.engine.(consensus.Istanbul); ok { log.Error("Cannot set etherbase in Istanbul consensus") return } s.etherbase = etherbase - s.lock.Unlock() + s.miner.SetEtherbase(etherbase) } From e92052b3a4fc8f72425a6497841077626ad5390a Mon Sep 17 00:00:00 2001 From: namtruong Date: Thu, 3 Jan 2019 15:26:42 +0000 Subject: [PATCH 31/32] return error when sendRawPrivateTransaction is called to submit public transaction (privateFor list empty) --- internal/ethapi/api.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index dc0718d36..7f56c3eee 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1342,6 +1342,8 @@ func (s *PublicTransactionPoolAPI) SendRawPrivateTransaction(ctx context.Context return common.Hash{}, err } } + } else { + return common.Hash{}, fmt.Errorf("transaction is not private") } return submitTransaction(ctx, s.b, tx, isPrivate) From 01a8a5ec807a746b76cd60ffe8b419bb5ba8d4ba Mon Sep 17 00:00:00 2001 From: namtruong Date: Fri, 4 Jan 2019 19:32:17 +0000 Subject: [PATCH 32/32] minor documentation update --- docs/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api.md b/docs/api.md index 143c9a6f3..45f731f64 100644 --- a/docs/api.md +++ b/docs/api.md @@ -60,7 +60,7 @@ __To support sending raw transactions in Quorum, the `web3.eth.sendRawPrivateTra web3.eth.sendRawPrivateTransaction(signedTransactionData [, privateData] [, callback]) ``` -Sends an already signed transaction. For example can be signed using: https://github.com/SilentCicero/ethereumjs-accounts +Sends a pre-signed transaction. For example can be signed using: https://github.com/SilentCicero/ethereumjs-accounts __Important:__ Please note that before calling this API, a `storeraw` api need to be called first to Quorum's private transaction manager. Instructions on how to do this can be found [here](https://github.com/jpmorganchase/tessera/wiki/Interface-&-API).