Skip to content

Commit

Permalink
Revert "Enable smart contract calling from LES (ethereum#207)" (ether…
Browse files Browse the repository at this point in the history
…eum#239)

This reverts commit 348e076.
  • Loading branch information
jarmg authored Jun 4, 2019
1 parent 348e076 commit dfc9eef
Show file tree
Hide file tree
Showing 19 changed files with 160 additions and 315 deletions.
9 changes: 0 additions & 9 deletions consensus/istanbul/backend/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,10 +428,6 @@ func (sb *Backend) IsLastBlockOfEpoch(header *types.Header) bool {
// consensus rules that happen at finalization (e.g. block rewards).
func (sb *Backend) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction,
uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {

// Calculate a new gas price suggestion and push it to the GasPriceOracle SmartContract
sb.updateGasPriceSuggestion(state)

// No block rewards in Istanbul, so the state remains as is and uncles are dropped
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
header.UncleHash = nilUncleHash
Expand All @@ -440,11 +436,6 @@ func (sb *Backend) Finalize(chain consensus.ChainReader, header *types.Header, s
return types.NewBlock(header, txs, nil, receipts), nil
}

// TODO (jarmg 5/23/18): Implement this
func (sb *Backend) updateGasPriceSuggestion(state *state.StateDB) *state.StateDB {
return (state)
}

// Seal generates a new block for the given input block with the local miner's
// seal place on top.
func (sb *Backend) Seal(chain consensus.ChainReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error {
Expand Down
116 changes: 39 additions & 77 deletions core/currency.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,66 +109,33 @@ type exchangeRate struct {
Denominator *big.Int
}

type CurrencyOperator struct {
gcWl *GasCurrencyWhitelist // Object to retrieve the set of currencies that will have their exchange rate monitored
exchangeRates map[common.Address]*exchangeRate // indexedCurrency:CeloGold exchange rate
regAdd *RegisteredAddresses
iEvmH *InternalEVMHandler
currencyOperatorMu sync.RWMutex
type PriceComparator struct {
gcWl *GasCurrencyWhitelist // Object to retrieve the set of currencies that will have their exchange rate monitored
exchangeRates map[common.Address]*exchangeRate // indexedCurrency:CeloGold exchange rate
regAdd *RegisteredAddresses
iEvmH *InternalEVMHandler
}

func (co *CurrencyOperator) getExchangeRate(currency *common.Address) (*exchangeRate, error) {
// Returns the price of gold in the provided currency.
func (pc *PriceComparator) getExchangeRate(currency *common.Address) (*big.Int, *big.Int, error) {
if currency == nil {
return &exchangeRate{cgExchangeRateNum, cgExchangeRateDen}, nil
return cgExchangeRateNum, cgExchangeRateDen, nil
} else {
co.currencyOperatorMu.RLock()
defer co.currencyOperatorMu.RUnlock()
if exchangeRate, ok := co.exchangeRates[*currency]; !ok {
return nil, errExchangeRateCacheMiss
if exchangeRate, ok := pc.exchangeRates[*currency]; !ok {
return nil, nil, errExchangeRateCacheMiss
} else {
return exchangeRate, nil
return exchangeRate.Numerator, exchangeRate.Denominator, nil
}
}
}

func (co *CurrencyOperator) ConvertToGold(val *big.Int, currencyFrom *common.Address) (*big.Int, error) {
celoGoldAddress := co.regAdd.GetRegisteredAddress(params.GoldTokenRegistryId)
if currencyFrom == nil || currencyFrom == celoGoldAddress {
return val, nil
}
return co.Convert(val, currencyFrom, celoGoldAddress)
}

// NOTE (jarmg 4/24/18): values are rounded down which can cause
// an estimate to be off by 1 (at most)
func (co *CurrencyOperator) Convert(val *big.Int, currencyFrom *common.Address, currencyTo *common.Address) (*big.Int, error) {
exchangeRateFrom, err1 := co.getExchangeRate(currencyFrom)
exchangeRateTo, err2 := co.getExchangeRate(currencyTo)

if err1 != nil || err2 != nil {
log.Error("CurrencyOperator.Convert - Error in retreiving currency exchange rates")
if err1 != nil {
return nil, err1
}
if err2 != nil {
return nil, err2
}
}

// Given value of val and rates n1/d1 and n2/d2 the function below does
// (val * n1 * d2) / (d1 * n2)
numerator := new(big.Int).Mul(val, new(big.Int).Mul(exchangeRateFrom.Numerator, exchangeRateTo.Denominator))
denominator := new(big.Int).Mul(exchangeRateFrom.Denominator, exchangeRateTo.Numerator)
return new(big.Int).Div(numerator, denominator), nil
}

func (co *CurrencyOperator) Cmp(val1 *big.Int, currency1 *common.Address, val2 *big.Int, currency2 *common.Address) int {
func (pc *PriceComparator) Cmp(val1 *big.Int, currency1 *common.Address, val2 *big.Int, currency2 *common.Address) int {
if currency1 == currency2 {
return val1.Cmp(val2)
}

exchangeRate1, err1 := co.getExchangeRate(currency1)
exchangeRate2, err2 := co.getExchangeRate(currency2)
exchangeRate1Num, exchangeRate1Den, err1 := pc.getExchangeRate(currency1)
exchangeRate2Num, exchangeRate2Den, err2 := pc.getExchangeRate(currency2)

if err1 != nil || err2 != nil {
currency1Output := "nil"
Expand All @@ -184,90 +151,85 @@ func (co *CurrencyOperator) Cmp(val1 *big.Int, currency1 *common.Address, val2 *
}

// Below code block is basically evaluating this comparison:
// val1 * exchangeRate1.Numerator/exchangeRate1.Denominator < val2 * exchangeRate2.Numerator/exchangeRate2.Denominator
// val1 / exchangeRate1Num/exchangeRate1Den < val2 / exchangeRate2Num/exchangeRate2Den
// It will transform that comparison to this, to remove having to deal with fractional values.
// val1 * exchangeRate1.Numerator * exchangeRate2.Denominator < val2 * exchangeRate2.Numerator * exchangeRate1.Denominator
leftSide := new(big.Int).Mul(val1, new(big.Int).Mul(exchangeRate1.Numerator, exchangeRate2.Denominator))
rightSide := new(big.Int).Mul(val2, new(big.Int).Mul(exchangeRate2.Numerator, exchangeRate1.Denominator))
// val1 * exchangeRate2Num * exchangeRate1Den < val2 * exchangeRate1Num * exchangeRate2Den
leftSide := new(big.Int).Mul(val1, new(big.Int).Mul(exchangeRate2Num, exchangeRate1Den))
rightSide := new(big.Int).Mul(val2, new(big.Int).Mul(exchangeRate1Num, exchangeRate2Den))
return leftSide.Cmp(rightSide)
}

// This function will retrieve the exchange rates from the SortedOracles contract and cache them.
// SortedOracles must have a function with the following signature:
// "function medianRate(address)"
func (co *CurrencyOperator) retrieveExchangeRates() {
gasCurrencyAddresses := co.gcWl.retrieveWhitelist()
log.Trace("CurrencyOperator.retrieveExchangeRates called", "gasCurrencyAddresses", gasCurrencyAddresses)
func (pc *PriceComparator) retrieveExchangeRates() {
gasCurrencyAddresses := pc.gcWl.retrieveWhitelist()
log.Trace("PriceComparator.retrieveExchangeRates called", "gasCurrencyAddresses", gasCurrencyAddresses)

sortedOraclesAddress := co.regAdd.GetRegisteredAddress(params.SortedOraclesRegistryId)
sortedOraclesAddress := pc.regAdd.GetRegisteredAddress(params.SortedOraclesRegistryId)

if sortedOraclesAddress == nil {
log.Error("Can't get the sortedOracles smart contract address from the registry")
return
}

celoGoldAddress := co.regAdd.GetRegisteredAddress(params.GoldTokenRegistryId)
celoGoldAddress := pc.regAdd.GetRegisteredAddress(params.GoldTokenRegistryId)

if celoGoldAddress == nil {
log.Error("Can't get the celo gold smart contract address from the registry")
return
}

co.currencyOperatorMu.Lock()

for _, gasCurrencyAddress := range gasCurrencyAddresses {
if gasCurrencyAddress == *celoGoldAddress {
continue
}

var returnArray [2]*big.Int

log.Trace("CurrencyOperator.retrieveExchangeRates - Calling medianRate", "sortedOraclesAddress", sortedOraclesAddress.Hex(),
log.Trace("PriceComparator.retrieveExchangeRates - Calling medianRate", "sortedOraclesAddress", sortedOraclesAddress.Hex(),
"gas currency", gasCurrencyAddress.Hex())

if leftoverGas, err := co.iEvmH.MakeCall(*sortedOraclesAddress, medianRateFuncABI, "medianRate", []interface{}{gasCurrencyAddress}, &returnArray, 20000, nil, nil); err != nil {
log.Error("CurrencyOperator.retrieveExchangeRates - SortedOracles.medianRate invocation error", "leftoverGas", leftoverGas, "err", err)
if leftoverGas, err := pc.iEvmH.MakeCall(*sortedOraclesAddress, medianRateFuncABI, "medianRate", []interface{}{gasCurrencyAddress}, &returnArray, 20000, nil, nil); err != nil {
log.Error("PriceComparator.retrieveExchangeRates - SortedOracles.medianRate invocation error", "leftoverGas", leftoverGas, "err", err)
continue
} else {
log.Trace("CurrencyOperator.retrieveExchangeRates - SortedOracles.medianRate invocation success", "returnArray", returnArray, "leftoverGas", leftoverGas)
log.Trace("PriceComparator.retrieveExchangeRates - SortedOracles.medianRate invocation success", "returnArray", returnArray, "leftoverGas", leftoverGas)

if _, ok := co.exchangeRates[gasCurrencyAddress]; !ok {
co.exchangeRates[gasCurrencyAddress] = &exchangeRate{}
if _, ok := pc.exchangeRates[gasCurrencyAddress]; !ok {
pc.exchangeRates[gasCurrencyAddress] = &exchangeRate{}
}

co.exchangeRates[gasCurrencyAddress].Numerator = returnArray[0]
co.exchangeRates[gasCurrencyAddress].Denominator = returnArray[1]
pc.exchangeRates[gasCurrencyAddress].Numerator = returnArray[0]
pc.exchangeRates[gasCurrencyAddress].Denominator = returnArray[1]
}
}

co.currencyOperatorMu.Unlock()
}

// TODO (jarmg 5/30/18): Change this to cache based on block number
func (co *CurrencyOperator) mainLoop() {
co.retrieveExchangeRates()
func (pc *PriceComparator) mainLoop() {
pc.retrieveExchangeRates()
ticker := time.NewTicker(10 * time.Second)

for range ticker.C {
co.retrieveExchangeRates()
pc.retrieveExchangeRates()
}
}

func NewCurrencyOperator(gcWl *GasCurrencyWhitelist, regAdd *RegisteredAddresses, iEvmH *InternalEVMHandler) *CurrencyOperator {
func NewPriceComparator(gcWl *GasCurrencyWhitelist, regAdd *RegisteredAddresses, iEvmH *InternalEVMHandler) *PriceComparator {
exchangeRates := make(map[common.Address]*exchangeRate)

co := &CurrencyOperator{
pc := &PriceComparator{
gcWl: gcWl,
exchangeRates: exchangeRates,
regAdd: regAdd,
iEvmH: iEvmH,
}

if co.gcWl != nil {
go co.mainLoop()
if pc.gcWl != nil {
go pc.mainLoop()
}

return co
return pc
}

// This function will retrieve the balance of an ERC20 token.
Expand Down
36 changes: 14 additions & 22 deletions core/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,24 +29,14 @@ import (
"github.com/ethereum/go-ethereum/params"
)

// ChainContext supports retrieving chain data and consensus parameters
// from the block chain to be used during transaction processing.
// ChainContext supports retrieving headers and consensus parameters from the
// current blockchain to be used during transaction processing.
type ChainContext interface {
// Engine retrieves the blockchain's consensus engine.
// Engine retrieves the chain's consensus engine.
Engine() consensus.Engine

// GetHeader returns the hash corresponding to their hash.
GetHeader(common.Hash, uint64) *types.Header

// GetVMConfig returns the node's vm configuration
GetVMConfig() *vm.Config

CurrentHeader() *types.Header

State() (*state.StateDB, error)

// Config returns the blockchain's chain configuration
Config() *params.ChainConfig
}

// NewEVMContext creates a new context for use in the EVM.
Expand Down Expand Up @@ -148,24 +138,24 @@ func Transfer(db vm.StateDB, sender, recipient common.Address, amount *big.Int)

// An EVM handler to make calls to smart contracts from within geth
type InternalEVMHandler struct {
chain ChainContext
regAdd *RegisteredAddresses
blockchain *BlockChain // Used to construct the EVM object needed to make the call the medianator contract
chainConfig *params.ChainConfig // The config object of the eth object
regAdd *RegisteredAddresses
}

func (iEvmH *InternalEVMHandler) MakeCall(scAddress common.Address, abi abi.ABI, funcName string, args []interface{}, returnObj interface{}, gas uint64, header *types.Header, state *state.StateDB) (uint64, error) {
// Normally, when making an evm call, we should use the current block's state. However,
// there are times (e.g. retrieving the set of validators when an epoch ends) that we need
// to call the evm using the currently mined block. In that case, the header and state params
// will be non nil.
log.Trace("InternalEVMHandler.MakeCall called")

if header == nil {
header = iEvmH.chain.CurrentHeader()
header = iEvmH.blockchain.CurrentBlock().Header()
}

if state == nil {
var err error
state, err = iEvmH.chain.State()
state, err = iEvmH.blockchain.StateAt(header.Root)
if err != nil {
log.Error("Error in retrieving the state from the blockchain")
return 0, err
Expand All @@ -175,8 +165,8 @@ func (iEvmH *InternalEVMHandler) MakeCall(scAddress common.Address, abi abi.ABI,
// The EVM Context requires a msg, but the actual field values don't really matter for this case.
// Putting in zero values.
msg := types.NewMessage(common.HexToAddress("0x0"), nil, 0, common.Big0, 0, common.Big0, nil, nil, []byte{}, false)
context := NewEVMContext(msg, header, iEvmH.chain, nil, iEvmH.regAdd)
evm := vm.NewEVM(context, state, iEvmH.chain.Config(), *iEvmH.chain.GetVMConfig())
context := NewEVMContext(msg, header, iEvmH.blockchain, nil, iEvmH.regAdd)
evm := vm.NewEVM(context, state, iEvmH.chainConfig, *iEvmH.blockchain.GetVMConfig())

zeroCaller := vm.AccountRef(common.HexToAddress("0x0"))
return evm.ABIStaticCall(zeroCaller, scAddress, abi, funcName, args, returnObj, gas)
Expand All @@ -186,9 +176,11 @@ func (iEvmH *InternalEVMHandler) SetRegisteredAddresses(regAdd *RegisteredAddres
iEvmH.regAdd = regAdd
}

func NewInternalEVMHandler(chain ChainContext) *InternalEVMHandler {
func NewInternalEVMHandler(chainConfig *params.ChainConfig, blockchain *BlockChain) *InternalEVMHandler {
iEvmH := InternalEVMHandler{
chain: chain,
blockchain: blockchain,
chainConfig: chainConfig,
}

return &iEvmH
}
7 changes: 1 addition & 6 deletions core/registeredAddresses.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const (

var (
registrySmartContractAddress = common.HexToAddress("0x000000000000000000000000000000000000ce10")
registeredContractIds = []string{params.GoldTokenRegistryId, params.AddressBasedEncryptionRegistryId, params.ReserveRegistryId, params.SortedOraclesRegistryId, params.GasCurrencyWhitelistRegistryId, params.ValidatorsRegistryId, params.GasPriceOracleRegistryId}
registeredContractIds = []string{params.GoldTokenRegistryId, params.AddressBasedEncryptionRegistryId, params.ReserveRegistryId, params.SortedOraclesRegistryId, params.GasCurrencyWhitelistRegistryId, params.ValidatorsRegistryId}
getAddressForFuncABI, _ = abi.JSON(strings.NewReader(getAddressForABI))
zeroAddress = common.Address{}
)
Expand Down Expand Up @@ -93,15 +93,10 @@ func (ra *RegisteredAddresses) RefreshAddresses() {
}

func (ra *RegisteredAddresses) GetRegisteredAddress(registryId string) *common.Address {
if len(ra.registeredAddresses) == 0 { // This refresh is for a light client that failed to refresh (did not have a network connection) during node construction
ra.RefreshAddresses()
}

ra.registeredAddressesMu.RLock()
defer ra.registeredAddressesMu.RUnlock()

if address, ok := ra.registeredAddresses[registryId]; !ok {
log.Error("RegisteredAddresses.GetRegisteredAddress - Error in address retrieval for ", "registry", registryId)
return nil
} else {
return &address
Expand Down
12 changes: 6 additions & 6 deletions core/tx_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -411,16 +411,16 @@ type txPricedList struct {
nonNilCurrencyHeaps map[common.Address]*priceHeap // Heap of prices of all the stored non-nil currency transactions
nilCurrencyHeap *priceHeap // Heap of prices of all the stored nil currency transactions
stales int // Number of stale price points to (re-heap trigger)
co *CurrencyOperator // Comparator object used to compare prices that are using different currencies
pc *PriceComparator // Comparator object used to compare prices that are using different currencies
}

// newTxPricedList creates a new price-sorted transaction heap.
func newTxPricedList(all *txLookup, co *CurrencyOperator) *txPricedList {
func newTxPricedList(all *txLookup, pc *PriceComparator) *txPricedList {
return &txPricedList{
all: all,
nonNilCurrencyHeaps: make(map[common.Address]*priceHeap),
nilCurrencyHeap: new(priceHeap),
co: co,
pc: pc,
}
}

Expand Down Expand Up @@ -489,7 +489,7 @@ func (l *txPricedList) Cap(cgThreshold *big.Int, local *accountSet) types.Transa
continue
}

if l.co.Cmp(tx.GasPrice(), tx.GasCurrency(), cgThreshold, nil) >= 0 {
if l.pc.Cmp(tx.GasPrice(), tx.GasCurrency(), cgThreshold, nil) >= 0 {
save = append(save, tx)
break
}
Expand Down Expand Up @@ -531,7 +531,7 @@ func (l *txPricedList) Underpriced(tx *types.Transaction, local *accountSet) boo
}

cheapest := l.getMinPricedTx()
return l.co.Cmp(cheapest.GasPrice(), cheapest.GasCurrency(), tx.GasPrice(), tx.GasCurrency()) >= 0
return l.pc.Cmp(cheapest.GasPrice(), cheapest.GasCurrency(), tx.GasPrice(), tx.GasCurrency()) >= 0
}

// Discard finds a number of most underpriced transactions, removes them from the
Expand Down Expand Up @@ -574,7 +574,7 @@ func (l *txPricedList) getHeapWithMinHead() (*priceHeap, *types.Transaction) {
cheapestTxn = []*types.Transaction(*cheapestHeap)[0]
} else {
txn := []*types.Transaction(*priceHeap)[0]
if l.co.Cmp(cheapestTxn.GasPrice(), cheapestTxn.GasCurrency(), txn.GasPrice(), txn.GasCurrency()) < 0 {
if l.pc.Cmp(cheapestTxn.GasPrice(), cheapestTxn.GasCurrency(), txn.GasPrice(), txn.GasCurrency()) < 0 {
cheapestHeap = priceHeap
}
}
Expand Down
Loading

0 comments on commit dfc9eef

Please sign in to comment.