github.com/Unheilbar/quorum@v1.0.0/core/state_processor.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "errors" 21 "fmt" 22 23 "github.com/ethereum/go-ethereum/common" 24 "github.com/ethereum/go-ethereum/consensus" 25 "github.com/ethereum/go-ethereum/consensus/misc" 26 "github.com/ethereum/go-ethereum/core/mps" 27 "github.com/ethereum/go-ethereum/core/state" 28 "github.com/ethereum/go-ethereum/core/types" 29 "github.com/ethereum/go-ethereum/core/vm" 30 "github.com/ethereum/go-ethereum/crypto" 31 "github.com/ethereum/go-ethereum/log" 32 "github.com/ethereum/go-ethereum/params" 33 "github.com/ethereum/go-ethereum/permission/core" 34 "github.com/ethereum/go-ethereum/private" 35 ) 36 37 // StateProcessor is a basic Processor, which takes care of transitioning 38 // state from one point to another. 39 // 40 // StateProcessor implements Processor. 41 type StateProcessor struct { 42 config *params.ChainConfig // Chain configuration options 43 bc *BlockChain // Canonical block chain 44 engine consensus.Engine // Consensus engine used for block rewards 45 } 46 47 // NewStateProcessor initialises a new StateProcessor. 48 func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consensus.Engine) *StateProcessor { 49 return &StateProcessor{ 50 config: config, 51 bc: bc, 52 engine: engine, 53 } 54 } 55 56 // Process processes the state changes according to the Ethereum rules by running 57 // the transaction messages using the statedb and applying any rewards to both 58 // the processor (coinbase) and any included uncles. 59 // 60 // Process returns the receipts and logs accumulated during the process and 61 // returns the amount of gas that was used in the process. If any of the 62 // transactions failed to execute due to insufficient gas it will return an error. 63 // 64 // Quorum: Private transactions are handled for the following: 65 // 66 // 1. On original single private state (SPS) design 67 // 2. On multiple private states (MPS) design 68 // 3. Contract extension callback (p.bc.CheckAndSetPrivateState) 69 func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, privateStateRepo mps.PrivateStateRepository, cfg vm.Config) (types.Receipts, types.Receipts, []*types.Log, uint64, error) { 70 var ( 71 receipts types.Receipts 72 usedGas = new(uint64) 73 header = block.Header() 74 allLogs []*types.Log 75 gp = new(GasPool).AddGas(block.GasLimit()) 76 77 privateReceipts types.Receipts 78 ) 79 // Mutate the block and state according to any hard-fork specs 80 if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { 81 misc.ApplyDAOHardFork(statedb) 82 } 83 blockContext := NewEVMBlockContext(header, p.bc, nil) 84 // Iterate over and process the individual transactions 85 for i, tx := range block.Transactions() { 86 mpsReceipt, err := handleMPS(i, tx, gp, usedGas, cfg, statedb, privateStateRepo, p.config, p.bc, header, false, false) 87 if err != nil { 88 return nil, nil, nil, 0, err 89 } 90 91 // handling transaction in 2 scenarios: 92 // 1. For MPS, the target private state being applied would be the EmptyPrivateState. 93 // This must be last to avoid contract address collisions. 94 // 2. For orignal SPS design, the target private state is the single private state 95 // 96 // in both cases, privateStateRepo is responsible to return the appropriate 97 // private state for execution and a bool flag to enable the privacy execution 98 privateStateDB, err := privateStateRepo.DefaultState() 99 if err != nil { 100 return nil, nil, nil, 0, err 101 } 102 privateStateDB.Prepare(tx.Hash(), block.Hash(), i) 103 statedb.Prepare(tx.Hash(), block.Hash(), i) 104 105 privateStateDBToUse := PrivateStateDBForTxn(p.config.IsQuorum, tx, statedb, privateStateDB) 106 107 // Quorum - check for account permissions to execute the transaction 108 if core.IsV2Permission() { 109 if err := core.CheckAccountPermission(tx.From(), tx.To(), tx.Value(), tx.Data(), tx.Gas(), tx.GasPrice()); err != nil { 110 return nil, nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) 111 } 112 } 113 114 if p.config.IsQuorum && !p.config.IsGasPriceEnabled(header.Number) && tx.GasPrice() != nil && tx.GasPrice().Cmp(common.Big0) > 0 { 115 return nil, nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), ErrInvalidGasPrice) 116 } 117 118 msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number)) 119 if err != nil { 120 return nil, nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) 121 } 122 123 // Quorum: this tx needs to be applied as if we were not a party 124 msg = msg.WithEmptyPrivateData(privateStateRepo.IsMPS() && tx.IsPrivate()) 125 126 // the same transaction object is used for multiple executions (clear the privacy metadata - it should be updated after privacyManager.receive) 127 // when running in parallel for multiple private states is implemented - a copy of the tx may be used 128 tx.SetTxPrivacyMetadata(nil) 129 130 txContext := NewEVMTxContext(msg) 131 vmenv := vm.NewEVM(blockContext, txContext, statedb, privateStateDBToUse, p.config, cfg) 132 vmenv.SetCurrentTX(tx) 133 receipt, privateReceipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, privateStateDB, header, tx, usedGas, vmenv, cfg, privateStateRepo.IsMPS(), privateStateRepo) 134 if err != nil { 135 return nil, nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) 136 } 137 138 receipts = append(receipts, receipt) 139 allLogs = append(allLogs, receipt.Logs...) 140 141 // if the private receipt is nil this means the tx was public 142 // and we do not need to apply the additional logic. 143 if privateReceipt != nil { 144 newPrivateReceipt, privateLogs := HandlePrivateReceipt(receipt, privateReceipt, mpsReceipt, tx, privateStateDB, privateStateRepo, p.bc) 145 privateReceipts = append(privateReceipts, newPrivateReceipt) 146 allLogs = append(allLogs, privateLogs...) 147 } 148 } 149 // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) 150 p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles()) 151 152 return receipts, privateReceipts, allLogs, *usedGas, nil 153 } 154 155 // Quorum 156 func HandlePrivateReceipt(receipt *types.Receipt, privateReceipt *types.Receipt, mpsReceipt *types.Receipt, tx *types.Transaction, privateStateDB *state.StateDB, privateStateRepo mps.PrivateStateRepository, bc *BlockChain) (*types.Receipt, []*types.Log) { 157 var ( 158 privateLogs []*types.Log 159 ) 160 161 if tx.IsPrivacyMarker() { 162 // This was a public privacy marker transaction, so we need to handle two scenarios: 163 // 1) MPS: privateReceipt is an auxiliary MPS receipt which contains actual private receipts in PSReceipts[] 164 // 2) non-MPS: privateReceipt is the actual receipt for the inner private transaction 165 // In both cases we return a receipt for the public PMT, which holds the private receipt(s) in PSReceipts[], 166 // and we then discard the privateReceipt. 167 if privateStateRepo != nil && privateStateRepo.IsMPS() { 168 receipt.PSReceipts = privateReceipt.PSReceipts 169 privateLogs = append(privateLogs, privateReceipt.Logs...) 170 } else { 171 receipt.PSReceipts = make(map[types.PrivateStateIdentifier]*types.Receipt) 172 receipt.PSReceipts[privateStateRepo.DefaultStateMetadata().ID] = privateReceipt 173 privateLogs = append(privateLogs, privateReceipt.Logs...) 174 bc.CheckAndSetPrivateState(privateReceipt.Logs, privateStateDB, privateStateRepo.DefaultStateMetadata().ID) 175 } 176 177 // There should be no auxiliary receipt from MPS execution, just logging in case this ever occurs 178 if mpsReceipt != nil { 179 log.Error("Unexpected MPS auxiliary receipt, when processing a privacy marker transaction") 180 } 181 return privateReceipt, privateLogs 182 } else { 183 // This was a regular private transaction. 184 privateLogs = append(privateLogs, privateReceipt.Logs...) 185 bc.CheckAndSetPrivateState(privateReceipt.Logs, privateStateDB, privateStateRepo.DefaultStateMetadata().ID) 186 187 // handling the auxiliary receipt from MPS execution 188 if mpsReceipt != nil { 189 privateReceipt.PSReceipts = mpsReceipt.PSReceipts 190 privateLogs = append(privateLogs, mpsReceipt.Logs...) 191 } 192 return privateReceipt, privateLogs 193 } 194 } 195 196 // Quorum 197 // returns the privateStateDB to be used for a transaction 198 func PrivateStateDBForTxn(isQuorum bool, tx *types.Transaction, stateDb, privateStateDB *state.StateDB) *state.StateDB { 199 if isQuorum && (tx.IsPrivate() || tx.IsPrivacyMarker()) { 200 return privateStateDB 201 } 202 return stateDb 203 } 204 205 // Quorum 206 // handling MPS scenario for a private transaction 207 // 208 // handleMPS returns the auxiliary receipt and not the standard receipt 209 func handleMPS(ti int, tx *types.Transaction, gp *GasPool, usedGas *uint64, cfg vm.Config, statedb *state.StateDB, privateStateRepo mps.PrivateStateRepository, config *params.ChainConfig, bc ChainContext, header *types.Header, applyOnPartiesOnly bool, isInnerPrivateTxn bool) (mpsReceipt *types.Receipt, err error) { 210 if tx.IsPrivate() && privateStateRepo != nil && privateStateRepo.IsMPS() { 211 publicStateDBFactory := func() *state.StateDB { 212 db := statedb.Copy() 213 db.Prepare(tx.Hash(), header.Hash(), ti) 214 return db 215 } 216 privateStateDBFactory := func(psi types.PrivateStateIdentifier) (*state.StateDB, error) { 217 db, err := privateStateRepo.StatePSI(psi) 218 if err != nil { 219 return nil, err 220 } 221 db.Prepare(tx.Hash(), header.Hash(), ti) 222 return db, nil 223 } 224 mpsReceipt, err = ApplyTransactionOnMPS(config, bc, nil, gp, publicStateDBFactory, privateStateDBFactory, header, tx, usedGas, cfg, privateStateRepo, applyOnPartiesOnly, isInnerPrivateTxn) 225 } 226 return 227 } 228 229 // Quorum 230 // ApplyTransactionOnMPS runs the transaction on multiple private states which 231 // the transaction is designated to. 232 // 233 // For each designated private state, the transaction is ran only ONCE. 234 // 235 // ApplyTransactionOnMPS returns the auxiliary receipt which is mainly used to capture 236 // multiple private receipts and logs array. Logs are decorated with types.PrivateStateIdentifier 237 // 238 // The originalGP gas pool will not be modified 239 func ApplyTransactionOnMPS(config *params.ChainConfig, bc ChainContext, author *common.Address, originalGP *GasPool, 240 publicStateDBFactory func() *state.StateDB, privateStateDBFactory func(psi types.PrivateStateIdentifier) (*state.StateDB, error), 241 header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config, privateStateRepo mps.PrivateStateRepository, 242 applyOnPartiesOnly bool, isInnerPrivateTxn bool) (*types.Receipt, error) { 243 mpsReceipt := &types.Receipt{ 244 QuorumReceiptExtraData: types.QuorumReceiptExtraData{ 245 PSReceipts: make(map[types.PrivateStateIdentifier]*types.Receipt), 246 }, 247 Logs: make([]*types.Log, 0), 248 } 249 _, managedParties, _, _, err := private.P.Receive(common.BytesToEncryptedPayloadHash(tx.Data())) 250 if err != nil { 251 return nil, err 252 } 253 targetPsi := make(map[types.PrivateStateIdentifier]struct{}) 254 for _, managedParty := range managedParties { 255 psMetadata, err := bc.PrivateStateManager().ResolveForManagedParty(managedParty) 256 if err != nil { 257 return nil, err 258 } 259 targetPsi[psMetadata.ID] = struct{}{} 260 } 261 // execute in all the managed private states 262 // TODO this could be enhanced to run in parallel 263 for _, psi := range bc.PrivateStateManager().PSIs() { 264 if cfg.ApplyOnPartyOverride != nil && *cfg.ApplyOnPartyOverride != psi { 265 continue 266 } 267 _, applyAsParty := targetPsi[psi] 268 if !applyAsParty && applyOnPartiesOnly { 269 continue 270 } 271 privateStateDB, err := privateStateDBFactory(psi) 272 if err != nil { 273 return nil, err 274 } 275 publicStateDB := publicStateDBFactory() 276 277 // use a clone of the gas pool (as we don't want to consume gas multiple times for each MPS execution, which might blow the block gasLimit on MPS node) 278 gp := new(GasPool).AddGas(originalGP.Gas()) 279 280 _, privateReceipt, err := ApplyTransaction(config, bc, author, gp, publicStateDB, privateStateDB, header, tx, usedGas, cfg, !applyAsParty, privateStateRepo, isInnerPrivateTxn) 281 if err != nil { 282 return nil, err 283 } 284 285 // set the PSI for each log (so that the filter system knows for what private state they are) 286 // we don't care about the empty privateReceipt (as we'll execute the transaction on the empty state anyway) 287 if applyAsParty { 288 for _, log := range privateReceipt.Logs { 289 log.PSI = psi 290 mpsReceipt.Logs = append(mpsReceipt.Logs, log) 291 } 292 mpsReceipt.PSReceipts[psi] = privateReceipt 293 294 bc.CheckAndSetPrivateState(privateReceipt.Logs, privateStateDB, psi) 295 } 296 } 297 298 return mpsReceipt, nil 299 } 300 301 // /Quorum 302 303 func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb, privateStateDB *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, evm *vm.EVM, cfg vm.Config, forceNonParty bool, privateStateRepo mps.PrivateStateRepository) (*types.Receipt, *types.Receipt, error) { 304 // Create a new context to be used in the EVM environment. 305 306 // Quorum 307 txIndex := statedb.TxIndex() 308 evm.InnerApply = func(innerTx *types.Transaction) error { 309 return ApplyInnerTransaction(bc, author, gp, statedb, privateStateDB, header, tx, usedGas, cfg, forceNonParty, privateStateRepo, evm, innerTx, txIndex) 310 } 311 // End Quorum 312 313 // Apply the transaction to the current state (included in the env) 314 result, err := ApplyMessage(evm, msg, gp) 315 if err != nil { 316 return nil, nil, err 317 } 318 319 // Update the state with pending changes. 320 var root []byte 321 if config.IsByzantium(header.Number) { 322 statedb.Finalise(true) 323 } else { 324 root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes() 325 } 326 *usedGas += result.UsedGas 327 328 // Create a new receipt for the transaction, storing the intermediate root and gas used 329 // by the tx. 330 receipt := &types.Receipt{Type: tx.Type(), PostState: common.CopyBytes(root), CumulativeGasUsed: *usedGas} 331 332 // If this is a private transaction, the public receipt should always 333 // indicate success. 334 if !(config.IsQuorum && tx.IsPrivate()) && result.Failed() { 335 receipt.Status = types.ReceiptStatusFailed 336 } else { 337 receipt.Status = types.ReceiptStatusSuccessful 338 } 339 receipt.TxHash = tx.Hash() 340 receipt.GasUsed = result.UsedGas 341 342 // If the transaction created a contract, store the creation address in the receipt. 343 if msg.To() == nil { 344 receipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce()) 345 } 346 347 // Set the receipt logs and create the bloom filter. 348 receipt.Logs = statedb.GetLogs(tx.Hash()) 349 receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) 350 receipt.BlockHash = statedb.BlockHash() 351 receipt.BlockNumber = header.Number 352 receipt.TransactionIndex = uint(statedb.TxIndex()) 353 // Quorum 354 var privateReceipt *types.Receipt 355 if config.IsQuorum { 356 if tx.IsPrivate() { 357 var privateRoot []byte 358 if config.IsByzantium(header.Number) { 359 privateStateDB.Finalise(true) 360 } else { 361 privateRoot = privateStateDB.IntermediateRoot(config.IsEIP158(header.Number)).Bytes() 362 } 363 privateReceipt = types.NewReceipt(privateRoot, result.Failed(), *usedGas) 364 privateReceipt.TxHash = tx.Hash() 365 privateReceipt.GasUsed = result.UsedGas 366 if msg.To() == nil { 367 privateReceipt.ContractAddress = crypto.CreateAddress(evm.TxContext.Origin, tx.Nonce()) 368 } 369 370 privateReceipt.Logs = privateStateDB.GetLogs(tx.Hash()) 371 privateReceipt.Bloom = types.CreateBloom(types.Receipts{privateReceipt}) 372 } else { 373 // This may have been a privacy marker transaction, in which case need to retrieve the receipt for the 374 // inner private transaction (note that this can be an mpsReceipt, containing private receipts in PSReceipts). 375 if evm.InnerPrivateReceipt != nil { 376 privateReceipt = evm.InnerPrivateReceipt 377 } 378 } 379 } 380 381 // Save revert reason if feature enabled 382 if bc != nil && bc.QuorumConfig().RevertReasonEnabled() { 383 revertReason := result.Revert() 384 if revertReason != nil { 385 if config.IsQuorum && tx.IsPrivate() { 386 privateReceipt.RevertReason = revertReason 387 } else { 388 receipt.RevertReason = revertReason 389 } 390 } 391 } 392 // End Quorum 393 394 return receipt, privateReceipt, err 395 } 396 397 // ApplyTransaction attempts to apply a transaction to the given state database 398 // and uses the input parameters for its environment. It returns the receipt 399 // for the transaction, gas used and an error if the transaction failed, 400 // indicating the block was invalid. 401 func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb, privateStateDB *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config, forceNonParty bool, privateStateRepo mps.PrivateStateRepository, isInnerPrivateTxn bool) (*types.Receipt, *types.Receipt, error) { 402 // Quorum - decide the privateStateDB to use 403 privateStateDbToUse := PrivateStateDBForTxn(config.IsQuorum, tx, statedb, privateStateDB) 404 // End Quorum 405 406 // Quorum - check for account permissions to execute the transaction 407 if core.IsV2Permission() { 408 if err := core.CheckAccountPermission(tx.From(), tx.To(), tx.Value(), tx.Data(), tx.Gas(), tx.GasPrice()); err != nil { 409 return nil, nil, err 410 } 411 } 412 413 if config.IsQuorum && !config.IsGasPriceEnabled(header.Number) && tx.GasPrice() != nil && tx.GasPrice().Cmp(common.Big0) > 0 { 414 return nil, nil, ErrInvalidGasPrice 415 } 416 417 msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) 418 if err != nil { 419 return nil, nil, err 420 } 421 // Quorum: this tx needs to be applied as if we were not a party 422 msg = msg.WithEmptyPrivateData(forceNonParty && tx.IsPrivate()) 423 // Quorum: if this is the inner private txn of a PMT then need to indicate this 424 msg = msg.WithInnerPrivateFlag(isInnerPrivateTxn) 425 426 // Create a new context to be used in the EVM environment 427 blockContext := NewEVMBlockContext(header, bc, author) 428 txContext := NewEVMTxContext(msg) 429 vmenv := vm.NewEVM(blockContext, txContext, statedb, privateStateDbToUse, config, cfg) 430 431 // the same transaction object is used for multiple executions (clear the privacy metadata - it should be updated after privacyManager.receive) 432 // when running in parallel for multiple private states is implemented - a copy of the tx may be used 433 tx.SetTxPrivacyMetadata(nil) 434 vmenv.SetCurrentTX(tx) 435 436 return applyTransaction(msg, config, bc, author, gp, statedb, privateStateDB, header, tx, usedGas, vmenv, cfg, forceNonParty, privateStateRepo) 437 } 438 439 // Quorum 440 441 // ApplyInnerTransaction is called from within the Quorum precompile for privacy marker transactions. 442 // It's a call back which essentially duplicates the logic in Process(), 443 // in this case to process the actual private transaction. 444 func ApplyInnerTransaction(bc ChainContext, author *common.Address, gp *GasPool, stateDB *state.StateDB, privateStateDB *state.StateDB, header *types.Header, outerTx *types.Transaction, usedGas *uint64, evmConf vm.Config, forceNonParty bool, privateStateRepo mps.PrivateStateRepository, vmenv *vm.EVM, innerTx *types.Transaction, txIndex int) error { 445 // this should never happen, but added as sanity check 446 if !innerTx.IsPrivate() { 447 return errors.New("attempt to process non-private transaction from within ApplyInnerTransaction()") 448 } 449 450 // create a single use gas pool (as we don't want the gas consumed by the inner tx to blow the block gasLimit on a participant node) 451 singleUseGasPool := new(GasPool).AddGas(innerTx.Gas()) 452 453 if privateStateRepo != nil && privateStateRepo.IsMPS() { 454 mpsReceipt, err := handleMPS(txIndex, innerTx, singleUseGasPool, usedGas, evmConf, stateDB, privateStateRepo, bc.Config(), bc, header, true, true) 455 if err != nil { 456 return err 457 } 458 459 // Store the auxiliary MPS receipt for the inner private transaction (this contains private receipts in PSReceipts). 460 vmenv.InnerPrivateReceipt = mpsReceipt 461 return nil 462 } 463 464 defer prepareStates(outerTx, stateDB, privateStateDB, txIndex) 465 prepareStates(innerTx, stateDB, privateStateDB, txIndex) 466 467 used := uint64(0) 468 _, innerPrivateReceipt, err := ApplyTransaction(bc.Config(), bc, author, singleUseGasPool, stateDB, privateStateDB, header, innerTx, &used, evmConf, forceNonParty, privateStateRepo, true) 469 if err != nil { 470 return err 471 } 472 473 if innerPrivateReceipt != nil { 474 if innerPrivateReceipt.Logs == nil { 475 innerPrivateReceipt.Logs = make([]*types.Log, 0) 476 } 477 478 // Store the receipt for the inner private transaction. 479 innerPrivateReceipt.TxHash = innerTx.Hash() 480 vmenv.InnerPrivateReceipt = innerPrivateReceipt 481 } 482 483 return nil 484 } 485 486 // Quorum 487 func prepareStates(tx *types.Transaction, stateDB *state.StateDB, privateStateDB *state.StateDB, txIndex int) { 488 stateDB.Prepare(tx.Hash(), stateDB.BlockHash(), txIndex) 489 privateStateDB.Prepare(tx.Hash(), privateStateDB.BlockHash(), txIndex) 490 }