parent
972ea71b17
commit
d4bc279d88
@ -0,0 +1,64 @@ |
||||
package hmyapi |
||||
|
||||
import ( |
||||
"context" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/log" |
||||
"github.com/harmony-one/harmony/accounts" |
||||
"github.com/harmony-one/harmony/core" |
||||
"github.com/harmony-one/harmony/core/types" |
||||
) |
||||
|
||||
// PrivateAccountAPI provides an API to access accounts managed by this node.
|
||||
// It offers methods to create, (un)lock en list accounts. Some methods accept
|
||||
// passwords and are therefore considered private by default.
|
||||
type PrivateAccountAPI struct { |
||||
am *accounts.Manager |
||||
nonceLock *AddrLocker |
||||
b *core.HmyAPIBackend |
||||
} |
||||
|
||||
// NewAccount will create a new account and returns the address for the new account.
|
||||
func (s *PrivateAccountAPI) NewAccount(password string) (common.Address, error) { |
||||
// TODO: port
|
||||
return common.Address{}, nil |
||||
} |
||||
|
||||
// SendTransaction will create a transaction from the given arguments and
|
||||
// tries to sign it with the key associated with args.To. If the given passwd isn't
|
||||
// able to decrypt the key it fails.
|
||||
func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs, passwd string) (common.Hash, error) { |
||||
if args.Nonce == nil { |
||||
// Hold the addresse's mutex around signing to prevent concurrent assignment of
|
||||
// the same nonce to multiple accounts.
|
||||
s.nonceLock.LockAddr(args.From) |
||||
defer s.nonceLock.UnlockAddr(args.From) |
||||
} |
||||
signed, err := s.signTransaction(ctx, &args, passwd) |
||||
if err != nil { |
||||
log.Warn("Failed transaction send attempt", "from", args.From, "to", args.To, "value", args.Value.ToInt(), "err", err) |
||||
return common.Hash{}, err |
||||
} |
||||
return SubmitTransaction(ctx, s.b, signed) |
||||
} |
||||
|
||||
// signTransaction sets defaults and signs the given transaction
|
||||
// NOTE: the caller needs to ensure that the nonceLock is held, if applicable,
|
||||
// and release it after the transaction has been submitted to the tx pool
|
||||
func (s *PrivateAccountAPI) signTransaction(ctx context.Context, args *SendTxArgs, passwd string) (*types.Transaction, error) { |
||||
// Look up the wallet containing the requested signer
|
||||
account := accounts.Account{Address: args.From} |
||||
wallet, err := s.am.Find(account) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
// Set some sanity defaults and terminate on failure
|
||||
if err := args.setDefaults(ctx, s.b); err != nil { |
||||
return nil, err |
||||
} |
||||
// Assemble the transaction and sign with the wallet
|
||||
tx := args.toTransaction() |
||||
|
||||
return wallet.SignTxWithPassphrase(account, passwd, tx, s.b.ChainConfig().ChainID) |
||||
} |
@ -0,0 +1,81 @@ |
||||
package hmyapi |
||||
|
||||
import ( |
||||
"context" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/common/hexutil" |
||||
"github.com/ethereum/go-ethereum/rpc" |
||||
"github.com/harmony-one/harmony/core" |
||||
) |
||||
|
||||
// PublicBlockChainAPI provides an API to access the Harmony blockchain.
|
||||
// It offers only methods that operate on public data that is freely available to anyone.
|
||||
type PublicBlockChainAPI struct { |
||||
b *core.HmyAPIBackend |
||||
} |
||||
|
||||
// NewPublicBlockChainAPI creates a new Harmony blockchain API.
|
||||
func NewPublicBlockChainAPI(b *core.HmyAPIBackend) *PublicBlockChainAPI { |
||||
return &PublicBlockChainAPI{b} |
||||
} |
||||
|
||||
// GetBlockByNumber returns the requested block. When blockNr is -1 the chain head is returned. When fullTx is true all
|
||||
// transactions in the block are returned in full detail, otherwise only the transaction hash is returned.
|
||||
func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, blockNr rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { |
||||
block, err := s.b.BlockByNumber(ctx, blockNr) |
||||
if block != nil { |
||||
response, err := RPCMarshalBlock(block, false, false) |
||||
if err == nil && blockNr == rpc.PendingBlockNumber { |
||||
// Pending blocks need to nil out a few fields
|
||||
for _, field := range []string{"hash", "nonce", "miner"} { |
||||
response[field] = nil |
||||
} |
||||
} |
||||
return response, err |
||||
} |
||||
return nil, err |
||||
} |
||||
|
||||
// GetBlockByHash returns the requested block. When fullTx is true all transactions in the block are returned in full
|
||||
// detail, otherwise only the transaction hash is returned.
|
||||
func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, blockHash common.Hash, fullTx bool) (map[string]interface{}, error) { |
||||
block, err := s.b.GetBlock(ctx, blockHash) |
||||
if block != nil { |
||||
return RPCMarshalBlock(block, false, false) |
||||
} |
||||
return nil, err |
||||
} |
||||
|
||||
// GetCode returns the code stored at the given address in the state for the given block number.
|
||||
func (s *PublicBlockChainAPI) GetCode(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (hexutil.Bytes, error) { |
||||
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) |
||||
if state == nil || err != nil { |
||||
return nil, err |
||||
} |
||||
code := state.GetCode(address) |
||||
return code, state.Error() |
||||
} |
||||
|
||||
// GetStorageAt returns the storage from the state at the given address, key and
|
||||
// block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block
|
||||
// numbers are also allowed.
|
||||
func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, key string, blockNr rpc.BlockNumber) (hexutil.Bytes, error) { |
||||
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) |
||||
if state == nil || err != nil { |
||||
return nil, err |
||||
} |
||||
res := state.GetState(address, common.HexToHash(key)) |
||||
return res[:], state.Error() |
||||
} |
||||
|
||||
// GetBalance returns the amount of wei for the given address in the state of the
|
||||
// given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta
|
||||
// block numbers are also allowed.
|
||||
func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*hexutil.Big, error) { |
||||
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) |
||||
if state == nil || err != nil { |
||||
return nil, err |
||||
} |
||||
return (*hexutil.Big)(state.GetBalance(address)), state.Error() |
||||
} |
@ -0,0 +1,30 @@ |
||||
package hmyapi |
||||
|
||||
import ( |
||||
"github.com/ethereum/go-ethereum/common/hexutil" |
||||
"github.com/harmony-one/harmony/api/proto" |
||||
"github.com/harmony-one/harmony/core" |
||||
) |
||||
|
||||
// PublicHarmonyAPI provides an API to access Harmony related information.
|
||||
// It offers only methods that operate on public data that is freely available to anyone.
|
||||
type PublicHarmonyAPI struct { |
||||
b *core.BlockChain |
||||
} |
||||
|
||||
// ProtocolVersion returns the current Harmony protocol version this node supports
|
||||
func (s *PublicHarmonyAPI) ProtocolVersion() hexutil.Uint { |
||||
return hexutil.Uint(proto.ProtocolVersion) |
||||
} |
||||
|
||||
// Syncing returns false in case the node is currently not syncing with the network. It can be up to date or has not
|
||||
// yet received the latest block headers from its pears. In case it is synchronizing:
|
||||
// - startingBlock: block number this node started to synchronise from
|
||||
// - currentBlock: block number this node is currently importing
|
||||
// - highestBlock: block number of the highest block header this node has received from peers
|
||||
// - pulledStates: number of state entries processed until now
|
||||
// - knownStates: number of known state entries that still need to be pulled
|
||||
func (s *PublicHarmonyAPI) Syncing() (interface{}, error) { |
||||
// TODO(ricl): port
|
||||
return false, nil |
||||
} |
@ -0,0 +1,22 @@ |
||||
package hmyapi |
||||
|
||||
import ( |
||||
"github.com/ethereum/go-ethereum/common/hexutil" |
||||
"github.com/ethereum/go-ethereum/p2p" |
||||
) |
||||
|
||||
// PublicNetAPI offers network related RPC methods
|
||||
type PublicNetAPI struct { |
||||
net *p2p.Server |
||||
networkVersion uint64 |
||||
} |
||||
|
||||
// NewPublicNetAPI creates a new net API instance.
|
||||
func NewPublicNetAPI(net *p2p.Server, networkVersion uint64) *PublicNetAPI { |
||||
return &PublicNetAPI{net, networkVersion} |
||||
} |
||||
|
||||
// PeerCount returns the number of connected peers
|
||||
func (s *PublicNetAPI) PeerCount() hexutil.Uint { |
||||
return hexutil.Uint(s.net.PeerCount()) |
||||
} |
@ -1,18 +0,0 @@ |
||||
package hmyapi |
||||
|
||||
import ( |
||||
"github.com/ethereum/go-ethereum/common" |
||||
) |
||||
|
||||
// PrivateAccountAPI provides an API to access accounts managed by this node.
|
||||
// It offers methods to create, (un)lock en list accounts. Some methods accept
|
||||
// passwords and are therefore considered private by default.
|
||||
type PrivateAccountAPI struct { |
||||
nonceLock *AddrLocker |
||||
} |
||||
|
||||
// NewAccount will create a new account and returns the address for the new account.
|
||||
func (s *PrivateAccountAPI) NewAccount(password string) (common.Address, error) { |
||||
// TODO: port
|
||||
return common.Address{}, nil |
||||
} |
@ -1,223 +0,0 @@ |
||||
package hmyapi |
||||
|
||||
import ( |
||||
"context" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/common/hexutil" |
||||
"github.com/ethereum/go-ethereum/p2p" |
||||
"github.com/ethereum/go-ethereum/rpc" |
||||
"github.com/harmony-one/harmony/api/proto" |
||||
"github.com/harmony-one/harmony/core" |
||||
"github.com/harmony-one/harmony/core/rawdb" |
||||
"github.com/harmony-one/harmony/core/types" |
||||
) |
||||
|
||||
// PublicBlockChainAPI provides an API to access the Harmony blockchain.
|
||||
// It offers only methods that operate on public data that is freely available to anyone.
|
||||
type PublicBlockChainAPI struct { |
||||
b *core.HmyAPIBackend |
||||
} |
||||
|
||||
// NewPublicBlockChainAPI creates a new Harmony blockchain API.
|
||||
func NewPublicBlockChainAPI(b *core.HmyAPIBackend) *PublicBlockChainAPI { |
||||
return &PublicBlockChainAPI{b} |
||||
} |
||||
|
||||
// GetBlockByNumber returns the requested block. When blockNr is -1 the chain head is returned. When fullTx is true all
|
||||
// transactions in the block are returned in full detail, otherwise only the transaction hash is returned.
|
||||
func (s *PublicBlockChainAPI) GetBlockByNumber(ctx context.Context, blockNr rpc.BlockNumber, fullTx bool) (map[string]interface{}, error) { |
||||
block, err := s.b.BlockByNumber(ctx, blockNr) |
||||
if block != nil { |
||||
response, err := RPCMarshalBlock(block, false, false) |
||||
if err == nil && blockNr == rpc.PendingBlockNumber { |
||||
// Pending blocks need to nil out a few fields
|
||||
for _, field := range []string{"hash", "nonce", "miner"} { |
||||
response[field] = nil |
||||
} |
||||
} |
||||
return response, err |
||||
} |
||||
return nil, err |
||||
} |
||||
|
||||
// GetBlockByHash returns the requested block. When fullTx is true all transactions in the block are returned in full
|
||||
// detail, otherwise only the transaction hash is returned.
|
||||
func (s *PublicBlockChainAPI) GetBlockByHash(ctx context.Context, blockHash common.Hash, fullTx bool) (map[string]interface{}, error) { |
||||
block, err := s.b.GetBlock(ctx, blockHash) |
||||
if block != nil { |
||||
return RPCMarshalBlock(block, false, false) |
||||
} |
||||
return nil, err |
||||
} |
||||
|
||||
// newRPCTransactionFromBlockHash returns a transaction that will serialize to the RPC representation.
|
||||
func newRPCTransactionFromBlockHash(b *types.Block, hash common.Hash) *RPCTransaction { |
||||
for idx, tx := range b.Transactions() { |
||||
if tx.Hash() == hash { |
||||
return newRPCTransactionFromBlockIndex(b, uint64(idx)) |
||||
} |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// newRPCTransactionFromBlockIndex returns a transaction that will serialize to the RPC representation.
|
||||
func newRPCTransactionFromBlockIndex(b *types.Block, index uint64) *RPCTransaction { |
||||
txs := b.Transactions() |
||||
if index >= uint64(len(txs)) { |
||||
return nil |
||||
} |
||||
return newRPCTransaction(txs[index], b.Hash(), b.NumberU64(), index) |
||||
} |
||||
|
||||
// GetBalance returns the amount of wei for the given address in the state of the
|
||||
// given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta
|
||||
// block numbers are also allowed.
|
||||
func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*hexutil.Big, error) { |
||||
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) |
||||
if state == nil || err != nil { |
||||
return nil, err |
||||
} |
||||
return (*hexutil.Big)(state.GetBalance(address)), state.Error() |
||||
} |
||||
|
||||
// PublicHarmonyAPI provides an API to access Harmony related information.
|
||||
// It offers only methods that operate on public data that is freely available to anyone.
|
||||
type PublicHarmonyAPI struct { |
||||
b *core.BlockChain |
||||
} |
||||
|
||||
// TODO(ricl): update the following two functions.
|
||||
|
||||
// ProtocolVersion returns the current Harmony protocol version this node supports
|
||||
func (s *PublicHarmonyAPI) ProtocolVersion() hexutil.Uint { |
||||
return hexutil.Uint(proto.ProtocolVersion) |
||||
} |
||||
|
||||
// Syncing returns false in case the node is currently not syncing with the network. It can be up to date or has not
|
||||
// yet received the latest block headers from its pears. In case it is synchronizing:
|
||||
// - startingBlock: block number this node started to synchronise from
|
||||
// - currentBlock: block number this node is currently importing
|
||||
// - highestBlock: block number of the highest block header this node has received from peers
|
||||
// - pulledStates: number of state entries processed until now
|
||||
// - knownStates: number of known state entries that still need to be pulled
|
||||
func (s *PublicHarmonyAPI) Syncing() (interface{}, error) { |
||||
// TODO(ricl): port
|
||||
return false, nil |
||||
} |
||||
|
||||
// PublicNetAPI offers network related RPC methods
|
||||
type PublicNetAPI struct { |
||||
net *p2p.Server |
||||
networkVersion uint64 |
||||
} |
||||
|
||||
// NewPublicNetAPI creates a new net API instance.
|
||||
func NewPublicNetAPI(net *p2p.Server, networkVersion uint64) *PublicNetAPI { |
||||
return &PublicNetAPI{net, networkVersion} |
||||
} |
||||
|
||||
// PeerCount returns the number of connected peers
|
||||
func (s *PublicNetAPI) PeerCount() hexutil.Uint { |
||||
return hexutil.Uint(s.net.PeerCount()) |
||||
} |
||||
|
||||
// PublicTransactionPoolAPI exposes methods for the RPC interface
|
||||
type PublicTransactionPoolAPI struct { |
||||
b *core.HmyAPIBackend |
||||
nonceLock *AddrLocker |
||||
} |
||||
|
||||
// NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool.
|
||||
func NewPublicTransactionPoolAPI(b *core.HmyAPIBackend, nonceLock *AddrLocker) *PublicTransactionPoolAPI { |
||||
return &PublicTransactionPoolAPI{b, nonceLock} |
||||
} |
||||
|
||||
// GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number.
|
||||
func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { |
||||
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { |
||||
n := hexutil.Uint(len(block.Transactions())) |
||||
return &n |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash.
|
||||
func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { |
||||
if block, _ := s.b.GetBlock(ctx, blockHash); block != nil { |
||||
n := hexutil.Uint(len(block.Transactions())) |
||||
return &n |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index.
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction { |
||||
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { |
||||
return newRPCTransactionFromBlockIndex(block, uint64(index)) |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index.
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction { |
||||
if block, _ := s.b.GetBlock(ctx, blockHash); block != nil { |
||||
return newRPCTransactionFromBlockIndex(block, uint64(index)) |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// GetTransactionByHash returns the transaction for the given hash
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) *RPCTransaction { |
||||
// Try to return an already finalized transaction
|
||||
if tx, blockHash, blockNumber, index := rawdb.ReadTransaction(s.b.ChainDb(), hash); tx != nil { |
||||
return newRPCTransaction(tx, blockHash, blockNumber, index) |
||||
} |
||||
// No finalized transaction, try to retrieve it from the pool
|
||||
if tx := s.b.GetPoolTransaction(hash); tx != nil { |
||||
return newRPCPendingTransaction(tx) |
||||
} |
||||
// Transaction unknown, return as such
|
||||
return nil |
||||
} |
||||
|
||||
// GetCode returns the code stored at the given address in the state for the given block number.
|
||||
func (s *PublicBlockChainAPI) GetCode(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (hexutil.Bytes, error) { |
||||
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) |
||||
if state == nil || err != nil { |
||||
return nil, err |
||||
} |
||||
code := state.GetCode(address) |
||||
return code, state.Error() |
||||
} |
||||
|
||||
// GetStorageAt returns the storage from the state at the given address, key and
|
||||
// block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta block
|
||||
// numbers are also allowed.
|
||||
func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.Address, key string, blockNr rpc.BlockNumber) (hexutil.Bytes, error) { |
||||
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) |
||||
if state == nil || err != nil { |
||||
return nil, err |
||||
} |
||||
res := state.GetState(address, common.HexToHash(key)) |
||||
return res[:], state.Error() |
||||
} |
||||
|
||||
// GetTransactionCount returns the number of transactions the given address has sent for the given block number
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*hexutil.Uint64, error) { |
||||
// Ask transaction pool for the nonce which includes pending transactions
|
||||
if blockNr == rpc.PendingBlockNumber { |
||||
nonce, err := s.b.GetPoolNonce(ctx, address) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return (*hexutil.Uint64)(&nonce), nil |
||||
} |
||||
// Resolve block number and use its state to ask for the nonce
|
||||
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) |
||||
if state == nil || err != nil { |
||||
return nil, err |
||||
} |
||||
nonce := state.GetNonce(address) |
||||
return (*hexutil.Uint64)(&nonce), state.Error() |
||||
} |
@ -0,0 +1,84 @@ |
||||
package hmyapi |
||||
|
||||
import ( |
||||
"bytes" |
||||
"context" |
||||
"errors" |
||||
"math/big" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/common/hexutil" |
||||
"github.com/harmony-one/harmony/core" |
||||
"github.com/harmony-one/harmony/core/types" |
||||
) |
||||
|
||||
// SendTxArgs represents the arguments to sumbit a new transaction into the transaction pool.
|
||||
type SendTxArgs struct { |
||||
From common.Address `json:"from"` |
||||
To *common.Address `json:"to"` |
||||
ShardID uint32 `json:"shardID` |
||||
Gas *hexutil.Uint64 `json:"gas"` |
||||
GasPrice *hexutil.Big `json:"gasPrice"` |
||||
Value *hexutil.Big `json:"value"` |
||||
Nonce *hexutil.Uint64 `json:"nonce"` |
||||
// We accept "data" and "input" for backwards-compatibility reasons. "input" is the
|
||||
// newer name and should be preferred by clients.
|
||||
Data *hexutil.Bytes `json:"data"` |
||||
Input *hexutil.Bytes `json:"input"` |
||||
} |
||||
|
||||
// setDefaults is a helper function that fills in default values for unspecified tx fields.
|
||||
func (args *SendTxArgs) setDefaults(ctx context.Context, b *core.HmyAPIBackend) error { |
||||
if args.Gas == nil { |
||||
args.Gas = new(hexutil.Uint64) |
||||
*(*uint64)(args.Gas) = 90000 |
||||
} |
||||
// TODO(ricl): add check for shardID
|
||||
if args.GasPrice == nil { |
||||
// TODO(ricl): port
|
||||
// price, err := b.SuggestPrice(ctx)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
// args.GasPrice = (*hexutil.Big)(price)
|
||||
} |
||||
if args.Value == nil { |
||||
args.Value = new(hexutil.Big) |
||||
} |
||||
if args.Nonce == nil { |
||||
nonce, err := b.GetPoolNonce(ctx, args.From) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
args.Nonce = (*hexutil.Uint64)(&nonce) |
||||
} |
||||
if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) { |
||||
return errors.New(`both "data" and "input" are set and not equal. Please use "input" to pass transaction call data`) |
||||
} |
||||
if args.To == nil { |
||||
// Contract creation
|
||||
var input []byte |
||||
if args.Data != nil { |
||||
input = *args.Data |
||||
} else if args.Input != nil { |
||||
input = *args.Input |
||||
} |
||||
if len(input) == 0 { |
||||
return errors.New(`contract creation without any data provided`) |
||||
} |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (args *SendTxArgs) toTransaction() *types.Transaction { |
||||
var input []byte |
||||
if args.Data != nil { |
||||
input = *args.Data |
||||
} else if args.Input != nil { |
||||
input = *args.Input |
||||
} |
||||
if args.To == nil { |
||||
return types.NewContractCreation(uint64(*args.Nonce), args.ShardID, (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input) |
||||
} |
||||
return types.NewTransaction(uint64(*args.Nonce), *args.To, args.ShardID, (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input) |
||||
} |
@ -0,0 +1,134 @@ |
||||
package hmyapi |
||||
|
||||
import ( |
||||
"context" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/common/hexutil" |
||||
"github.com/ethereum/go-ethereum/rlp" |
||||
"github.com/ethereum/go-ethereum/rpc" |
||||
"github.com/harmony-one/harmony/accounts" |
||||
"github.com/harmony-one/harmony/core" |
||||
"github.com/harmony-one/harmony/core/rawdb" |
||||
"github.com/harmony-one/harmony/core/types" |
||||
) |
||||
|
||||
// PublicTransactionPoolAPI exposes methods for the RPC interface
|
||||
type PublicTransactionPoolAPI struct { |
||||
b *core.HmyAPIBackend |
||||
nonceLock *AddrLocker |
||||
} |
||||
|
||||
// NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool.
|
||||
func NewPublicTransactionPoolAPI(b *core.HmyAPIBackend, nonceLock *AddrLocker) *PublicTransactionPoolAPI { |
||||
return &PublicTransactionPoolAPI{b, nonceLock} |
||||
} |
||||
|
||||
// GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number.
|
||||
func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByNumber(ctx context.Context, blockNr rpc.BlockNumber) *hexutil.Uint { |
||||
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { |
||||
n := hexutil.Uint(len(block.Transactions())) |
||||
return &n |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// GetBlockTransactionCountByHash returns the number of transactions in the block with the given hash.
|
||||
func (s *PublicTransactionPoolAPI) GetBlockTransactionCountByHash(ctx context.Context, blockHash common.Hash) *hexutil.Uint { |
||||
if block, _ := s.b.GetBlock(ctx, blockHash); block != nil { |
||||
n := hexutil.Uint(len(block.Transactions())) |
||||
return &n |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// GetTransactionByBlockNumberAndIndex returns the transaction for the given block number and index.
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionByBlockNumberAndIndex(ctx context.Context, blockNr rpc.BlockNumber, index hexutil.Uint) *RPCTransaction { |
||||
if block, _ := s.b.BlockByNumber(ctx, blockNr); block != nil { |
||||
return newRPCTransactionFromBlockIndex(block, uint64(index)) |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// GetTransactionByBlockHashAndIndex returns the transaction for the given block hash and index.
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionByBlockHashAndIndex(ctx context.Context, blockHash common.Hash, index hexutil.Uint) *RPCTransaction { |
||||
if block, _ := s.b.GetBlock(ctx, blockHash); block != nil { |
||||
return newRPCTransactionFromBlockIndex(block, uint64(index)) |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// GetTransactionByHash returns the transaction for the given hash
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionByHash(ctx context.Context, hash common.Hash) *RPCTransaction { |
||||
// Try to return an already finalized transaction
|
||||
if tx, blockHash, blockNumber, index := rawdb.ReadTransaction(s.b.ChainDb(), hash); tx != nil { |
||||
return newRPCTransaction(tx, blockHash, blockNumber, index) |
||||
} |
||||
// No finalized transaction, try to retrieve it from the pool
|
||||
if tx := s.b.GetPoolTransaction(hash); tx != nil { |
||||
return newRPCPendingTransaction(tx) |
||||
} |
||||
// Transaction unknown, return as such
|
||||
return nil |
||||
} |
||||
|
||||
// GetTransactionCount returns the number of transactions the given address has sent for the given block number
|
||||
func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*hexutil.Uint64, error) { |
||||
// Ask transaction pool for the nonce which includes pending transactions
|
||||
if blockNr == rpc.PendingBlockNumber { |
||||
nonce, err := s.b.GetPoolNonce(ctx, address) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return (*hexutil.Uint64)(&nonce), nil |
||||
} |
||||
// Resolve block number and use its state to ask for the nonce
|
||||
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) |
||||
if state == nil || err != nil { |
||||
return nil, err |
||||
} |
||||
nonce := state.GetNonce(address) |
||||
return (*hexutil.Uint64)(&nonce), state.Error() |
||||
} |
||||
|
||||
// SendTransaction creates a transaction for the given argument, sign it and submit it to the
|
||||
// transaction pool.
|
||||
func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args SendTxArgs) (common.Hash, error) { |
||||
// Look up the wallet containing the requested signer
|
||||
account := accounts.Account{Address: args.From} |
||||
|
||||
wallet, err := s.b.AccountManager().Find(account) |
||||
if err != nil { |
||||
return common.Hash{}, err |
||||
} |
||||
|
||||
if args.Nonce == nil { |
||||
// Hold the addresse's mutex around signing to prevent concurrent assignment of
|
||||
// the same nonce to multiple accounts.
|
||||
s.nonceLock.LockAddr(args.From) |
||||
defer s.nonceLock.UnlockAddr(args.From) |
||||
} |
||||
|
||||
// Set some sanity defaults and terminate on failure
|
||||
if err := args.setDefaults(ctx, s.b); err != nil { |
||||
return common.Hash{}, err |
||||
} |
||||
// Assemble the transaction and sign with the wallet
|
||||
tx := args.toTransaction() |
||||
|
||||
signed, err := wallet.SignTx(account, tx, s.b.ChainConfig().ChainID) |
||||
if err != nil { |
||||
return common.Hash{}, err |
||||
} |
||||
return SubmitTransaction(ctx, s.b, signed) |
||||
} |
||||
|
||||
// SendRawTransaction will add the signed transaction to the transaction pool.
|
||||
// The sender is responsible for signing the transaction and using the correct nonce.
|
||||
func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encodedTx hexutil.Bytes) (common.Hash, error) { |
||||
tx := new(types.Transaction) |
||||
if err := rlp.DecodeBytes(encodedTx, tx); err != nil { |
||||
return common.Hash{}, err |
||||
} |
||||
return SubmitTransaction(ctx, s.b, tx) |
||||
} |
@ -0,0 +1,30 @@ |
||||
package hmyapi |
||||
|
||||
import ( |
||||
"context" |
||||
|
||||
"github.com/ethereum/go-ethereum/common" |
||||
"github.com/ethereum/go-ethereum/crypto" |
||||
"github.com/ethereum/go-ethereum/log" |
||||
"github.com/harmony-one/harmony/core" |
||||
"github.com/harmony-one/harmony/core/types" |
||||
) |
||||
|
||||
// SubmitTransaction is a helper function that submits tx to txPool and logs a message.
|
||||
func SubmitTransaction(ctx context.Context, b *core.HmyAPIBackend, tx *types.Transaction) (common.Hash, error) { |
||||
if err := b.SendTx(ctx, tx); err != nil { |
||||
return common.Hash{}, err |
||||
} |
||||
if tx.To() == nil { |
||||
signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number()) |
||||
from, err := types.Sender(signer, tx) |
||||
if err != nil { |
||||
return common.Hash{}, err |
||||
} |
||||
addr := crypto.CreateAddress(from, tx.Nonce()) |
||||
log.Info("Submitted contract creation", "fullhash", tx.Hash().Hex(), "contract", addr.Hex()) |
||||
} else { |
||||
log.Info("Submitted transaction", "fullhash", tx.Hash().Hex(), "recipient", tx.To()) |
||||
} |
||||
return tx.Hash(), nil |
||||
} |
Loading…
Reference in new issue