feat(rpc): add json rpc
This commit is contained in:
parent
d27fa23065
commit
da866a34fe
|
@ -0,0 +1,61 @@
|
|||
package jsonrpc
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/meshplus/bitxhub/api/jsonrpc/namespaces/eth"
|
||||
"github.com/meshplus/bitxhub/api/jsonrpc/namespaces/net"
|
||||
"github.com/meshplus/bitxhub/api/jsonrpc/namespaces/web3"
|
||||
"github.com/meshplus/bitxhub/internal/coreapi/api"
|
||||
"github.com/meshplus/bitxhub/internal/repo"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// RPC namespaces and API version
|
||||
const (
|
||||
Web3Namespace = "web3"
|
||||
EthNamespace = "eth"
|
||||
PersonalNamespace = "personal"
|
||||
NetNamespace = "net"
|
||||
flagRPCAPI = "rpc-api"
|
||||
|
||||
apiVersion = "1.0"
|
||||
)
|
||||
|
||||
// GetAPIs returns the list of all APIs from the Ethereum namespaces
|
||||
func GetAPIs(config *repo.Config, api api.CoreAPI, logger logrus.FieldLogger) ([]rpc.API, error) {
|
||||
var apis []rpc.API
|
||||
|
||||
ethAPI, err := eth.NewAPI(config, api, logger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
apis = append(apis,
|
||||
rpc.API{
|
||||
Namespace: EthNamespace,
|
||||
Version: apiVersion,
|
||||
Service: ethAPI,
|
||||
Public: true,
|
||||
},
|
||||
)
|
||||
|
||||
apis = append(apis,
|
||||
rpc.API{
|
||||
Namespace: Web3Namespace,
|
||||
Version: apiVersion,
|
||||
Service: web3.NewAPI(),
|
||||
Public: true,
|
||||
},
|
||||
)
|
||||
|
||||
apis = append(apis,
|
||||
rpc.API{
|
||||
Namespace: NetNamespace,
|
||||
Version: apiVersion,
|
||||
Service: net.NewAPI(config),
|
||||
Public: true,
|
||||
},
|
||||
)
|
||||
|
||||
return apis, nil
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package jsonrpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/ethereum/go-ethereum/rpc"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/meshplus/bitxhub/internal/coreapi/api"
|
||||
"github.com/meshplus/bitxhub/internal/loggers"
|
||||
"github.com/meshplus/bitxhub/internal/repo"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type ChainBrokerService struct {
|
||||
config *repo.Config
|
||||
genesis *repo.Genesis
|
||||
api api.CoreAPI
|
||||
server *rpc.Server
|
||||
logger logrus.FieldLogger
|
||||
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
}
|
||||
|
||||
func NewChainBrokerService(coreAPI api.CoreAPI, config *repo.Config) (*ChainBrokerService, error) {
|
||||
server := rpc.NewServer()
|
||||
|
||||
logger := loggers.Logger(loggers.API)
|
||||
|
||||
apis, err := GetAPIs(config, coreAPI, logger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Register all the APIs exposed by the namespace services
|
||||
for _, api := range apis {
|
||||
if err := server.RegisterName(api.Namespace, api.Service); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
return &ChainBrokerService{
|
||||
logger: logger,
|
||||
config: config,
|
||||
api: coreAPI,
|
||||
server: server,
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (cbs *ChainBrokerService) Start() error {
|
||||
router := mux.NewRouter()
|
||||
router.Handle("/", cbs.server)
|
||||
|
||||
go func() {
|
||||
if err := http.ListenAndServe(fmt.Sprintf(":%d", cbs.config.Port.JsonRpc), router); err != nil {
|
||||
cbs.logger.WithFields(logrus.Fields{
|
||||
"error": err.Error(),
|
||||
}).Error("Failed to start JSON_RPC service")
|
||||
return
|
||||
}
|
||||
|
||||
cbs.logger.WithFields(logrus.Fields{
|
||||
"port": cbs.config.Port.JsonRpc,
|
||||
}).Info("JSON-RPC service started")
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cbs *ChainBrokerService) Stop() error {
|
||||
cbs.cancel()
|
||||
|
||||
cbs.logger.Info("GRPC service stopped")
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,279 @@
|
|||
package eth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/meshplus/bitxhub-kit/types"
|
||||
types2 "github.com/meshplus/bitxhub/api/jsonrpc/types"
|
||||
"github.com/meshplus/bitxhub/internal/coreapi/api"
|
||||
"github.com/meshplus/bitxhub/internal/repo"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// PublicEthereumAPI is the eth_ prefixed set of APIs in the Web3 JSON-RPC spec.
|
||||
type PublicEthereumAPI struct {
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
chainIDEpoch *big.Int
|
||||
logger logrus.FieldLogger
|
||||
api api.CoreAPI
|
||||
}
|
||||
|
||||
// NewAPI creates an instance of the public ETH Web3 API.
|
||||
func NewAPI(config *repo.Config, api api.CoreAPI, logger logrus.FieldLogger) (*PublicEthereumAPI, error) {
|
||||
epoch, err := types2.ParseChainID(config.Genesis.ChainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
return &PublicEthereumAPI{
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
chainIDEpoch: epoch,
|
||||
logger: logger,
|
||||
api: api,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ProtocolVersion returns the supported Ethereum protocol version.
|
||||
func (api *PublicEthereumAPI) ProtocolVersion() hexutil.Uint {
|
||||
api.logger.Debug("eth_protocolVersion")
|
||||
return hexutil.Uint(types2.ProtocolVersion)
|
||||
}
|
||||
|
||||
// ChainId returns the chain's identifier in hex format
|
||||
func (api *PublicEthereumAPI) ChainId() (hexutil.Uint, error) { // nolint
|
||||
api.logger.Debug("eth_chainId")
|
||||
return hexutil.Uint(uint(api.chainIDEpoch.Uint64())), nil
|
||||
}
|
||||
|
||||
// Syncing returns whether or not the current node is syncing with other peers. Returns false if not, or a struct
|
||||
// outlining the state of the sync if it is.
|
||||
func (api *PublicEthereumAPI) Syncing() (interface{}, error) {
|
||||
api.logger.Debug("eth_syncing")
|
||||
|
||||
// TODO
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Mining returns whether or not this node is currently mining. Always false.
|
||||
func (api *PublicEthereumAPI) Mining() bool {
|
||||
api.logger.Debug("eth_mining")
|
||||
return false
|
||||
}
|
||||
|
||||
// Hashrate returns the current node's hashrate. Always 0.
|
||||
func (api *PublicEthereumAPI) Hashrate() hexutil.Uint64 {
|
||||
api.logger.Debug("eth_hashrate")
|
||||
return 0
|
||||
}
|
||||
|
||||
// GasPrice returns the current gas price based on Ethermint's gas price oracle.
|
||||
func (api *PublicEthereumAPI) GasPrice() *hexutil.Big {
|
||||
api.logger.Debug("eth_gasPrice")
|
||||
out := big.NewInt(0)
|
||||
return (*hexutil.Big)(out)
|
||||
}
|
||||
|
||||
// BlockNumber returns the current block number.
|
||||
func (api *PublicEthereumAPI) BlockNumber() (hexutil.Uint64, error) {
|
||||
api.logger.Debug("eth_blockNumber")
|
||||
meta, err := api.api.Chain().Meta()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return hexutil.Uint64(meta.Height), nil
|
||||
}
|
||||
|
||||
// GetBalance returns the provided account's balance up to the provided block number.
|
||||
func (api *PublicEthereumAPI) GetBalance(address common.Address, blockNum types2.BlockNumber) (*hexutil.Big, error) {
|
||||
api.logger.Debug("eth_getBalance", "address", address, "block number", blockNum)
|
||||
|
||||
if blockNum != types2.LatestBlockNumber {
|
||||
return nil, fmt.Errorf("only support query for latest block number")
|
||||
}
|
||||
|
||||
account := api.api.Account().GetAccount(types.NewAddress(address.Bytes()))
|
||||
|
||||
balance := account.GetBalance()
|
||||
|
||||
return (*hexutil.Big)(big.NewInt(int64(balance))), nil
|
||||
}
|
||||
|
||||
// GetStorageAt returns the contract storage at the given address, block number, and key.
|
||||
func (api *PublicEthereumAPI) GetStorageAt(address common.Address, key string, blockNum types2.BlockNumber) (hexutil.Bytes, error) {
|
||||
api.logger.Debug("eth_getStorageAt", "address", address, "key", key, "block number", blockNum)
|
||||
|
||||
if blockNum != types2.LatestBlockNumber {
|
||||
return nil, fmt.Errorf("only support query for latest block number")
|
||||
}
|
||||
|
||||
account := api.api.Account().GetAccount(types.NewAddress(address.Bytes()))
|
||||
|
||||
ok, val := account.GetState([]byte(key))
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return val, nil
|
||||
}
|
||||
|
||||
// GetTransactionCount returns the number of transactions at the given address up to the given block number.
|
||||
func (api *PublicEthereumAPI) GetTransactionCount(address common.Address, blockNum types2.BlockNumber) (*hexutil.Uint64, error) {
|
||||
api.logger.Debug("eth_getTransactionCount", "address", address, "block number", blockNum)
|
||||
|
||||
if blockNum != types2.LatestBlockNumber {
|
||||
return nil, fmt.Errorf("only support query for latest block number")
|
||||
}
|
||||
|
||||
account := api.api.Account().GetAccount(types.NewAddress(address.Bytes()))
|
||||
|
||||
nonce := account.GetNonce()
|
||||
|
||||
return (*hexutil.Uint64)(&nonce), nil
|
||||
}
|
||||
|
||||
// GetBlockTransactionCountByHash returns the number of transactions in the block identified by hash.
|
||||
func (api *PublicEthereumAPI) GetBlockTransactionCountByHash(hash common.Hash) *hexutil.Uint {
|
||||
api.logger.Debug("eth_getBlockTransactionCountByHash", "hash", hash)
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetBlockTransactionCountByNumber returns the number of transactions in the block identified by its height.
|
||||
func (api *PublicEthereumAPI) GetBlockTransactionCountByNumber(blockNum uint64) *hexutil.Uint {
|
||||
api.logger.Debug("eth_getBlockTransactionCountByNumber", "block number", blockNum)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetUncleCountByBlockHash returns the number of uncles in the block idenfied by hash. Always zero.
|
||||
func (api *PublicEthereumAPI) GetUncleCountByBlockHash(_ common.Hash) hexutil.Uint {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (api *PublicEthereumAPI) GetUncleCountByBlockNumber(_ uint64) hexutil.Uint {
|
||||
return 0
|
||||
}
|
||||
|
||||
// GetCode returns the contract code at the given address and block number.
|
||||
func (api *PublicEthereumAPI) GetCode(address common.Address, blockNumber types2.BlockNumber) (hexutil.Bytes, error) {
|
||||
api.logger.Debug("eth_getCode", "address", address, "block number", blockNumber)
|
||||
|
||||
if blockNumber != types2.LatestBlockNumber {
|
||||
return nil, fmt.Errorf("only support query for latest block number")
|
||||
}
|
||||
|
||||
account := api.api.Account().GetAccount(types.NewAddress(address.Bytes()))
|
||||
|
||||
code := account.Code()
|
||||
|
||||
return code, nil
|
||||
}
|
||||
|
||||
// GetTransactionLogs returns the logs given a transaction hash.
|
||||
func (api *PublicEthereumAPI) GetTransactionLogs(txHash common.Hash) ([]*ethtypes.Log, error) {
|
||||
api.logger.Debug("eth_getTransactionLogs", "hash", txHash)
|
||||
// TODO
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// SendRawTransaction send a raw Ethereum transaction.
|
||||
func (api *PublicEthereumAPI) SendRawTransaction(data hexutil.Bytes) (common.Hash, error) {
|
||||
api.logger.Debug("eth_sendRawTransaction", "data", data)
|
||||
|
||||
// TODO
|
||||
|
||||
return common.Hash{}, nil
|
||||
}
|
||||
|
||||
// Call performs a raw contract call.
|
||||
func (api *PublicEthereumAPI) Call(args types2.CallArgs, blockNr uint64, _ *map[common.Address]types2.Account) (hexutil.Bytes, error) {
|
||||
api.logger.Debug("eth_call", "args", args, "block number", blockNr)
|
||||
// TODO
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// EstimateGas returns an estimate of gas usage for the given smart contract call.
|
||||
// It adds 1,000 gas to the returned value instead of using the gas adjustment
|
||||
// param from the SDK.
|
||||
func (api *PublicEthereumAPI) EstimateGas(args types2.CallArgs) (hexutil.Uint64, error) {
|
||||
api.logger.Debug("eth_estimateGas", "args", args)
|
||||
// TODO
|
||||
|
||||
return hexutil.Uint64(1000), nil
|
||||
}
|
||||
|
||||
// GetBlockByHash returns the block identified by hash.
|
||||
func (api *PublicEthereumAPI) GetBlockByHash(hash common.Hash, fullTx bool) (map[string]interface{}, error) {
|
||||
api.logger.Debug("eth_getBlockByHash", "hash", hash, "full", fullTx)
|
||||
// TODO
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetBlockByNumber returns the block identified by number.
|
||||
func (api *PublicEthereumAPI) GetBlockByNumber(blockNum uint64, fullTx bool) (map[string]interface{}, error) {
|
||||
api.logger.Debug("eth_getBlockByNumber", "number", blockNum, "full", fullTx)
|
||||
// TODO
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetTransactionByHash returns the transaction identified by hash.
|
||||
func (api *PublicEthereumAPI) GetTransactionByHash(hash common.Hash) (*types2.Transaction, error) {
|
||||
api.logger.Debug("eth_getTransactionByHash", "hash", hash)
|
||||
// TODO
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetTransactionByBlockHashAndIndex returns the transaction identified by hash and index.
|
||||
func (api *PublicEthereumAPI) GetTransactionByBlockHashAndIndex(hash common.Hash, idx hexutil.Uint) (*types2.Transaction, error) {
|
||||
api.logger.Debug("eth_getTransactionByHashAndIndex", "hash", hash, "index", idx)
|
||||
// TODO
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetTransactionByBlockNumberAndIndex returns the transaction identified by number and index.
|
||||
func (api *PublicEthereumAPI) GetTransactionByBlockNumberAndIndex(blockNum uint64, idx hexutil.Uint) (*types2.Transaction, error) {
|
||||
api.logger.Debug("eth_getTransactionByBlockNumberAndIndex", "number", blockNum, "index", idx)
|
||||
// TODO
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetTransactionReceipt returns the transaction receipt identified by hash.
|
||||
func (api *PublicEthereumAPI) GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error) {
|
||||
api.logger.Debug("eth_getTransactionReceipt", "hash", hash)
|
||||
// TODO
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// PendingTransactions returns the transactions that are in the transaction pool
|
||||
// and have a from address that is one of the accounts this node manages.
|
||||
func (api *PublicEthereumAPI) PendingTransactions() ([]*types2.Transaction, error) {
|
||||
api.logger.Debug("eth_pendingTransactions")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// GetUncleByBlockHashAndIndex returns the uncle identified by hash and index. Always returns nil.
|
||||
func (api *PublicEthereumAPI) GetUncleByBlockHashAndIndex(hash common.Hash, idx hexutil.Uint) map[string]interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetUncleByBlockNumberAndIndex returns the uncle identified by number and index. Always returns nil.
|
||||
func (api *PublicEthereumAPI) GetUncleByBlockNumberAndIndex(number hexutil.Uint, idx hexutil.Uint) map[string]interface{} {
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package net
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/meshplus/bitxhub/api/jsonrpc/types"
|
||||
"github.com/meshplus/bitxhub/internal/repo"
|
||||
)
|
||||
|
||||
// PublicNetAPI is the eth_ prefixed set of APIs in the Web3 JSON-RPC spec.
|
||||
type PublicNetAPI struct {
|
||||
networkVersion uint64
|
||||
}
|
||||
|
||||
// NewAPI creates an instance of the public Net Web3 API.
|
||||
func NewAPI(config *repo.Config) *PublicNetAPI {
|
||||
// parse the chainID from a integer string
|
||||
chainIDEpoch, err := types.ParseChainID(config.ChainID)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return &PublicNetAPI{
|
||||
networkVersion: chainIDEpoch.Uint64(),
|
||||
}
|
||||
}
|
||||
|
||||
// Version returns the current ethereum protocol version.
|
||||
func (api *PublicNetAPI) Version() string {
|
||||
return fmt.Sprintf("%d", api.networkVersion)
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package web3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
"github.com/meshplus/bitxhub"
|
||||
)
|
||||
|
||||
// PublicWeb3API is the web3_ prefixed set of APIs in the Web3 JSON-RPC spec.
|
||||
type PublicWeb3API struct{}
|
||||
|
||||
// NewAPI creates an instance of the Web3 API.
|
||||
func NewAPI() *PublicWeb3API {
|
||||
return &PublicWeb3API{}
|
||||
}
|
||||
|
||||
// ClientVersion returns the client version in the Web3 user agent format.
|
||||
func (PublicWeb3API) ClientVersion() string {
|
||||
return fmt.Sprintf("%s-%s-%s", bitxhub.CurrentVersion, bitxhub.CurrentBranch, bitxhub.CurrentCommit)
|
||||
}
|
||||
|
||||
// Sha3 returns the keccak-256 hash of the passed-in input.
|
||||
func (PublicWeb3API) Sha3(input hexutil.Bytes) hexutil.Bytes {
|
||||
return crypto.Keccak256(input)
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
// AddrLocker is a mutex structure used to avoid querying outdated account data
|
||||
type AddrLocker struct {
|
||||
mu sync.Mutex
|
||||
locks map[common.Address]*sync.Mutex
|
||||
}
|
||||
|
||||
// lock returns the lock of the given address.
|
||||
func (l *AddrLocker) lock(address common.Address) *sync.Mutex {
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
if l.locks == nil {
|
||||
l.locks = make(map[common.Address]*sync.Mutex)
|
||||
}
|
||||
if _, ok := l.locks[address]; !ok {
|
||||
l.locks[address] = new(sync.Mutex)
|
||||
}
|
||||
return l.locks[address]
|
||||
}
|
||||
|
||||
// LockAddr locks an account's mutex. This is used to prevent another tx getting the
|
||||
// same nonce until the lock is released. The mutex prevents the (an identical nonce) from
|
||||
// being read again during the time that the first transaction is being signed.
|
||||
func (l *AddrLocker) LockAddr(address common.Address) {
|
||||
l.lock(address).Lock()
|
||||
}
|
||||
|
||||
// UnlockAddr unlocks the mutex of the given account.
|
||||
func (l *AddrLocker) UnlockAddr(address common.Address) {
|
||||
l.lock(address).Unlock()
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
)
|
||||
|
||||
// BlockNumber represents decoding hex string to block values
|
||||
type BlockNumber int64
|
||||
|
||||
const (
|
||||
// LatestBlockNumber mapping from "latest" to 0 for tm query
|
||||
LatestBlockNumber = BlockNumber(0)
|
||||
|
||||
// EarliestBlockNumber mapping from "earliest" to 1 for tm query (earliest query not supported)
|
||||
EarliestBlockNumber = BlockNumber(1)
|
||||
|
||||
// PendingBlockNumber mapping from "pending" to -1 for tm query
|
||||
PendingBlockNumber = BlockNumber(-1)
|
||||
)
|
||||
|
||||
// NewBlockNumber creates a new BlockNumber instance.
|
||||
func NewBlockNumber(n *big.Int) BlockNumber {
|
||||
return BlockNumber(n.Int64())
|
||||
}
|
||||
|
||||
// UnmarshalJSON parses the given JSON fragment into a BlockNumber. It supports:
|
||||
// - "latest", "earliest" or "pending" as string arguments
|
||||
// - the block number
|
||||
// Returned errors:
|
||||
// - an invalid block number error when the given argument isn't a known strings
|
||||
// - an out of range error when the given block number is either too little or too large
|
||||
func (bn *BlockNumber) UnmarshalJSON(data []byte) error {
|
||||
input := strings.TrimSpace(string(data))
|
||||
if len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' {
|
||||
input = input[1 : len(input)-1]
|
||||
}
|
||||
|
||||
switch input {
|
||||
case "earliest":
|
||||
*bn = EarliestBlockNumber
|
||||
return nil
|
||||
case "latest":
|
||||
*bn = LatestBlockNumber
|
||||
return nil
|
||||
case "pending":
|
||||
*bn = PendingBlockNumber
|
||||
return nil
|
||||
}
|
||||
|
||||
blckNum, err := hexutil.DecodeUint64(input)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if blckNum > math.MaxInt64 {
|
||||
return fmt.Errorf("blocknumber too high")
|
||||
}
|
||||
|
||||
*bn = BlockNumber(blckNum)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Int64 converts block number to primitive type
|
||||
func (bn BlockNumber) Int64() int64 {
|
||||
return int64(bn)
|
||||
}
|
||||
|
||||
// TmHeight is a util function used for the Tendermint RPC client. It returns
|
||||
// nil if the block number is "latest". Otherwise, it returns the pointer of the
|
||||
// int64 value of the height.
|
||||
func (bn BlockNumber) TmHeight() *int64 {
|
||||
if bn == LatestBlockNumber {
|
||||
return nil
|
||||
}
|
||||
height := bn.Int64()
|
||||
return &height
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
regexChainID = `[a-z]*`
|
||||
regexSeparator = `-{1}`
|
||||
regexEpoch = `[1-9][0-9]*`
|
||||
ethermintChainID = regexp.MustCompile(fmt.Sprintf(`^(%s)%s(%s)$`, regexChainID, regexSeparator, regexEpoch))
|
||||
)
|
||||
|
||||
// IsValidChainID returns false if the given chain identifier is incorrectly formatted.
|
||||
func IsValidChainID(chainID string) bool {
|
||||
if len(chainID) > 48 {
|
||||
return false
|
||||
}
|
||||
|
||||
return ethermintChainID.MatchString(chainID)
|
||||
}
|
||||
|
||||
// ParseChainID parses a string chain identifier's epoch to an Ethereum-compatible
|
||||
// chain-id in *big.Int format. The function returns an error if the chain-id has an invalid format
|
||||
func ParseChainID(chainID string) (*big.Int, error) {
|
||||
chainID = strings.TrimSpace(chainID)
|
||||
if len(chainID) > 48 {
|
||||
return nil, fmt.Errorf("chain-id '%s' cannot exceed 48 chars", chainID)
|
||||
}
|
||||
|
||||
matches := ethermintChainID.FindStringSubmatch(chainID)
|
||||
if matches == nil || len(matches) != 3 || matches[1] == "" {
|
||||
return nil, fmt.Errorf("invalid chain-id: %s", chainID)
|
||||
}
|
||||
|
||||
// verify that the chain-id entered is a base 10 integer
|
||||
chainIDInt, ok := new(big.Int).SetString(matches[2], 10)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid chain-id, epoch %s must be base-10 integer format", matches[2])
|
||||
}
|
||||
|
||||
return chainIDInt, nil
|
||||
}
|
||||
|
||||
// GenerateRandomChainID returns a random chain-id in the valid format.
|
||||
func GenerateRandomChainID() string {
|
||||
return fmt.Sprintf("ethermint-%d", 10+rand.Intn(10000))
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
)
|
||||
|
||||
// Copied the Account and StorageResult types since they are registered under an
|
||||
// internal pkg on geth.
|
||||
|
||||
// Constants to match up protocol versions and messages
|
||||
const (
|
||||
eth65 = 65
|
||||
|
||||
// ProtocolVersion is the latest supported version of the eth protocol.
|
||||
ProtocolVersion = eth65
|
||||
)
|
||||
|
||||
// AccountResult struct for account proof
|
||||
type AccountResult struct {
|
||||
Address common.Address `json:"address"`
|
||||
AccountProof []string `json:"accountProof"`
|
||||
Balance *hexutil.Big `json:"balance"`
|
||||
CodeHash common.Hash `json:"codeHash"`
|
||||
Nonce hexutil.Uint64 `json:"nonce"`
|
||||
StorageHash common.Hash `json:"storageHash"`
|
||||
StorageProof []StorageResult `json:"storageProof"`
|
||||
}
|
||||
|
||||
// StorageResult defines the format for storage proof return
|
||||
type StorageResult struct {
|
||||
Key string `json:"key"`
|
||||
Value *hexutil.Big `json:"value"`
|
||||
Proof []string `json:"proof"`
|
||||
}
|
||||
|
||||
// Transaction represents a transaction returned to RPC clients.
|
||||
type Transaction struct {
|
||||
BlockHash *common.Hash `json:"blockHash"`
|
||||
BlockNumber *hexutil.Big `json:"blockNumber"`
|
||||
From common.Address `json:"from"`
|
||||
Gas hexutil.Uint64 `json:"gas"`
|
||||
GasPrice *hexutil.Big `json:"gasPrice"`
|
||||
Hash common.Hash `json:"hash"`
|
||||
Input hexutil.Bytes `json:"input"`
|
||||
Nonce hexutil.Uint64 `json:"nonce"`
|
||||
To *common.Address `json:"to"`
|
||||
TransactionIndex *hexutil.Uint64 `json:"transactionIndex"`
|
||||
Value *hexutil.Big `json:"value"`
|
||||
V *hexutil.Big `json:"v"`
|
||||
R *hexutil.Big `json:"r"`
|
||||
S *hexutil.Big `json:"s"`
|
||||
}
|
||||
|
||||
// SendTxArgs represents the arguments to submit a new transaction into the transaction pool.
|
||||
// Duplicate struct definition since geth struct is in internal package
|
||||
// Ref: https://github.com/ethereum/go-ethereum/blob/release/1.9/internal/ethapi/api.go#L1346
|
||||
type SendTxArgs struct {
|
||||
From common.Address `json:"from"`
|
||||
To *common.Address `json:"to"`
|
||||
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"`
|
||||
}
|
||||
|
||||
// CallArgs represents the arguments for a call.
|
||||
type CallArgs struct {
|
||||
From *common.Address `json:"from"`
|
||||
To *common.Address `json:"to"`
|
||||
Gas *hexutil.Uint64 `json:"gas"`
|
||||
GasPrice *hexutil.Big `json:"gasPrice"`
|
||||
Value *hexutil.Big `json:"value"`
|
||||
Data *hexutil.Bytes `json:"data"`
|
||||
}
|
||||
|
||||
// Account indicates the overriding fields of account during the execution of
|
||||
// a message call.
|
||||
// NOTE: state and stateDiff can't be specified at the same time. If state is
|
||||
// set, message execution will only use the data in the given state. Otherwise
|
||||
// if statDiff is set, all diff will be applied first and then execute the call
|
||||
// message.
|
||||
type Account struct {
|
||||
Nonce *hexutil.Uint64 `json:"nonce"`
|
||||
Code *hexutil.Bytes `json:"code"`
|
||||
Balance **hexutil.Big `json:"balance"`
|
||||
State *map[common.Hash]common.Hash `json:"state"`
|
||||
StateDiff *map[common.Hash]common.Hash `json:"stateDiff"`
|
||||
}
|
|
@ -16,11 +16,11 @@ import (
|
|||
"github.com/meshplus/bitxhub-kit/log"
|
||||
"github.com/meshplus/bitxhub/api/gateway"
|
||||
"github.com/meshplus/bitxhub/api/grpc"
|
||||
"github.com/meshplus/bitxhub/api/jsonrpc"
|
||||
"github.com/meshplus/bitxhub/internal/app"
|
||||
"github.com/meshplus/bitxhub/internal/coreapi"
|
||||
"github.com/meshplus/bitxhub/internal/loggers"
|
||||
"github.com/meshplus/bitxhub/internal/repo"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
@ -96,6 +96,16 @@ func start(ctx *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// start json-rpc service
|
||||
cbs, err := jsonrpc.NewChainBrokerService(api, repo.Config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := cbs.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go func() {
|
||||
logger.WithField("port", repo.Config.Port.Gateway).Info("Gateway service started")
|
||||
err := gateway.Start(repo.Config)
|
||||
|
|
|
@ -3,6 +3,7 @@ title = "BitXHub configuration file"
|
|||
solo = false
|
||||
|
||||
[port]
|
||||
jsonrpc = 8881
|
||||
grpc = 60011
|
||||
gateway = 9091
|
||||
pprof = 53121
|
||||
|
@ -44,7 +45,7 @@ solo = false
|
|||
consensus = "info"
|
||||
executor = "info"
|
||||
router = "info"
|
||||
api = "info"
|
||||
api = "debug"
|
||||
coreapi = "info"
|
||||
storage = "info"
|
||||
|
||||
|
@ -61,6 +62,7 @@ solo = false
|
|||
type = "serial" # opensource version only supports serial type, commercial version supports serial and parallel types
|
||||
|
||||
[genesis]
|
||||
chainid = "a-1"
|
||||
dider = "0xc7F999b83Af6DF9e67d0a37Ee7e900bF38b3D013"
|
||||
[[genesis.admins]]
|
||||
address = "0xc7F999b83Af6DF9e67d0a37Ee7e900bF38b3D013"
|
||||
|
|
1
go.mod
1
go.mod
|
@ -15,6 +15,7 @@ require (
|
|||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/golang/mock v1.5.0
|
||||
github.com/google/btree v1.0.0
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.2.2
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0
|
||||
|
|
|
@ -53,6 +53,7 @@ type Security struct {
|
|||
}
|
||||
|
||||
type Port struct {
|
||||
JsonRpc int64 `toml:"jsonrpc" json:"jsonrpc"`
|
||||
Grpc int64 `toml:"grpc" json:"grpc"`
|
||||
Gateway int64 `toml:"gateway" json:"gateway"`
|
||||
PProf int64 `toml:"pprof" json:"pprof"`
|
||||
|
@ -104,6 +105,7 @@ type LogModule struct {
|
|||
}
|
||||
|
||||
type Genesis struct {
|
||||
ChainID string `json:"chainid" toml:"chainid"`
|
||||
Admins []*Admin `json:"admins" toml:"admins"`
|
||||
Strategy map[string]string `json:"strategy" toml:"strategy"`
|
||||
Dider string `json:"dider" toml:"dider"`
|
||||
|
|
|
@ -49,6 +49,7 @@ function prepare() {
|
|||
x_replace "s/9091/909${i}/g" "${bitxhubConfig}"
|
||||
x_replace "s/53121/5312${i}/g" "${bitxhubConfig}"
|
||||
x_replace "s/40011/4001${i}/g" "${bitxhubConfig}"
|
||||
x_replace "s/8881/888${i}/g" "${bitxhubConfig}"
|
||||
x_replace "1s/1/${i}/" "${networkConfig}"
|
||||
done
|
||||
|
||||
|
|
Loading…
Reference in New Issue