Skip to content

Commit

Permalink
Update debitFrom and creditTo to work with stability fee (ethereum#295)
Browse files Browse the repository at this point in the history
* Test

* lower param amounts

* change branch to point to nitya/stability-fee

* cr comment

* gofmt
  • Loading branch information
nityas authored Jun 22, 2019
1 parent 440864d commit de6848d
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 35 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ jobs:
mkdir -p ~/.ssh/
echo -e "Host github.com\n\tStrictHostKeyChecking no\n" > ~/.ssh/config
export CELO_MONOREPO_DIR="./celo-monorepo"
git clone --depth 1 https://${GH_AUTH_USERNAME}:${GH_AUTH_TOKEN}@github.com/celo-org/celo-monorepo.git ${CELO_MONOREPO_DIR} -b master
git clone --depth 1 https://${GH_AUTH_USERNAME}:${GH_AUTH_TOKEN}@github.com/celo-org/celo-monorepo.git ${CELO_MONOREPO_DIR} -b nitya/stability-fee
# Change these paths to use https login since the SSH key does not have access to these repositories.
# Once we open source this code, these modifications can be eliminated.
# These environment variables are configured at https://circleci.com/gh/celo-org/geth/edit#env-vars
Expand Down
61 changes: 31 additions & 30 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ func IntrinsicGas(data []byte, contractCreation, homestead bool, gasCurrency *co
// In this case, however, the user always ends up paying maxGasForDebitAndCreditTransactions
// keeping it consistent.
if gasCurrency != nil {
gas += 3*params.MaxGasForDebitAndCreditTransactions + params.MaxGasToReadErc20Balance
gas += params.AdditionalGasForNonGoldCurrencies
}

return gas, nil
Expand Down Expand Up @@ -207,22 +207,41 @@ func (st *StateTransition) canBuyGas(accountOwner common.Address, gasNeeded *big
return balanceOf.Cmp(gasNeeded) > 0
}

func (st *StateTransition) debitOrCreditErc20Balance(functionSelector []byte, address common.Address, amount *big.Int, gasCurrency *common.Address) error {
func (st *StateTransition) debitFrom(address common.Address, amount *big.Int, gasCurrency *common.Address) error {
if amount.Cmp(big.NewInt(0)) == 0 {
return nil
}
evm := st.evm
// Function is "debitFrom(address from, uint256 value)"
// selector is first 4 bytes of keccak256 of "debitFrom(address,uint256)"
// Source:
// pip3 install pyethereum
// python3 -c 'from ethereum.utils import sha3; print(sha3("debitFrom(address,uint256)")[0:4].hex())'
functionSelector := hexutil.MustDecode("0x362a5f80")
transactionData := common.GetEncodedAbi(functionSelector, [][]byte{common.AddressToAbi(address), common.AmountToAbi(amount)})

rootCaller := vm.AccountRef(common.HexToAddress("0x0"))
// The caller was already charged for the cost of this operation via IntrinsicGas.
ret, leftoverGas, err := evm.Call(rootCaller, *gasCurrency, transactionData, params.MaxGasForDebitAndCreditTransactions, big.NewInt(0))
if err != nil {
log.Error("failed to debit or credit ERC20 balance", "functionSelector", functionSelector, "ret", hexutil.Encode(ret), "leftoverGas", leftoverGas, "err", err)
return err
}
_, _, err := evm.Call(rootCaller, *gasCurrency, transactionData, params.MaxGasForDebitFromTransactions, big.NewInt(0))
return err
}

return nil
func (st *StateTransition) creditTo(address common.Address, amount *big.Int, gasCurrency *common.Address) error {
if amount.Cmp(big.NewInt(0)) == 0 {
return nil
}
evm := st.evm
// Function is "creditTo(address from, uint256 value)"
// selector is first 4 bytes of keccak256 of "creditTo(address,uint256)"
// Source:
// pip3 install pyethereum
// python3 -c 'from ethereum.utils import sha3; print(sha3("creditTo(address,uint256)")[0:4].hex())'
functionSelector := hexutil.MustDecode("0x9951b90c")
transactionData := common.GetEncodedAbi(functionSelector, [][]byte{common.AddressToAbi(address), common.AmountToAbi(amount)})
rootCaller := vm.AccountRef(common.HexToAddress("0x0"))
// The caller was already charged for the cost of this operation via IntrinsicGas.
_, _, err := evm.Call(rootCaller, *gasCurrency, transactionData, params.MaxGasForCreditToTransactions, big.NewInt(0))
return err
}

func (st *StateTransition) debitGas(from common.Address, amount *big.Int, gasCurrency *common.Address) (err error) {
Expand All @@ -231,9 +250,9 @@ func (st *StateTransition) debitGas(from common.Address, amount *big.Int, gasCur
if gasCurrency == nil {
st.state.SubBalance(from, amount)
return nil
} else {
return st.debitFrom(from, amount, gasCurrency)
}

return st.debitOrCreditErc20Balance(getDebitFromFunctionSelector(), from, amount, gasCurrency)
}

func (st *StateTransition) creditGas(to common.Address, amount *big.Int, gasCurrency *common.Address) (err error) {
Expand All @@ -242,27 +261,9 @@ func (st *StateTransition) creditGas(to common.Address, amount *big.Int, gasCurr
if gasCurrency == nil {
st.state.AddBalance(to, amount)
return nil
} else {
return st.creditTo(to, amount, gasCurrency)
}

return st.debitOrCreditErc20Balance(getCreditToFunctionSelector(), to, amount, gasCurrency)
}

func getDebitFromFunctionSelector() []byte {
// Function is "debitFrom(address from, uint256 value)"
// selector is first 4 bytes of keccak256 of "debitFrom(address,uint256)"
// Source:
// pip3 install pyethereum
// python3 -c 'from ethereum.utils import sha3; print(sha3("debitFrom(address,uint256)")[0:4].hex())'
return hexutil.MustDecode("0x362a5f80")
}

func getCreditToFunctionSelector() []byte {
// Function is "creditTo(address from, uint256 value)"
// selector is first 4 bytes of keccak256 of "creditTo(address,uint256)"
// Source:
// pip3 install pyethereum
// python3 -c 'from ethereum.utils import sha3; print(sha3("creditTo(address,uint256)")[0:4].hex())'
return hexutil.MustDecode("0x9951b90c")
}

func (st *StateTransition) preCheck() error {
Expand Down
2 changes: 1 addition & 1 deletion core/tx_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
"txn cost", tx.Cost().String())
return ErrInsufficientFunds
} else if tx.GasCurrency() != nil {
gasCurrencyBalance, _, err := GetBalanceOf(from, *tx.GasCurrency(), pool.iEvmH, nil, 10*1000)
gasCurrencyBalance, _, err := GetBalanceOf(from, *tx.GasCurrency(), pool.iEvmH, nil, params.MaxGasToReadErc20Balance)

if err != nil {
log.Debug("validateTx error in getting gas currency balance", "gasCurrency", tx.GasCurrency(), "error", err)
Expand Down
2 changes: 1 addition & 1 deletion internal/ethapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1226,7 +1226,7 @@ func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error {
} else {
// When paying for gas in a currency other than Celo Gold, the intrinsic gas use is greater than when paying for gas in Celo Gold.
// We need to cover the gas use of one 'balanceOf', one 'debitFrom', and two 'creditTo' calls.
*(*uint64)(args.Gas) = defaultGas + 3*params.MaxGasForDebitAndCreditTransactions + params.MaxGasToReadErc20Balance
*(*uint64)(args.Gas) = defaultGas + params.AdditionalGasForNonGoldCurrencies
}
}
if args.GasPrice == nil {
Expand Down
7 changes: 5 additions & 2 deletions params/protocol_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ const (
// TODO(asa): Make these operations less expensive by charging only what is used.
// The problem is we don't know how much to refund until the refund is complete.
// If these values are changed, "setDefaults" will need updating.
MaxGasForDebitAndCreditTransactions uint64 = 30 * 1000
MaxGasToReadErc20Balance uint64 = 3 * 1000
MaxGasForDebitFromTransactions uint64 = 50 * 1000
ExpectedGasForDebitFromTransactions uint64 = 35 * 1000
MaxGasForCreditToTransactions uint64 = 30 * 1000
MaxGasToReadErc20Balance uint64 = 10 * 1000
AdditionalGasForNonGoldCurrencies uint64 = 2*MaxGasForCreditToTransactions + ExpectedGasForDebitFromTransactions + MaxGasToReadErc20Balance
)

0 comments on commit de6848d

Please sign in to comment.