quorum/eth/api_backend.go

234 lines
7.0 KiB
Go
Raw Normal View History

// Copyright 2015 The go-ethereum Authors
// This file is part of go-ethereum.
//
// go-ethereum is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// go-ethereum is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
package eth
import (
"math/big"
"fmt"
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/internal/ethapi"
rpc "github.com/ethereum/go-ethereum/rpc"
"golang.org/x/net/context"
)
var raftHasNoPending = fmt.Errorf("Raft mode has no Pending block. Use latest instead.")
// EthApiBackend implements ethapi.Backend for full nodes
type EthApiBackend struct {
eth *Ethereum
}
func (b *EthApiBackend) SetHead(number uint64) {
b.eth.blockchain.SetHead(number)
}
func (b *EthApiBackend) HeaderByNumber(blockNr rpc.BlockNumber) *types.Header {
// Pending block is only known by the miner
if blockNr == rpc.PendingBlockNumber {
block, _, _ := b.eth.blockVoting.Pending()
return block.Header()
}
// Otherwise resolve and return the block
if blockNr == rpc.LatestBlockNumber {
return b.eth.blockchain.CurrentBlock().Header()
}
return b.eth.blockchain.GetHeaderByNumber(uint64(blockNr))
}
func (b *EthApiBackend) BlockByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Block, error) {
// Pending block is only known by the miner
if blockNr == rpc.PendingBlockNumber {
if b.eth.protocolManager.raftMode {
return nil, raftHasNoPending
}
block, _, _ := b.eth.blockVoting.Pending()
return block, nil
}
// Otherwise resolve and return the block
if blockNr == rpc.LatestBlockNumber {
return b.eth.blockchain.CurrentBlock(), nil
}
return b.eth.blockchain.GetBlockByNumber(uint64(blockNr)), nil
}
func (b *EthApiBackend) StateAndHeaderByNumber(blockNr rpc.BlockNumber) (ethapi.State, *types.Header, error) {
// Pending state is only known by the miner
if blockNr == rpc.PendingBlockNumber {
if b.eth.protocolManager.raftMode {
return nil, nil, raftHasNoPending
}
block, publicState, privateState := b.eth.blockVoting.Pending()
return EthApiState{publicState, privateState}, block.Header(), nil
}
// Otherwise resolve the block number and return its state
header := b.HeaderByNumber(blockNr)
if header == nil {
return nil, nil, nil
}
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.
2016-10-31 04:46:40 -07:00
publicState, privateState, err := b.eth.BlockChain().StateAt(header.Root)
return EthApiState{publicState, privateState}, header, err
}
func (b *EthApiBackend) GetBlock(ctx context.Context, blockHash common.Hash) (*types.Block, error) {
return b.eth.blockchain.GetBlockByHash(blockHash), nil
}
func (b *EthApiBackend) GetReceipts(ctx context.Context, blockHash common.Hash) (types.Receipts, error) {
return core.GetBlockReceipts(b.eth.chainDb, blockHash, core.GetBlockNumber(b.eth.chainDb, blockHash)), nil
}
func (b *EthApiBackend) GetTd(blockHash common.Hash) *big.Int {
return b.eth.blockchain.GetTdByHash(blockHash)
}
func (b *EthApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (vm.Environment, func() error, error) {
var (
statedb = state.(EthApiState)
publicState = statedb.publicState
privateState = statedb.privateState
)
if msg.To() != nil && !privateState.Exist(*msg.To()) {
privateState = publicState
}
2016-11-16 15:36:12 -08:00
addr, _ := msg.From()
from := privateState.GetOrNewStateObject(addr)
from.SetBalance(common.MaxBig)
vmError := func() error { return nil }
return core.NewEnv(publicState, privateState, b.eth.chainConfig, b.eth.blockchain, msg, header, b.eth.chainConfig.VmConfig), vmError, nil
}
func (b *EthApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
b.eth.txMu.Lock()
defer b.eth.txMu.Unlock()
b.eth.txPool.SetLocal(signedTx)
return b.eth.txPool.Add(signedTx)
}
func (b *EthApiBackend) RemoveTx(txHash common.Hash) {
b.eth.txMu.Lock()
defer b.eth.txMu.Unlock()
b.eth.txPool.Remove(txHash)
}
func (b *EthApiBackend) GetPoolTransactions() types.Transactions {
b.eth.txMu.Lock()
defer b.eth.txMu.Unlock()
var txs types.Transactions
for _, batch := range b.eth.txPool.Pending() {
txs = append(txs, batch...)
}
return txs
}
func (b *EthApiBackend) GetPoolTransaction(hash common.Hash) *types.Transaction {
b.eth.txMu.Lock()
defer b.eth.txMu.Unlock()
return b.eth.txPool.Get(hash)
}
func (b *EthApiBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) {
b.eth.txMu.Lock()
defer b.eth.txMu.Unlock()
return b.eth.txPool.State().GetNonce(addr), nil
}
func (b *EthApiBackend) Stats() (pending int, queued int) {
b.eth.txMu.Lock()
defer b.eth.txMu.Unlock()
return b.eth.txPool.Stats()
}
func (b *EthApiBackend) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) {
b.eth.txMu.Lock()
defer b.eth.txMu.Unlock()
return b.eth.TxPool().Content()
}
func (b *EthApiBackend) Downloader() *downloader.Downloader {
return b.eth.Downloader()
}
func (b *EthApiBackend) ProtocolVersion() int {
return b.eth.EthVersion()
}
func (b *EthApiBackend) SuggestPrice(ctx context.Context) (*big.Int, error) {
2016-11-07 03:23:49 -08:00
return big.NewInt(0), nil
}
func (b *EthApiBackend) ChainDb() ethdb.Database {
return b.eth.ChainDb()
}
func (b *EthApiBackend) EventMux() *event.TypeMux {
return b.eth.EventMux()
}
func (b *EthApiBackend) AccountManager() *accounts.Manager {
return b.eth.AccountManager()
}
type EthApiState struct {
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.
2016-10-31 04:46:40 -07:00
publicState, privateState *state.StateDB
}
func (s EthApiState) GetBalance(ctx context.Context, addr common.Address) (*big.Int, error) {
if s.publicState.Exist(addr) {
return s.publicState.GetBalance(addr), nil
}
return s.privateState.GetBalance(addr), nil
}
func (s EthApiState) GetCode(ctx context.Context, addr common.Address) ([]byte, error) {
if s.publicState.Exist(addr) {
return s.publicState.GetCode(addr), nil
}
return s.privateState.GetCode(addr), nil
}
func (s EthApiState) GetState(ctx context.Context, a common.Address, b common.Hash) (common.Hash, error) {
if s.publicState.Exist(a) {
return s.publicState.GetState(a, b), nil
}
return s.privateState.GetState(a, b), nil
}
func (s EthApiState) GetNonce(ctx context.Context, addr common.Address) (uint64, error) {
if s.publicState.Exist(addr) {
return s.publicState.GetNonce(addr), nil
}
return s.privateState.GetNonce(addr), nil
}