github.com/baptiste-b-pegasys/quorum/v22@v22.4.2/core/vm/contracts_quorum.go (about)

     1  // Copyright 2014 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 vm
    18  
    19  import (
    20  	"errors"
    21  
    22  	"github.com/ethereum/go-ethereum/common"
    23  	"github.com/ethereum/go-ethereum/core/types"
    24  	"github.com/ethereum/go-ethereum/log"
    25  	"github.com/ethereum/go-ethereum/private"
    26  )
    27  
    28  // QuorumPrecompiledContract is an extended interface for native Quorum Go contracts. The implementation
    29  // requires a deterministic gas count based on the input size of the Run method of the
    30  // contract.
    31  type QuorumPrecompiledContract interface {
    32  	RequiredGas(input []byte) uint64            // RequiredPrice calculates the contract gas use
    33  	Run(evm *EVM, input []byte) ([]byte, error) // Run runs the precompiled contract
    34  }
    35  
    36  // QuorumPrecompiledContracts is the default set of pre-compiled Quorum contracts (with an extended interface).
    37  var QuorumPrecompiledContracts = map[common.Address]QuorumPrecompiledContract{
    38  	common.QuorumPrivacyPrecompileContractAddress(): &privacyMarker{},
    39  }
    40  
    41  // RunQuorumPrecompiledContract runs and evaluates the output of an extended precompiled contract.
    42  // It returns
    43  // - the returned bytes,
    44  // - the _remaining_ gas,
    45  // - any error that occurred
    46  func RunQuorumPrecompiledContract(evm *EVM, p QuorumPrecompiledContract, input []byte, suppliedGas uint64) (ret []byte, remainingGas uint64, err error) {
    47  	gasCost := p.RequiredGas(input)
    48  	if suppliedGas < gasCost {
    49  		return nil, 0, ErrOutOfGas
    50  	}
    51  	suppliedGas -= gasCost
    52  	output, err := p.Run(evm, input)
    53  	return output, suppliedGas, err
    54  }
    55  
    56  type privacyMarker struct{}
    57  
    58  func (c *privacyMarker) RequiredGas(_ []byte) uint64 {
    59  	return uint64(0)
    60  }
    61  
    62  // privacyMarker precompile execution
    63  // Retrieves private transaction from Tessera and executes it.
    64  // If we are not a participant, then just ensure public state remains in sync.
    65  //		input = 20 byte address of sender, 64 byte hash for the private transaction
    66  func (c *privacyMarker) Run(evm *EVM, _ []byte) ([]byte, error) {
    67  	log.Debug("Running privacy marker precompile")
    68  
    69  	// support vanilla ethereum tests where tx is not set
    70  	if evm.currentTx == nil {
    71  		return nil, nil
    72  	}
    73  	logger := log.New("pmtHash", evm.currentTx.Hash())
    74  
    75  	if evm.depth != 0 || !evm.currentTx.IsPrivacyMarker() {
    76  		// only supporting direct precompile calls so far
    77  		logger.Warn("Invalid privacy marker precompile execution")
    78  		return nil, nil
    79  	}
    80  
    81  	if evm.currentTx.IsPrivate() {
    82  		//only public transactions can call the precompile
    83  		logger.Warn("PMT is not a public transaction")
    84  		return nil, nil
    85  	}
    86  
    87  	tx, _, _, err := private.FetchPrivateTransaction(evm.currentTx.Data())
    88  	if err != nil {
    89  		logger.Error("Failed to retrieve inner transaction from private transaction manager", "err", err)
    90  		return nil, nil
    91  	}
    92  
    93  	if tx == nil {
    94  		logger.Debug("Not a participant, skipping execution")
    95  		return nil, nil
    96  	}
    97  
    98  	if !tx.IsPrivate() {
    99  		//should only allow private txns from inside precompile, as many assumptions
   100  		//about how a tx operates are based on its privacy (e.g. which dbs to use, PE checks etc)
   101  		logger.Warn("Inner transaction retrieved from private transaction manager is not a private transaction, skipping execution")
   102  		return nil, nil
   103  	}
   104  	//validate the private tx is signed, and that it's the same signer as the PMT
   105  	signedBy := tx.From()
   106  	if signedBy.Hex() == (common.Address{}).Hex() || signedBy.Hex() != evm.currentTx.From().Hex() {
   107  		logger.Warn("PMT and inner private transaction have different signers, skipping execution")
   108  		return nil, nil
   109  	}
   110  
   111  	// validate the private tx has the same nonce as the PMT
   112  	if tx.Nonce() != evm.currentTx.Nonce() {
   113  		logger.Warn("PMT and inner private transaction have different nonces, skipping execution")
   114  		return nil, nil
   115  	}
   116  
   117  	if err := applyTransactionWithoutIncrementingNonce(evm, tx); err != nil {
   118  		logger.Warn("Unable to apply PMT's inner transaction to EVM, skipping execution", "err", err)
   119  		return nil, nil
   120  	}
   121  	logger.Debug("Inner private transaction applied")
   122  	return nil, nil
   123  }
   124  
   125  // Effectively execute the internal private transaction without incrementing the nonce of the sender account.
   126  // (1)  make a copy of the sender's starting (i.e. current) account nonce.
   127  // (2)  decrement the sender's account nonce in the public state so that the internal private transaction (which has the same 'from' and 'nonce' as the outer PMT) can be executed.
   128  // (3a)  execute the internal private transaction.
   129  // (3b) if the internal private tx is successfully executed then the sender's account nonce will be incremented back to the starting nonce.
   130  // (3c) if the execution was unsuccessful then the nonce may not be incremented.
   131  // (4)  force reset the nonce to the starting value in any case.
   132  func applyTransactionWithoutIncrementingNonce(evm *EVM, tx *types.Transaction) error {
   133  	if evm.InnerApply == nil {
   134  		return errors.New("nil inner apply function")
   135  	}
   136  
   137  	fromAddr := evm.currentTx.From()
   138  
   139  	startingNonce := evm.PublicState().GetNonce(fromAddr)
   140  	evm.publicState.SetNonce(fromAddr, startingNonce-1)
   141  	defer evm.publicState.SetNonce(fromAddr, startingNonce)
   142  
   143  	return evm.InnerApply(tx)
   144  }