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-kit/log"
|
||||||
"github.com/meshplus/bitxhub/api/gateway"
|
"github.com/meshplus/bitxhub/api/gateway"
|
||||||
"github.com/meshplus/bitxhub/api/grpc"
|
"github.com/meshplus/bitxhub/api/grpc"
|
||||||
|
"github.com/meshplus/bitxhub/api/jsonrpc"
|
||||||
"github.com/meshplus/bitxhub/internal/app"
|
"github.com/meshplus/bitxhub/internal/app"
|
||||||
"github.com/meshplus/bitxhub/internal/coreapi"
|
"github.com/meshplus/bitxhub/internal/coreapi"
|
||||||
"github.com/meshplus/bitxhub/internal/loggers"
|
"github.com/meshplus/bitxhub/internal/loggers"
|
||||||
"github.com/meshplus/bitxhub/internal/repo"
|
"github.com/meshplus/bitxhub/internal/repo"
|
||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
@ -96,6 +96,16 @@ func start(ctx *cli.Context) error {
|
||||||
return err
|
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() {
|
go func() {
|
||||||
logger.WithField("port", repo.Config.Port.Gateway).Info("Gateway service started")
|
logger.WithField("port", repo.Config.Port.Gateway).Info("Gateway service started")
|
||||||
err := gateway.Start(repo.Config)
|
err := gateway.Start(repo.Config)
|
||||||
|
|
|
@ -3,6 +3,7 @@ title = "BitXHub configuration file"
|
||||||
solo = false
|
solo = false
|
||||||
|
|
||||||
[port]
|
[port]
|
||||||
|
jsonrpc = 8881
|
||||||
grpc = 60011
|
grpc = 60011
|
||||||
gateway = 9091
|
gateway = 9091
|
||||||
pprof = 53121
|
pprof = 53121
|
||||||
|
@ -44,7 +45,7 @@ solo = false
|
||||||
consensus = "info"
|
consensus = "info"
|
||||||
executor = "info"
|
executor = "info"
|
||||||
router = "info"
|
router = "info"
|
||||||
api = "info"
|
api = "debug"
|
||||||
coreapi = "info"
|
coreapi = "info"
|
||||||
storage = "info"
|
storage = "info"
|
||||||
|
|
||||||
|
@ -61,6 +62,7 @@ solo = false
|
||||||
type = "serial" # opensource version only supports serial type, commercial version supports serial and parallel types
|
type = "serial" # opensource version only supports serial type, commercial version supports serial and parallel types
|
||||||
|
|
||||||
[genesis]
|
[genesis]
|
||||||
|
chainid = "a-1"
|
||||||
dider = "0xc7F999b83Af6DF9e67d0a37Ee7e900bF38b3D013"
|
dider = "0xc7F999b83Af6DF9e67d0a37Ee7e900bF38b3D013"
|
||||||
[[genesis.admins]]
|
[[genesis.admins]]
|
||||||
address = "0xc7F999b83Af6DF9e67d0a37Ee7e900bF38b3D013"
|
address = "0xc7F999b83Af6DF9e67d0a37Ee7e900bF38b3D013"
|
||||||
|
|
1
go.mod
1
go.mod
|
@ -15,6 +15,7 @@ require (
|
||||||
github.com/gogo/protobuf v1.3.2
|
github.com/gogo/protobuf v1.3.2
|
||||||
github.com/golang/mock v1.5.0
|
github.com/golang/mock v1.5.0
|
||||||
github.com/google/btree v1.0.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-middleware v1.2.2
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0
|
||||||
|
|
|
@ -53,6 +53,7 @@ type Security struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Port struct {
|
type Port struct {
|
||||||
|
JsonRpc int64 `toml:"jsonrpc" json:"jsonrpc"`
|
||||||
Grpc int64 `toml:"grpc" json:"grpc"`
|
Grpc int64 `toml:"grpc" json:"grpc"`
|
||||||
Gateway int64 `toml:"gateway" json:"gateway"`
|
Gateway int64 `toml:"gateway" json:"gateway"`
|
||||||
PProf int64 `toml:"pprof" json:"pprof"`
|
PProf int64 `toml:"pprof" json:"pprof"`
|
||||||
|
@ -104,6 +105,7 @@ type LogModule struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Genesis struct {
|
type Genesis struct {
|
||||||
|
ChainID string `json:"chainid" toml:"chainid"`
|
||||||
Admins []*Admin `json:"admins" toml:"admins"`
|
Admins []*Admin `json:"admins" toml:"admins"`
|
||||||
Strategy map[string]string `json:"strategy" toml:"strategy"`
|
Strategy map[string]string `json:"strategy" toml:"strategy"`
|
||||||
Dider string `json:"dider" toml:"dider"`
|
Dider string `json:"dider" toml:"dider"`
|
||||||
|
|
|
@ -49,6 +49,7 @@ function prepare() {
|
||||||
x_replace "s/9091/909${i}/g" "${bitxhubConfig}"
|
x_replace "s/9091/909${i}/g" "${bitxhubConfig}"
|
||||||
x_replace "s/53121/5312${i}/g" "${bitxhubConfig}"
|
x_replace "s/53121/5312${i}/g" "${bitxhubConfig}"
|
||||||
x_replace "s/40011/4001${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}"
|
x_replace "1s/1/${i}/" "${networkConfig}"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue