Skip to content

Commit

Permalink
链克交易手续费调整,按转账金额千分之五收取,最低收取0.05链克,最大500链克
Browse files Browse the repository at this point in the history
  • Loading branch information
lianxiangcloud committed Jun 12, 2019
1 parent 947951d commit 6c1388a
Show file tree
Hide file tree
Showing 17 changed files with 243 additions and 70 deletions.
50 changes: 50 additions & 0 deletions ethereum/go-ethereum/common/lkfee.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package common

import "math/big"

/*
手续费为交易金额的千分之五,单笔最低为0.05链克,最高为500链克;在计算时,不足
1链克的小数部分按照1链克计算,例如一笔交易金额为1000.1链克的交易的手续费为
5.005链克,1001链克的交易手续费也为5.005链克
if (x % (1e+18) != 0) {
fee = (x/(1e+18)+1) * rate *(1e+13)
} else {
fee = (x/(1e+18)) * rate *(1e+13)
}
if fee < min {
fee = min
}
if max != 0 && fee > max {
fee = max
}
*/

const (
MaxGasLimit = 5e9 // max gas limit (500 lianke)
MinGasLimit = 5e5 // min gas limit (0.05 lianke)

everLiankeFee = 5e4 // ever poundage fee unit(gas)
gasToLiankeRate = 1e7 // lianke = 1e+7 gas
gasPrice = 1e11
)

func CalNewFee(value *big.Int) uint64 {
var liankeCount *big.Int
lianke := new(big.Int).Mul(big.NewInt(gasPrice), big.NewInt(gasToLiankeRate))
if new(big.Int).Mod(value, lianke).Uint64() != 0 {
liankeCount = new(big.Int).Div(value, lianke)
liankeCount.Add(liankeCount, big.NewInt(1))
} else {
liankeCount = new(big.Int).Div(value, lianke)
}
calFeeGas := new(big.Int).Mul(big.NewInt(everLiankeFee), liankeCount)

if calFeeGas.Cmp(big.NewInt(MinGasLimit)) < 0 {
calFeeGas.Set(big.NewInt(MinGasLimit))
}
if MaxGasLimit != 0 && calFeeGas.Cmp(big.NewInt(MaxGasLimit)) > 0 {
calFeeGas.Set(big.NewInt(MaxGasLimit))
}
return calFeeGas.Uint64()
}
34 changes: 34 additions & 0 deletions ethereum/go-ethereum/common/lkfee_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package common

import (
"math/big"
"testing"
)

func TestCalNewFee(t *testing.T) {
type gasTest struct {
val *big.Int
gasFee uint64
}

lianke := new(big.Int).Mul(big.NewInt(gasPrice), big.NewInt(gasToLiankeRate))

// test msg
gasTestMsg := []gasTest {
{big.NewInt(0), MinGasLimit},
{big.NewInt(10), MinGasLimit},
{lianke, MinGasLimit},
{new(big.Int).Mul(big.NewInt(10), lianke), MinGasLimit},
{new(big.Int).Mul(big.NewInt(100), lianke), 5e6},
{new(big.Int).Mul(big.NewInt(1e10), lianke), MaxGasLimit},
{new(big.Int).Mul(big.NewInt(1e11), lianke), MaxGasLimit},
}

// check
for _, v := range gasTestMsg {
calFee := CalNewFee(v.val)
if v.gasFee != calFee {
t.Fatal("CalNewFee failed.", "val", v.val, "gasFee", v.gasFee, "calFee", calFee)
}
}
}
8 changes: 1 addition & 7 deletions ethereum/go-ethereum/consensus/ethash/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,10 +268,7 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent *
if expected.Cmp(header.Difficulty) != 0 {
return fmt.Errorf("invalid difficulty: have %v, want %v", header.Difficulty, expected)
}
// Verify that the gas limit is <= 2^63-1
if header.GasLimit.Cmp(math.MaxBig63) > 0 {
return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, math.MaxBig63)
}

// Verify that the gasUsed is <= gasLimit
if header.GasUsed.Cmp(header.GasLimit) > 0 {
return fmt.Errorf("invalid gasUsed: have %v, gasLimit %v", header.GasUsed, header.GasLimit)
Expand All @@ -285,9 +282,6 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent *
limit := new(big.Int).Set(parent.GasLimit)
limit = limit.Div(limit, params.GasLimitBoundDivisor)

if diff.Cmp(limit) >= 0 || header.GasLimit.Cmp(params.MinGasLimit) < 0 {
return fmt.Errorf("invalid gas limit: have %v, want %v += %v", header.GasLimit, parent.GasLimit, limit)
}
// Verify that the block number is parent's +1
if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 {
return consensus.ErrInvalidNumber
Expand Down
10 changes: 2 additions & 8 deletions ethereum/go-ethereum/core/tx_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,6 @@ type txList struct {
txs *txSortedMap // Heap indexed sorted hash map of the transactions

costcap *big.Int // Price of the highest costing transaction (reset only if exceeds balance)
gascap *big.Int // Gas limit of the highest spending transaction (reset only if exceeds block limit)
}

// newTxList create a new transaction list for maintaining nonce-indexable fast,
Expand All @@ -234,7 +233,6 @@ func newTxList(strict bool) *txList {
strict: strict,
txs: newTxSortedMap(),
costcap: new(big.Int),
gascap: new(big.Int),
}
}

Expand Down Expand Up @@ -266,9 +264,6 @@ func (l *txList) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Tran
if cost := tx.Cost(); l.costcap.Cmp(cost) < 0 {
l.costcap = cost
}
if gas := tx.Gas(); l.gascap.Cmp(gas) < 0 {
l.gascap = gas
}
return true, old
}

Expand All @@ -290,14 +285,13 @@ func (l *txList) Forward(threshold uint64) types.Transactions {
// the newly invalidated transactions.
func (l *txList) Filter(costLimit, gasLimit *big.Int) (types.Transactions, types.Transactions) {
// If all transactions are below the threshold, short circuit
if l.costcap.Cmp(costLimit) <= 0 && l.gascap.Cmp(gasLimit) <= 0 {
if l.costcap.Cmp(costLimit) <= 0 {
return nil, nil
}
l.costcap = new(big.Int).Set(costLimit) // Lower the caps to the thresholds
l.gascap = new(big.Int).Set(gasLimit)

// Filter out all the transactions above the account's funds
removed := l.txs.Filter(func(tx *types.Transaction) bool { return tx.Cost().Cmp(costLimit) > 0 || tx.Gas().Cmp(gasLimit) > 0 })
removed := l.txs.Filter(func(tx *types.Transaction) bool { return tx.Cost().Cmp(costLimit) > 0 })

// If the list was strict, filter anything above the lowest nonce
var invalids types.Transactions
Expand Down
26 changes: 16 additions & 10 deletions ethereum/go-ethereum/core/tx_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ import (
"sync"
"time"

"third_part/lklog"
"third_part/reporttrans"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types"
Expand All @@ -32,8 +35,6 @@ import (
"github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/params"
"gopkg.in/karalabe/cookiejar.v2/collections/prque"
"third_part/lklog"
"third_part/reporttrans"
)

const (
Expand Down Expand Up @@ -158,7 +159,8 @@ type TxPoolConfig struct {
AccountQueue uint64 // Maximum number of non-executable transaction slots permitted per account
GlobalQueue uint64 // Maximum number of non-executable transaction slots for all accounts

Lifetime time.Duration // Maximum amount of time non-executable transaction are queued
Lifetime time.Duration // Maximum amount of time non-executable transaction are queued
FeeUpdateTime uint64
}

// DefaultTxPoolConfig contains the default configurations for the transaction
Expand Down Expand Up @@ -652,7 +654,17 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
reportData.Cost = tx.Cost().String()
reportData.Gas = tx.Gas().String()
reportData.Nonce = tx.Nonce()
if tx.IllegalGasLimitOrGasPrice(hashcode) {

lastBlockTime := pool.chain.CurrentBlock().Time().Uint64()
feeUpdateTime := pool.config.FeeUpdateTime
var gasFail = false
if feeUpdateTime != 0 && lastBlockTime >= feeUpdateTime {
gasFail = tx.IllegalGasLimitOrGasPrice(hashcode, true)
} else {
gasFail = tx.IllegalGasLimitOrGasPrice(hashcode, false)
}

if gasFail {
reportData.Result = reporttrans.ERR_GAS_LIMIT_OR_GAS_PRICE
reporttrans.Report(reportData)
log.Error("Unallowed value", "gasLimit", tx.Gas(), "gasPrice", tx.GasPrice())
Expand All @@ -673,12 +685,6 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
reporttrans.Report(reportData)
return ErrNegativeValue
}
// Ensure the transaction doesn't exceed the current block limit gas.
if pool.currentMaxGas.Cmp(tx.Gas()) < 0 {
reportData.Result = reporttrans.ERR_GAS_LIMIT
reporttrans.Report(reportData)
return ErrGasLimit
}

if tx.To() != nil {
log.Debug("Transfer transaction occurring", "from", from.String(), "to", tx.To().String(), "amount", tx.Value(), "price", tx.GasPrice(), "nonce", tx.Nonce())
Expand Down
30 changes: 24 additions & 6 deletions ethereum/go-ethereum/core/types/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ import (
"math/big"
"sync/atomic"
"encoding/json"
"strings"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/rlp"
"strings"
)

//go:generate gencodec -type txdata -field-override txdataMarshaling -out gen_tx_json.go
Expand Down Expand Up @@ -114,11 +114,10 @@ func newTransaction(nonce uint64, to *common.Address, amount, gasLimit, gasPrice
// 非合约gasLimit会等于gasUsed, 这样gasLimit * gasPrice = 0.01 (eth)
gasPrice = big.NewInt(1e11)
d.Price.Set(gasPrice)
if !isContract(data) {
gasLimit = big.NewInt(1e5)
}
if gasLimit != nil {
if gasLimit.Sign() > 0 {
d.GasLimit.Set(gasLimit)
} else {
d.GasLimit.SetUint64(common.CalNewFee(amount))
}

return &Transaction{data: d}
Expand All @@ -136,11 +135,30 @@ func isContract(data []byte) bool {
return false
}

func (tx *Transaction) IllegalGasLimitOrGasPrice(hashcode bool) bool {
func (tx *Transaction) IllegalGasLimitOrGasPrice(hashcode bool, newFunc bool) bool {
if tx.GasPrice().Cmp(big.NewInt(1e11)) != 0 {
return true
}

if newFunc {
gasFee := common.CalNewFee(tx.Value())
iscontract := isContract(tx.Data())

if tx.Value().Cmp(big.NewInt(0)) > 0 {
if gasFee > tx.Gas().Uint64() {
return true
}
}
if iscontract && tx.To() == nil {
return false
}
if !hashcode && gasFee != tx.Gas().Uint64() {
return true
}

return false
}

iscontract := isContract(tx.Data())
if !iscontract && tx.Gas().Cmp(big.NewInt(1e5)) != 0 {
return true
Expand Down
42 changes: 40 additions & 2 deletions ethereum/go-ethereum/core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,13 +184,26 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
}
evm.StateDB.CreateAccount(addr)
}
evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)

// Initialise a new contract and set the code that is to be used by the EVM.
// The contract is a scoped environment for this execution context only.
contract := NewContract(caller, to, value, gas)
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))

var totalFee uint64
blockTime := evm.Context.Time.Uint64()
feeUpdateTime := evm.vmConfig.FeeUpdateTime
isFeeUpdate := feeUpdateTime != 0 && blockTime >= feeUpdateTime && len(contract.Code) > 0 && value.Sign() > 0
if isFeeUpdate {
totalFee = common.CalNewFee(value)
if !contract.UseGas(totalFee) {
contract.UseGas(contract.Gas)
return nil, contract.Gas, ErrOutOfGas
}
}

evm.Transfer(evm.StateDB, caller.Address(), to.Address(), value)

// @Note: ywh
// start := time.Now()

Expand All @@ -211,8 +224,14 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
evm.StateDB.RevertToSnapshot(snapshot)
if err != errExecutionReverted {
contract.UseGas(contract.Gas)
} else {
//evm: execution reverted
if isFeeUpdate {
contract.Gas += totalFee
}
}
}

return ret, contract.Gas, err
}

Expand Down Expand Up @@ -357,14 +376,27 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
snapshot := evm.StateDB.Snapshot()
evm.StateDB.CreateAccount(contractAddr)
evm.StateDB.SetNonce(contractAddr, 1)
evm.Transfer(evm.StateDB, caller.Address(), contractAddr, value)

// initialise a new contract and set the code that is to be used by the
// EVM. The contract is a scoped environment for this execution context
// only.
contract := NewContract(caller, AccountRef(contractAddr), value, gas)
contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code)

var totalFee uint64
blockTime := evm.Context.Time.Uint64()
feeUpdateTime := evm.vmConfig.FeeUpdateTime
ifFeeUpdate := feeUpdateTime != 0 && blockTime >= feeUpdateTime && len(contract.Code) > 0 && value.Sign() > 0
if ifFeeUpdate {
totalFee = common.CalNewFee(value)
if !contract.UseGas(totalFee) {
contract.UseGas(contract.Gas)
return nil, contractAddr, contract.Gas, ErrOutOfGas
}
}

evm.Transfer(evm.StateDB, caller.Address(), contractAddr, value)

if evm.vmConfig.NoRecursion && evm.depth > 0 {
return nil, contractAddr, gas, nil
}
Expand Down Expand Up @@ -399,8 +431,14 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
evm.StateDB.RevertToSnapshot(snapshot)
if err != errExecutionReverted {
contract.UseGas(contract.Gas)
} else {
// evm: execution reverted
if ifFeeUpdate {
contract.Gas += totalFee
}
}
}

// Assign err if contract code size exceeds the max while the err is still empty.
if maxCodeSizeExceeded && err == nil {
err = errMaxCodeSizeExceeded
Expand Down
4 changes: 4 additions & 0 deletions ethereum/go-ethereum/core/vm/instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,10 @@ func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
ret, returnGas, err := evm.Call(contract, toAddr, args, gas, value)
if err != nil {
log.Warn("evm.Call", "err", err)

log.Info("TxBatch with error, cancel it")
evm.tb.Cancel()

stack.push(evm.interpreter.intPool.getZero())
} else {
stack.push(evm.interpreter.intPool.get().SetUint64(1))
Expand Down
2 changes: 2 additions & 0 deletions ethereum/go-ethereum/core/vm/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ type Config struct {
// may be left uninitialised and will be set to the default
// table.
JumpTable [256]operation

FeeUpdateTime uint64
}

// Interpreter is used to run Ethereum based contracts and will utilise the
Expand Down
4 changes: 4 additions & 0 deletions ethereum/go-ethereum/eth/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@ func New(ctx *node.ServiceContext, config *Config, pending miner.Pending) (*Ethe
if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
return nil, genesisErr
}

config.TxPool.FeeUpdateTime = config.FeeUpdateTime
chainConfig.FeeUpdateTime = config.FeeUpdateTime

log.Info("Initialised chain configuration", "chainConfig", chainConfig.String())

eth := &Ethereum{
Expand Down

0 comments on commit 6c1388a

Please sign in to comment.