Skip to content

Commit

Permalink
Merge pull request expanse-org#28 from happyuc-project/huc/v0.0.3
Browse files Browse the repository at this point in the history
Contract fees collection mechanism change
  • Loading branch information
ldcc committed Jun 6, 2018
2 parents 812d395 + afa398a commit 36d3637
Show file tree
Hide file tree
Showing 11 changed files with 97 additions and 99 deletions.
4 changes: 3 additions & 1 deletion consensus/huchash/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,8 @@ var (
// reward. The total reward consists of the static block reward and rewards for
// included uncles. The coinbase of each uncle block is also rewarded.
func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, uncles []*types.Header) {
// when PendingBlock < 10, reward = FrontierBlockReward / 2 ^ (blockNum + 1 / rewardEpoch)
// when PendingBlock >= 10, reward = 0
var (
blockReward = new(big.Int).Set(FrontierBlockReward)
currBlockNum = new(big.Int).Sub(header.Number, big.NewInt(1))
Expand All @@ -546,7 +548,7 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header

// Compute currently epoch corresponding rewards
if epoch.Cmp(limitEpoch) >= 0 {
blockReward = new(big.Int)
blockReward = big.NewInt(0)
} else {
exponent.Exp(expBase, epoch, nil)
blockReward.Div(blockReward, exponent)
Expand Down
4 changes: 2 additions & 2 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ func (bc *BlockChain) repair(head **types.Block) error {
return nil
}
// Otherwise rewind one block and recheck state availability there
(*head) = bc.GetBlock((*head).ParentHash(), (*head).NumberU64()-1)
*head = bc.GetBlock((*head).ParentHash(), (*head).NumberU64()-1)
}
}

Expand Down Expand Up @@ -615,7 +615,7 @@ func (bc *BlockChain) GetBlocksFromHash(hash common.Hash, n int) (blocks []*type
// GetUnclesInChain retrieves all the uncles from a given block backwards until
// a specific distance is reached.
func (bc *BlockChain) GetUnclesInChain(block *types.Block, length int) []*types.Header {
uncles := []*types.Header{}
var uncles []*types.Header
for i := 0; block != nil && i < length; i++ {
uncles = append(uncles, block.Uncles()...)
block = bc.GetBlock(block.ParentHash(), block.NumberU64()-1)
Expand Down
2 changes: 1 addition & 1 deletion core/database_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ func GetBlockReceipts(db DatabaseReader, hash common.Hash, number uint64) types.
if len(data) == 0 {
return nil
}
storageReceipts := []*types.ReceiptForStorage{}
var storageReceipts []*types.ReceiptForStorage
if err := rlp.DecodeBytes(data, &storageReceipts); err != nil {
log.Error("Invalid receipt array RLP", "hash", hash, "err", err)
return nil
Expand Down
13 changes: 13 additions & 0 deletions core/state/state_object.go
Original file line number Diff line number Diff line change
Expand Up @@ -384,3 +384,16 @@ func (self *stateObject) Nonce() uint64 {
func (self *stateObject) Value() *big.Int {
panic("Value on stateObject should never be called")
}

func (account *Account) String() string {
return fmt.Sprintf(`
Nonce: %v
Balance: %v
Root: %x
CodeHash: %s
`,
account.Nonce,
account.Balance,
account.Root,
common.ToHex(account.CodeHash))
}
63 changes: 21 additions & 42 deletions core/state_transition.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ type StateTransition struct {
gasPrice *big.Int
initialGas uint64
value *big.Int
actValue *big.Int
data []byte
state vm.StateDB
evm *vm.EVM
Expand Down Expand Up @@ -119,7 +118,6 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition
msg: msg,
gasPrice: msg.GasPrice(),
value: msg.Value(),
actValue: msg.Value(),
data: msg.Data(),
state: evm.StateDB,
}
Expand Down Expand Up @@ -172,30 +170,22 @@ func (st *StateTransition) useGas(amount uint64) error {
// Transactions fee will be deducted from the recipient. Consider the recipient may
// not have hucer balance, fee will deducted from this transfer.
func (st *StateTransition) buyGas() error {
var (
state = st.state
from = st.from().Address()
hucTx = st.value.Cmp(big.NewInt(0)) > 0
mgval = new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), st.gasPrice)
)

if hucTx && st.value.Cmp(mgval) < 0 {
return errInsufficientBalanceForGas
} else if st.msg.To() == nil && state.GetBalance(from).Cmp(mgval) < 0 {
var assert *big.Int
if len(st.data) == 0 || st.msg.To() == nil {
assert = st.value
} else {
assert = st.state.GetBalance(*st.msg.To())
}
if assert.Cmp(new(big.Int).Mul(st.gasPrice, new(big.Int).SetUint64(st.msg.Gas()))) < 0 {
return errInsufficientBalanceForGas
} else if err := st.gp.SubGas(st.msg.Gas()); err != nil {
}
if err := st.gp.SubGas(st.msg.Gas()); err != nil {
return err
}

st.gas += st.msg.Gas()
st.initialGas = st.msg.Gas()

if hucTx {
state.SubBalance(from, mgval)
st.actValue = new(big.Int).Sub(st.value, mgval)
} else if st.msg.To() == nil {
state.SubBalance(from, mgval)
}
return nil
}

Expand All @@ -220,53 +210,51 @@ func (st *StateTransition) preCheck() error {
// failed. An error indicates a consensus issue.
func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bool, err error) {
// pre check and pay deposit
if err = st.preCheck(); err != nil {
if err := st.preCheck(); err != nil {
return nil, 0, false, err
}

// pay intrinsic gas
homestead := st.evm.ChainConfig().IsHomestead(st.evm.BlockNumber)
contractCreation := st.msg.To() == nil
if gas, err := IntrinsicGas(st.data, contractCreation, homestead); err != nil {
if gas, err := IntrinsicGas(st.data, st.msg.To() == nil, homestead); err != nil {
return nil, 0, false, err
} else if err = st.useGas(gas); err != nil {
return nil, 0, false, err
}

// do transaction
ret, failed, err = st.transitionDb()
ret, recipient, failed, err := st.transitionDb()
if err == vm.ErrInsufficientBalance {
return nil, 0, false, err
}

// refund deposit
st.refundGas()
// If that tx changing the hucer for any account, pay gas for miner
if st.value.Cmp(big.NewInt(0)) > 0 || st.msg.To() == nil {
st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice))
}
st.state.SubBalance(recipient, new(big.Int).Mul(st.gasPrice, new(big.Int).SetUint64(st.gasUsed())))
st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(st.gasPrice, new(big.Int).SetUint64(st.gasUsed())))

return ret, st.gasUsed(), failed, err
}

// vm errors do not effect consensus and are therefor not
// assigned to err, except for insufficient balance error.
func (st *StateTransition) transitionDb() (ret []byte, failed bool, err error) {
func (st *StateTransition) transitionDb() (ret []byte, recipient common.Address, failed bool, err error) {
sender := st.from()
if st.msg.To() == nil {
ret, _, st.gas, err = st.evm.Create(sender, st.data, st.gas, st.actValue)
ret, recipient, st.gas, err = st.evm.Create(sender, st.data, st.gas, st.value)
} else {
// Increment the nonce for the next transaction
recipient = *st.msg.To()
st.state.SetNonce(sender.Address(), st.state.GetNonce(sender.Address())+1)
ret, st.gas, err = st.evm.Call(sender, st.to().Address(), st.data, st.gas, st.actValue)
ret, st.gas, err = st.evm.Call(sender, st.to().Address(), st.data, st.gas, st.value)
}
if err != nil {
log.Debug("VM returned with error", "err", err)
if err == vm.ErrInsufficientBalance {
return nil, false, err
return nil, common.Address{}, false, err
}
}
return ret, err != nil, err
return ret, recipient, err != nil, err
}

func (st *StateTransition) refundGas() {
Expand All @@ -277,16 +265,7 @@ func (st *StateTransition) refundGas() {
}
st.gas += refund

// If that tx is contain about transfer or spend out hucer,
// Return hucer for remaining gas, exchanged at the original rate.
remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice)
if st.msg.To() == nil {
st.state.AddBalance(st.from().Address(), remaining)
} else if st.value.Cmp(big.NewInt(0)) > 0 {
st.state.AddBalance(st.to().Address(), remaining)
}
// Also return remaining gas to the block gas counter so it is
// available for the next transaction.
// Retaining gas to the block gas counter so it is available for the next transaction.
st.gp.AddGas(st.gas)
}

Expand Down
74 changes: 37 additions & 37 deletions core/tx_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,14 @@ import (
"gopkg.in/karalabe/cookiejar.v2/collections/prque"
)

// Per transaction that creates a contract minimum amount you need to store in.
var (
TxContractCreationDeposit, _ = new(big.Int).SetString("100000000000000000000", 10)
)

const (
// chainHeadChanSize is the size of channel listening to ChainHeadEvent.
chainHeadChanSize = 10
// rmTxChanSize is the size of channel listening to RemovedTransactionEvent.
rmTxChanSize = 10
chainHeadChanSize = 10 // chainHeadChanSize is the size of channel listening to ChainHeadEvent.
rmTxChanSize = 10 // rmTxChanSize is the size of channel listening to RemovedTransactionEvent.
)

var (
Expand All @@ -60,7 +63,7 @@ var (

// ErrContractCreation is returned if the total cost of executing a transaction
// is higher than the balance of the user's account.
ErrContractCreation = errors.New("can not create contract and transfer in same tx")
ErrContractCreation = errors.New("insufficient funds for create, minimum store 100 hucer into contract")

// ErrInsufficientValues is returned if the total cost of executing a transaction
// is higher than the balance of the user's account.
Expand Down Expand Up @@ -127,42 +130,35 @@ type blockChain interface {
CurrentBlock() *types.Block
GetBlock(hash common.Hash, number uint64) *types.Block
StateAt(root common.Hash) (*state.StateDB, error)

SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription
}

// TxPoolConfig are the configuration parameters of the transaction pool.
type TxPoolConfig struct {
NoLocals bool // Whether local transaction handling should be disabled
Journal string // Journal of local transactions to survive node restarts
Rejournal time.Duration // Time interval to regenerate the local transaction journal

PriceLimit uint64 // Minimum gas price to enforce for acceptance into the pool
PriceBump uint64 // Minimum price bump percentage to replace an already existing transaction (nonce)

AccountSlots uint64 // Minimum number of executable transaction slots guaranteed per account
GlobalSlots uint64 // Maximum number of executable transaction slots for all accounts
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
NoLocals bool // Whether local transaction handling should be disabled
Journal string // Journal of local transactions to survive node restarts
Rejournal time.Duration // Time interval to regenerate the local transaction journal
PriceLimit uint64 // Minimum gas price to enforce for acceptance into the pool
PriceBump uint64 // Minimum price bump percentage to replace an already existing transaction (nonce)
AccountSlots uint64 // Minimum number of executable transaction slots guaranteed per account
GlobalSlots uint64 // Maximum number of executable transaction slots for all accounts
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
}

// DefaultTxPoolConfig contains the default configurations for the transaction
// pool.
var DefaultTxPoolConfig = TxPoolConfig{
Journal: "transactions.rlp",
Rejournal: time.Hour,

PriceLimit: 1,
PriceBump: 10,

Journal: "transactions.rlp",
Rejournal: time.Hour,
PriceLimit: 1,
PriceBump: 10,
AccountSlots: 16,
GlobalSlots: 4096,
AccountQueue: 64,
GlobalQueue: 1024,

Lifetime: 3 * time.Hour,
Lifetime: 3 * time.Hour,
}

// sanitize checks the provided user configurations and changes anything that's
Expand Down Expand Up @@ -562,7 +558,8 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
}
// Transactions can't be negative. This may never happen using RLP decoded
// transactions but may occur if you create a transaction using the RPC.
if tx.Value().Sign() < 0 {
var val = tx.Value()
if val.Sign() < 0 {
return ErrNegativeValue
}
// Ensure the transaction doesn't exceed the current block limit gas.
Expand Down Expand Up @@ -594,24 +591,27 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {

// Transactor should have enough funds to cover the costs,
// cost == tx.data.Amount
var balance = pool.currentState.GetBalance(from)
if balance.Cmp(tx.Value()) < 0 {
if pool.currentState.GetBalance(from).Cmp(val) < 0 {
return ErrInsufficientValues
}

// Transfer and ContractCreation can not do with same tx
var hucTx = tx.Value().Cmp(big.NewInt(0)) > 0
if hucTx && contractCreation {
// Creating contract need to store a certain amount of hucer
if contractCreation && val.Cmp(TxContractCreationDeposit) < 0 {
return ErrContractCreation
}

// Transaction value should have enough funds to cover the fees,
// fee == gasPrice * gasLimit
if fee := tx.Fee(); hucTx && tx.Value().Cmp(fee) < 0 {
return ErrInsufficientFees
} else if contractCreation && balance.Cmp(fee) < 0 {
// fees == gasPrice * gasLimit
var assert *big.Int
if len(tx.Data()) == 0 || contractCreation {
assert = tx.Value()
} else {
assert = pool.currentState.GetBalance(*tx.To())
}
if assert.Cmp(tx.Fee()) < 0 {
return ErrInsufficientFees
}

return nil
}

Expand Down
3 changes: 1 addition & 2 deletions core/types/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,8 +286,7 @@ func (tx *Transaction) String() string {
} else {
to = fmt.Sprintf("%x", tx.data.Recipient[:])
}
return fmt.Sprintf(
`
return fmt.Sprintf(`
TX(%x)
Contract: %v
From: %s
Expand Down
3 changes: 1 addition & 2 deletions huc/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,8 @@ func (b *HucApiBackend) GetTd(blockHash common.Hash) *big.Int {
}

func (b *HucApiBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error) {
state.SetBalance(msg.From(), math.MaxBig256)
state.SetBalance(*msg.To(), math.MaxBig256)
vmError := func() error { return nil }

context := core.NewEVMContext(msg, header, b.huc.BlockChain(), nil)
return vm.NewEVM(context, state, b.huc.chainConfig, vmCfg), vmError, nil
}
Expand Down
2 changes: 1 addition & 1 deletion les/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ func (b *LesApiBackend) GetTd(blockHash common.Hash) *big.Int {
}

func (b *LesApiBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header, vmCfg vm.Config) (*vm.EVM, func() error, error) {
state.SetBalance(msg.From(), math.MaxBig256)
state.SetBalance(*msg.To(), math.MaxBig256)
context := core.NewEVMContext(msg, header, b.huc.blockchain, nil)
return vm.NewEVM(context, state, b.huc.chainConfig, vmCfg), state.Error, nil
}
Expand Down

0 comments on commit 36d3637

Please sign in to comment.