Skip to content

Commit 8c47c29

Browse files
authored
Merge pull request #60 from obscuren/quorum-private-logs
core, eth: support private state log and bloom filtering
2 parents e6282c2 + 9d5d5dd commit 8c47c29

File tree

11 files changed

+102
-98
lines changed

11 files changed

+102
-98
lines changed

core/blockchain.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -931,13 +931,14 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
931931
return i, err
932932
}
933933
// Process block using the parent state as reference point.
934-
receipts, logs, usedGas, err := self.processor.Process(block, self.publicStateCache, self.privateStateCache, self.config.VmConfig)
934+
publicReceipts, privateReceipts, logs, usedGas, err := self.processor.Process(block, self.publicStateCache, self.privateStateCache, self.config.VmConfig)
935935
if err != nil {
936936
reportBlock(block, err)
937937
return i, err
938938
}
939+
939940
// Validate the state using the default validator
940-
err = self.Validator().ValidateState(block, self.GetBlock(block.ParentHash(), block.NumberU64()-1), self.publicStateCache, receipts, usedGas)
941+
err = self.Validator().ValidateState(block, self.GetBlock(block.ParentHash(), block.NumberU64()-1), self.publicStateCache, publicReceipts, usedGas)
941942
if err != nil {
942943
reportBlock(block, err)
943944
return i, err
@@ -960,7 +961,8 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
960961
// coalesce logs for later processing
961962
coalescedLogs = append(coalescedLogs, logs...)
962963

963-
if err := WriteBlockReceipts(self.chainDb, block.Hash(), block.NumberU64(), receipts); err != nil {
964+
allReceipts := append(publicReceipts, privateReceipts...)
965+
if err := WriteBlockReceipts(self.chainDb, block.Hash(), block.NumberU64(), allReceipts); err != nil {
964966
return i, err
965967
}
966968

@@ -983,11 +985,15 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
983985
return i, err
984986
}
985987
// store the receipts
986-
if err := WriteReceipts(self.chainDb, receipts); err != nil {
988+
if err := WriteReceipts(self.chainDb, allReceipts); err != nil {
987989
return i, err
988990
}
989991
// Write map map bloom filters
990-
if err := WriteMipmapBloom(self.chainDb, block.NumberU64(), receipts); err != nil {
992+
if err := WriteMipmapBloom(self.chainDb, block.NumberU64(), allReceipts); err != nil {
993+
return i, err
994+
}
995+
// Write private block bloom
996+
if err := WritePrivateBlockBloom(self.chainDb, block.NumberU64(), privateReceipts); err != nil {
991997
return i, err
992998
}
993999
case SideStatTy:

core/blockchain_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
140140
if err != nil {
141141
return err
142142
}
143-
receipts, _, usedGas, err := blockchain.Processor().Process(block, statedb, statedb, vm.Config{})
143+
receipts, _, _, usedGas, err := blockchain.Processor().Process(block, statedb, statedb, vm.Config{})
144144
if err != nil {
145145
reportBlock(block, err)
146146
return err
@@ -434,8 +434,8 @@ func (bproc) ValidateHeader(ethdb.Database, *types.Header, *types.Header) error
434434
func (bproc) ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error {
435435
return nil
436436
}
437-
func (bproc) Process(block *types.Block, statedb, state2 *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error) {
438-
return nil, nil, new(big.Int), nil
437+
func (bproc) Process(block *types.Block, statedb, state2 *state.StateDB, cfg vm.Config) (types.Receipts, types.Receipts, vm.Logs, *big.Int, error) {
438+
return nil, nil, nil, new(big.Int), nil
439439
}
440440

441441
func makeHeaderChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Header {

core/call_helper.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ func (cg *callHelper) MakeCall(private bool, key *ecdsa.PrivateKey, to common.Ad
5757
if !private {
5858
privateState = publicState
5959
}
60+
61+
cg.header.Number = new(big.Int)
6062
_, _, err = ApplyMessage(NewEnv(publicState, privateState, &ChainConfig{}, nil, ptx.Transaction, &cg.header, vm.Config{}), ptx, cg.gp)
6163
if err != nil {
6264
return err

core/database_util.go

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,16 @@ var (
3636
headBlockKey = []byte("LastBlock")
3737
headFastKey = []byte("LastFast")
3838

39-
headerPrefix = []byte("h") // headerPrefix + num (uint64 big endian) + hash -> header
40-
tdSuffix = []byte("t") // headerPrefix + num (uint64 big endian) + hash + tdSuffix -> td
41-
numSuffix = []byte("n") // headerPrefix + num (uint64 big endian) + numSuffix -> hash
42-
blockHashPrefix = []byte("H") // blockHashPrefix + hash -> num (uint64 big endian)
43-
bodyPrefix = []byte("b") // bodyPrefix + num (uint64 big endian) + hash -> block body
44-
blockReceiptsPrefix = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts
45-
privateRootPrefix = []byte("P") // rootPrefix + block public root -> hash
39+
headerPrefix = []byte("h") // headerPrefix + num (uint64 big endian) + hash -> header
40+
tdSuffix = []byte("t") // headerPrefix + num (uint64 big endian) + hash + tdSuffix -> td
41+
numSuffix = []byte("n") // headerPrefix + num (uint64 big endian) + numSuffix -> hash
42+
blockHashPrefix = []byte("H") // blockHashPrefix + hash -> num (uint64 big endian)
43+
bodyPrefix = []byte("b") // bodyPrefix + num (uint64 big endian) + hash -> block body
44+
blockReceiptsPrefix = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts
45+
privateRootPrefix = []byte("P") // rootPrefix + block public root -> hash
46+
privateblockReceiptsPrefix = []byte("Pr") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts
47+
privateReceiptPrefix = []byte("Prs")
48+
privateBloomPrefix = []byte("Pb")
4649

4750
txMetaSuffix = []byte{0x01}
4851
receiptsPrefix = []byte("receipts-")
@@ -62,6 +65,22 @@ var (
6265
oldBlockHashPrefix = []byte("block-hash-") // [deprecated by the header/block split, remove eventually]
6366
)
6467

68+
// WritePrivateBlockBloom creates a bloom filter for the given receipts and saves it to the database
69+
// with the number given as identifier (i.e. block number).
70+
func WritePrivateBlockBloom(db ethdb.Database, number uint64, receipts types.Receipts) error {
71+
rbloom := types.CreateBloom(receipts)
72+
return db.Put(append(privateBloomPrefix, encodeBlockNumber(number)...), rbloom[:])
73+
}
74+
75+
// GetPrivateBlockBloom retrieves the private bloom associated with the given number.
76+
func GetPrivateBlockBloom(db ethdb.Database, number uint64) (bloom types.Bloom) {
77+
data, _ := db.Get(append(privateBloomPrefix, encodeBlockNumber(number)...))
78+
if len(data) > 0 {
79+
bloom = types.BytesToBloom(data)
80+
}
81+
return bloom
82+
}
83+
6584
// encodeBlockNumber encodes a block number as big endian uint64
6685
func encodeBlockNumber(number uint64) []byte {
6786
enc := make([]byte, 8)
@@ -396,6 +415,7 @@ func WriteBlockReceipts(db ethdb.Database, hash common.Hash, number uint64, rece
396415
if err != nil {
397416
return err
398417
}
418+
399419
// Store the flattened receipt slice
400420
key := append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
401421
if err := db.Put(key, bytes); err != nil {

core/private_state_test.go

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,9 @@ func TestPrivateTransaction(t *testing.T) {
5353

5454
prvContractAddr := common.Address{1}
5555
pubContractAddr := common.Address{2}
56-
/* gllc
57-
asm {
58-
PUSH1 10
59-
PUSH1 0
60-
SSTORE
61-
}
62-
*/
63-
privateState.SetCode(prvContractAddr, common.Hex2Bytes("600a60005500"))
56+
privateState.SetCode(prvContractAddr, common.Hex2Bytes("600a600055600060006001a1"))
6457
privateState.SetState(prvContractAddr, common.Hash{}, common.Hash{9})
65-
publicState.SetCode(pubContractAddr, common.Hex2Bytes("601460005500"))
58+
publicState.SetCode(pubContractAddr, common.Hex2Bytes("6014600055"))
6659
publicState.SetState(pubContractAddr, common.Hash{}, common.Hash{19})
6760

6861
// Private transaction 1
@@ -74,6 +67,9 @@ func TestPrivateTransaction(t *testing.T) {
7467
if stateEntry.Cmp(big.NewInt(10)) != 0 {
7568
t.Error("expected state to have 10, got", stateEntry)
7669
}
70+
if len(privateState.Logs()) != 1 {
71+
t.Error("expected private state to have 1 log, got", len(privateState.Logs()))
72+
}
7773

7874
// Public transaction 1
7975
err = helper.MakeCall(false, key, pubContractAddr, nil)

core/quorum/block_maker.go

100755100644
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,17 @@ func (ps *pendingState) applyTransaction(tx *types.Transaction, bc *core.BlockCh
4747
}
4848
config.ForceJit = false // disable forcing jit
4949

50-
receipt, logs, _, err := core.ApplyTransaction(cc, bc, ps.gp, ps.publicState, ps.privateState, ps.header, tx, ps.header.GasUsed, config)
50+
publicReceipt, _, _, err := core.ApplyTransaction(cc, bc, ps.gp, ps.publicState, ps.privateState, ps.header, tx, ps.header.GasUsed, config)
5151
if err != nil {
5252
ps.publicState.RevertToSnapshot(publicSnaphot)
5353
ps.privateState.RevertToSnapshot(privateSnapshot)
5454

5555
return err, nil
5656
}
5757
ps.txs = append(ps.txs, tx)
58-
ps.receipts = append(ps.receipts, receipt)
58+
ps.receipts = append(ps.receipts, publicReceipt)
5959

60-
return nil, logs
60+
return nil, publicReceipt.Logs
6161
}
6262

6363
func (ps *pendingState) applyTransactions(txs *types.TransactionsByPriorityAndNonce, mux *event.TypeMux, bc *core.BlockChain, cc *core.ChainConfig) (types.Transactions, types.Transactions) {

core/state_processor.go

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -55,36 +55,46 @@ func NewStateProcessor(config *ChainConfig, bc *BlockChain) *StateProcessor {
5555
// Process returns the receipts and logs accumulated during the process and
5656
// returns the amount of gas that was used in the process. If any of the
5757
// transactions failed to execute due to insufficient gas it will return an error.
58-
func (p *StateProcessor) Process(block *types.Block, publicState, privateState *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error) {
58+
func (p *StateProcessor) Process(block *types.Block, publicState, privateState *state.StateDB, cfg vm.Config) (types.Receipts, types.Receipts, vm.Logs, *big.Int, error) {
5959
var (
60-
receipts types.Receipts
61-
totalUsedGas = big.NewInt(0)
62-
err error
63-
header = block.Header()
64-
allLogs vm.Logs
65-
gp = new(GasPool).AddGas(block.GasLimit())
60+
publicReceipts types.Receipts
61+
privateReceipts types.Receipts
62+
totalUsedGas = big.NewInt(0)
63+
err error
64+
header = block.Header()
65+
allLogs vm.Logs
66+
gp = new(GasPool).AddGas(block.GasLimit())
6667
)
6768

6869
for i, tx := range block.Transactions() {
6970
publicState.StartRecord(tx.Hash(), block.Hash(), i)
70-
receipt, logs, _, err := ApplyTransaction(p.config, p.bc, gp, publicState, privateState, header, tx, totalUsedGas, cfg)
71+
privateState.StartRecord(tx.Hash(), block.Hash(), i)
72+
73+
publicReceipt, privateReceipt, _, err := ApplyTransaction(p.config, p.bc, gp, publicState, privateState, header, tx, totalUsedGas, cfg)
7174
if err != nil {
72-
return nil, nil, totalUsedGas, err
75+
return nil, nil, nil, totalUsedGas, err
76+
}
77+
publicReceipts = append(publicReceipts, publicReceipt)
78+
allLogs = append(allLogs, publicReceipt.Logs...)
79+
80+
// if the private receipt is nil this means the tx was public
81+
// and we do not need to apply the additional logic.
82+
if privateReceipt != nil {
83+
privateReceipts = append(privateReceipts, privateReceipt)
84+
allLogs = append(allLogs, privateReceipt.Logs...)
7385
}
74-
receipts = append(receipts, receipt)
75-
allLogs = append(allLogs, logs...)
7686
}
7787
AccumulateRewards(publicState, header, block.Uncles())
7888

79-
return receipts, allLogs, totalUsedGas, err
89+
return publicReceipts, privateReceipts, allLogs, totalUsedGas, err
8090
}
8191

8292
// ApplyTransaction attempts to apply a transaction to the given state database
8393
// and uses the input parameters for its environment.
8494
//
8595
// ApplyTransactions returns the generated receipts and vm logs during the
8696
// execution of the state transition phase.
87-
func ApplyTransaction(config *ChainConfig, bc *BlockChain, gp *GasPool, publicState, privateState *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, vm.Logs, *big.Int, error) {
97+
func ApplyTransaction(config *ChainConfig, bc *BlockChain, gp *GasPool, publicState, privateState *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, *types.Receipt, *big.Int, error) {
8898
if !tx.IsPrivate() {
8999
privateState = publicState
90100
}
@@ -100,19 +110,34 @@ func ApplyTransaction(config *ChainConfig, bc *BlockChain, gp *GasPool, publicSt
100110

101111
// Update the state with pending changes
102112
usedGas.Add(usedGas, gas)
103-
receipt := types.NewReceipt(publicState.IntermediateRoot().Bytes(), usedGas)
104-
receipt.TxHash = tx.Hash()
105-
receipt.GasUsed = new(big.Int).Set(gas)
113+
publicReceipt := types.NewReceipt(publicState.IntermediateRoot().Bytes(), usedGas)
114+
publicReceipt.TxHash = tx.Hash()
115+
publicReceipt.GasUsed = new(big.Int).Set(gas)
106116
if MessageCreatesContract(tx) {
107117
from, _ := tx.From()
108-
receipt.ContractAddress = crypto.CreateAddress(from, tx.Nonce())
118+
publicReceipt.ContractAddress = crypto.CreateAddress(from, tx.Nonce())
109119
}
110120

111121
logs := publicState.GetLogs(tx.Hash())
112-
receipt.Logs = logs
113-
receipt.Bloom = types.CreateBloom(types.Receipts{receipt})
122+
publicReceipt.Logs = logs
123+
publicReceipt.Bloom = types.CreateBloom(types.Receipts{publicReceipt})
124+
125+
var privateReceipt *types.Receipt
126+
if tx.IsPrivate() {
127+
privateReceipt = types.NewReceipt(privateState.IntermediateRoot().Bytes(), usedGas)
128+
privateReceipt.TxHash = tx.Hash()
129+
privateReceipt.GasUsed = new(big.Int).Set(gas)
130+
if MessageCreatesContract(tx) {
131+
from, _ := tx.From()
132+
privateReceipt.ContractAddress = crypto.CreateAddress(from, tx.Nonce())
133+
}
134+
135+
logs := privateState.GetLogs(tx.Hash())
136+
privateReceipt.Logs = logs
137+
privateReceipt.Bloom = types.CreateBloom(types.Receipts{privateReceipt})
138+
}
114139

115-
return receipt, logs, gas, err
140+
return publicReceipt, privateReceipt, gas, err
116141
}
117142

118143
// AccumulateRewards credits the coinbase of the given block with the

core/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ type HeaderValidator interface {
6161
// of gas used in the process and return an error if any of the internal rules
6262
// failed.
6363
type Processor interface {
64-
Process(block *types.Block, publicState, privateState *state.StateDB, cfg vm.Config) (types.Receipts, vm.Logs, *big.Int, error)
64+
Process(block *types.Block, publicState, privateState *state.StateDB, cfg vm.Config) (types.Receipts, types.Receipts, vm.Logs, *big.Int, error)
6565
}
6666

6767
// Finiliser is an interface which finilises blocks.

core/vm/vm.go

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -77,40 +77,6 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
7777
if codehash == (common.Hash{}) {
7878
codehash = crypto.Keccak256Hash(contract.Code)
7979
}
80-
var program *Program
81-
if false {
82-
// JIT disabled due to JIT not being Homestead gas reprice ready.
83-
84-
// If the JIT is enabled check the status of the JIT program,
85-
// if it doesn't exist compile a new program in a separate
86-
// goroutine or wait for compilation to finish if the JIT is
87-
// forced.
88-
switch GetProgramStatus(codehash) {
89-
case progReady:
90-
return RunProgram(GetProgram(codehash), evm.env, contract, input)
91-
case progUnknown:
92-
if evm.cfg.ForceJit {
93-
// Create and compile program
94-
program = NewProgram(contract.Code)
95-
perr := CompileProgram(program)
96-
if perr == nil {
97-
return RunProgram(program, evm.env, contract, input)
98-
}
99-
glog.V(logger.Info).Infoln("error compiling program", err)
100-
} else {
101-
// create and compile the program. Compilation
102-
// is done in a separate goroutine
103-
program = NewProgram(contract.Code)
104-
go func() {
105-
err := CompileProgram(program)
106-
if err != nil {
107-
glog.V(logger.Info).Infoln("error compiling program", err)
108-
return
109-
}
110-
}()
111-
}
112-
}
113-
}
11480

11581
var (
11682
caller = contract.caller
@@ -159,17 +125,6 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
159125
}
160126

161127
for ; ; instrCount++ {
162-
/*
163-
if EnableJit && it%100 == 0 {
164-
if program != nil && progStatus(atomic.LoadInt32(&program.status)) == progReady {
165-
// move execution
166-
fmt.Println("moved", it)
167-
glog.V(logger.Info).Infoln("Moved execution to JIT")
168-
return runProgram(program, pc, mem, stack, evm.env, contract, input)
169-
}
170-
}
171-
*/
172-
173128
// Get the memory location of pc
174129
op = contract.GetOp(pc)
175130
if evm.env.ReadOnly() && op.isMutating() {

eth/api.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,7 @@ func (api *PrivateDebugAPI) traceBlock(block *types.Block, logConfig *vm.LogConf
312312
return false, structLogger.StructLogs(), err
313313
}
314314

315-
receipts, _, usedGas, err := processor.Process(block, publicStateDb, privateStateDb, config)
315+
receipts, _, _, usedGas, err := processor.Process(block, publicStateDb, privateStateDb, config)
316316
if err != nil {
317317
return false, structLogger.StructLogs(), err
318318
}

0 commit comments

Comments
 (0)