From 71aae6ed494098315852b581fdd50521388472f2 Mon Sep 17 00:00:00 2001 From: JacobDenver007 <29848184+JacobDenver007@users.noreply.github.com> Date: Wed, 4 Dec 2019 16:09:51 +0800 Subject: [PATCH] Fee (#533) * add extend * add sign * add recover * add fp * modify txpool * fix sign payer bug * modify SignPayerActionWithMultiKey * execute new tx with feepayer * add feepayer test * modify bugs * fork * not execute when not forked * modify txpool * modif txpool * modify validator * sign feepayer * modify txpool * return error when payer exist and tx.price is not 0 * modify feepayer sign * return error when payer exist but tx.gasprice is not 0 * add gas when payer exist * add gas when payer exist * fix testcase * cost gas when code collision * code collision * add rpc getTransactionReceiptWithPayer * add rpc getTransactionReceiptWithPayer * add ft_getBlockAndResultByNumberWithPayer --- rpcapi/blockchain.go | 25 +++++++++++++++++++++++++ rpcapi/utils.go | 41 +++++++++++++++++++++++++++++++++++++++++ types/action.go | 44 ++++++++++++++++++++++++++++++++++++++++++++ types/transaction.go | 30 ++++++++++++++++++++++++++++++ 4 files changed, 140 insertions(+) diff --git a/rpcapi/blockchain.go b/rpcapi/blockchain.go index d97f4de3..48b85faa 100644 --- a/rpcapi/blockchain.go +++ b/rpcapi/blockchain.go @@ -80,6 +80,21 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(chainID *big.Int, b *types.Block, i return fields } +func (s *PublicBlockChainAPI) GetBlockByNumberWithPayer(ctx context.Context, blockNr rpc.BlockNumber, fullTx bool) map[string]interface{} { + block := s.b.BlockByNumber(ctx, blockNr) + if block != nil { + response := s.rpcOutputBlockWithPayer(s.b.ChainConfig().ChainID, block, true, fullTx) + return response + } + return nil +} + +func (s *PublicBlockChainAPI) rpcOutputBlockWithPayer(chainID *big.Int, b *types.Block, inclTx bool, fullTx bool) map[string]interface{} { + fields := RPCMarshalBlockWithPayer(chainID, b, inclTx, fullTx) + fields["totalDifficulty"] = s.b.GetTd(b.Hash()) + return fields +} + // GetTransactionByHash returns the transaction for the given hash func (s *PublicBlockChainAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) *types.RPCTransaction { // Try to return an already finalized transaction @@ -153,6 +168,16 @@ func (s *PublicBlockChainAPI) GetBlockAndResultByNumber(ctx context.Context, blo return r } +func (s *PublicBlockChainAPI) GetBlockAndResultByNumberWithPayer(ctx context.Context, blockNr rpc.BlockNumber) *types.BlockAndResult { + r := s.b.GetBlockDetailLog(ctx, blockNr) + if r == nil { + return nil + } + block := s.GetBlockByNumberWithPayer(ctx, blockNr, true) + r.Block = block + return r +} + // checkRangeInputArgs checks the input arguments of // GetTxsByAccount,GetTxsByBloom,GetInternalTxByAccount,GetInternalTxByBloom func (s *PublicBlockChainAPI) checkRangeInputArgs(blockNr, lookbackNum uint64) error { diff --git a/rpcapi/utils.go b/rpcapi/utils.go index dd8f2c4f..6c240dbd 100644 --- a/rpcapi/utils.go +++ b/rpcapi/utils.go @@ -78,3 +78,44 @@ func RPCMarshalBlock(chainID *big.Int, b *types.Block, inclTx bool, fullTx bool) return fields } + +func RPCMarshalBlockWithPayer(chainID *big.Int, b *types.Block, inclTx bool, fullTx bool) map[string]interface{} { + head := b.Header() // copies the header once + fields := map[string]interface{}{ + "number": head.Number, + "hash": b.Hash(), + "proposedIrreversible": head.ProposedIrreversible, + "parentHash": head.ParentHash, + "logsBloom": head.Bloom, + "stateRoot": head.Root, + "miner": head.Coinbase, + "difficulty": head.Difficulty, + "extraData": hexutil.Bytes(head.Extra), + "size": b.Size(), + "gasLimit": head.GasLimit, + "gasUsed": head.GasUsed, + "timestamp": head.Time, + "transactionsRoot": head.TxsRoot, + "receiptsRoot": head.ReceiptsRoot, + "forkID": head.ForkID, + } + + if inclTx { + formatTx := func(tx *types.Transaction, index uint64) interface{} { + return tx.Hash() + } + if fullTx { + formatTx = func(tx *types.Transaction, index uint64) interface{} { + return tx.NewRPCTransactionWithPayer(b.Hash(), b.NumberU64(), index) + } + } + txs := b.Transactions() + transactions := make([]interface{}, len(txs)) + for i, tx := range txs { + transactions[i] = formatTx(tx, uint64(i)) + } + fields["transactions"] = transactions + } + + return fields +} diff --git a/types/action.go b/types/action.go index 22e69622..ad8aef1a 100644 --- a/types/action.go +++ b/types/action.go @@ -473,6 +473,50 @@ func (a *Action) NewRPCAction(index uint64) *RPCAction { } } +type RPCActionWithPayer struct { + Type uint64 `json:"type"` + Nonce uint64 `json:"nonce"` + From common.Name `json:"from"` + To common.Name `json:"to"` + AssetID uint64 `json:"assetID"` + GasLimit uint64 `json:"gas"` + Amount *big.Int `json:"value"` + Remark hexutil.Bytes `json:"remark"` + Payload hexutil.Bytes `json:"payload"` + Hash common.Hash `json:"actionHash"` + ActionIdex uint64 `json:"actionIndex"` + Payer common.Name `json:"payer"` + PayerGasPrice *big.Int `json:"payerGasPrice"` +} + +func (a *RPCActionWithPayer) SetHash(hash common.Hash) { + a.Hash = hash +} + +func (a *Action) NewRPCActionWithPayer(index uint64) *RPCActionWithPayer { + var payer common.Name + var price *big.Int + if a.fp != nil { + payer = a.fp.Payer + price = a.fp.GasPrice + } + return &RPCActionWithPayer{ + Type: uint64(a.Type()), + Nonce: a.Nonce(), + From: a.Sender(), + To: a.Recipient(), + AssetID: a.AssetID(), + GasLimit: a.Gas(), + Amount: a.Value(), + Remark: hexutil.Bytes(a.Remark()), + Payload: hexutil.Bytes(a.Data()), + Hash: a.Hash(), + ActionIdex: index, + Payer: payer, + PayerGasPrice: price, + } +} + // deriveChainID derives the chain id from the given v parameter func deriveChainID(v *big.Int) *big.Int { v = new(big.Int).Sub(v, big.NewInt(35)) diff --git a/types/transaction.go b/types/transaction.go index 8d6e8dcb..dfc1085c 100644 --- a/types/transaction.go +++ b/types/transaction.go @@ -211,6 +211,36 @@ func (tx *Transaction) NewRPCTransaction(blockHash common.Hash, blockNumber uint return result } +type RPCTransactionWithPayer struct { + BlockHash common.Hash `json:"blockHash"` + BlockNumber uint64 `json:"blockNumber"` + Hash common.Hash `json:"txHash"` + TransactionIndex uint64 `json:"transactionIndex"` + RPCActionsWithPayer []*RPCActionWithPayer `json:"actions"` + GasAssetID uint64 `json:"gasAssetID"` + GasPrice *big.Int `json:"gasPrice"` + GasCost *big.Int `json:"gasCost"` +} + +func (tx *Transaction) NewRPCTransactionWithPayer(blockHash common.Hash, blockNumber uint64, index uint64) *RPCTransactionWithPayer { + result := new(RPCTransactionWithPayer) + if blockHash != (common.Hash{}) { + result.BlockHash = blockHash + result.BlockNumber = blockNumber + result.TransactionIndex = index + } + result.Hash = tx.Hash() + ras := make([]*RPCActionWithPayer, len(tx.GetActions())) + for index, action := range tx.GetActions() { + ras[index] = action.NewRPCActionWithPayer(uint64(index)) + } + result.RPCActionsWithPayer = ras + result.GasAssetID = tx.gasAssetID + result.GasPrice = tx.gasPrice + result.GasCost = tx.Cost() + return result +} + // TxByNonce sort by transaction first action nonce type TxByNonce []*Transaction