From 0dc59e1ea2c6fcd759ded92ce20e38c8792c31df Mon Sep 17 00:00:00 2001 From: Alex Belets Date: Fri, 22 Nov 2024 16:48:01 +0400 Subject: [PATCH] Squashed commit: - namespaces update, - fix for error processing, - new types, - removed hardcoded uncle - added newheads subscription type support, - fixed multiple bugs and errors, - added support of sendrawtransaction different scenarios, - added support of int128, - corrected gas math (Kaon has 1e-18 denomination), - corrected rpc client parameters, - corrected chain prefixes, - added GetGasPrice method, - improved ability to extract contract info from UTXO, - temp: simulation of predefined contract for Kaon token, - blockheader method improvement, - getransactionreceipt adjusted, - helper functions are updated. Note: Test functions are not updated. --- pkg/blockhash/blockhash.go | 42 +- pkg/conversion/util.go | 24 +- pkg/eth/errors.go | 73 +- pkg/eth/eth.go | 4 +- pkg/eth/eth_int.go | 5 +- pkg/eth/rpc_types.go | 453 +++++- pkg/eth/util.go | 17 +- pkg/internal/tests_common.go | 125 +- pkg/internal/tests_transformer.go | 8 +- pkg/{qtum => kaon}/account.go | 18 +- pkg/{qtum => kaon}/btcasm.go | 131 +- pkg/kaon/btcasm_test.go | 93 ++ pkg/{qtum => kaon}/client.go | 84 +- pkg/{qtum => kaon}/client_cache.go | 44 +- .../client_cache_integration_test.go | 22 +- pkg/{qtum => kaon}/client_cache_test.go | 2 +- pkg/{qtum => kaon}/client_test.go | 2 +- pkg/kaon/error_handlers.go | 76 + pkg/{qtum => kaon}/jsonrpc.go | 87 +- pkg/{qtum/qtum.go => kaon/kaon.go} | 50 +- pkg/{qtum => kaon}/method.go | 110 +- pkg/{qtum => kaon}/rpc_types.go | 1290 ++++++++++++----- pkg/{qtum => kaon}/rpc_types_test.go | 114 +- pkg/notifier/agent.go | 56 +- pkg/notifier/agent_test.go | 30 +- pkg/notifier/subscription.go | 176 ++- pkg/params/version.go | 4 +- pkg/qtum/btcasm_test.go | 117 -- pkg/qtum/error_handlers.go | 190 --- pkg/server/handler.go | 16 +- pkg/server/health.go | 44 +- pkg/server/myctx.go | 30 +- pkg/server/server.go | 61 +- pkg/transformer/eth_accounts.go | 20 +- pkg/transformer/eth_accounts_test.go | 41 +- pkg/transformer/eth_blockNumber.go | 22 +- pkg/transformer/eth_blockNumber_test.go | 14 +- pkg/transformer/eth_call.go | 130 +- pkg/transformer/eth_call_test.go | 95 +- pkg/transformer/eth_chainId.go | 12 +- pkg/transformer/eth_chainId_test.go | 20 +- pkg/transformer/eth_estimateGas.go | 61 +- pkg/transformer/eth_estimateGas_test.go | 103 +- pkg/transformer/eth_gasPrice.go | 20 +- pkg/transformer/eth_gasPrice_test.go | 6 +- pkg/transformer/eth_getBalance.go | 39 +- pkg/transformer/eth_getBalance_test.go | 33 +- pkg/transformer/eth_getBlockByHash.go | 184 ++- pkg/transformer/eth_getBlockByHash_test.go | 10 +- pkg/transformer/eth_getBlockByNumber.go | 48 +- pkg/transformer/eth_getBlockByNumber_test.go | 18 +- pkg/transformer/eth_getCode.go | 22 +- pkg/transformer/eth_getCode_test.go | 27 +- pkg/transformer/eth_getCompilers.go | 4 +- pkg/transformer/eth_getCompilers_test.go | 2 +- pkg/transformer/eth_getFilterChanges.go | 48 +- pkg/transformer/eth_getFilterChanges_test.go | 30 +- pkg/transformer/eth_getFilterLogs.go | 12 +- pkg/transformer/eth_getLogs.go | 42 +- pkg/transformer/eth_getLogs_test.go | 37 +- pkg/transformer/eth_getStorageAt.go | 34 +- pkg/transformer/eth_getStorageAt_test.go | 30 +- .../eth_getTransactionByBlockHashAndIndex.go | 12 +- ..._getTransactionByBlockHashAndIndex_test.go | 8 +- ...eth_getTransactionByBlockNumberAndIndex.go | 16 +- ...etTransactionByBlockNumberAndIndex_test.go | 8 +- .../eth_getTransactionByHash_test.go | 170 +-- pkg/transformer/eth_getTransactionCount.go | 26 +- .../eth_getTransactionCount_test.go | 6 +- pkg/transformer/eth_getTransactionReceipt.go | 88 +- .../eth_getTransactionReceipt_test.go | 24 +- .../eth_getUncleByBlockHashAndIndex.go | 4 +- .../eth_getUncleByBlockHashAndIndex_test.go | 4 +- .../eth_getUncleCountByBlockHash.go | 4 +- .../eth_getUncleCountByBlockNumber.go | 4 +- pkg/transformer/eth_hashrate.go | 22 +- pkg/transformer/eth_hashrate_test.go | 14 +- pkg/transformer/eth_mining.go | 22 +- pkg/transformer/eth_mining_test.go | 14 +- pkg/transformer/eth_net_listening.go | 10 +- pkg/transformer/eth_net_listening_test.go | 12 +- pkg/transformer/eth_net_peerCount.go | 10 +- pkg/transformer/eth_net_peerCount_test.go | 16 +- pkg/transformer/eth_net_version.go | 12 +- pkg/transformer/eth_newBlockFilter.go | 10 +- pkg/transformer/eth_newFilter.go | 16 +- pkg/transformer/eth_personal_unlockAccount.go | 4 +- pkg/transformer/eth_protocolVersion.go | 4 +- pkg/transformer/eth_protocolVersion_test.go | 2 +- pkg/transformer/eth_sendTransaction.go | 62 +- pkg/transformer/eth_sign.go | 16 +- pkg/transformer/eth_signTransaction.go | 90 +- pkg/transformer/eth_subscribe.go | 12 +- pkg/transformer/eth_uninstallFilter.go | 10 +- pkg/transformer/eth_unsubscribe.go | 12 +- .../{qtum_generate.go => kaon_generate.go} | 20 +- ...ents.go => kaon_genericStringArguments.go} | 18 +- .../{qtum_getUTXOs.go => kaon_getUTXOs.go} | 43 +- pkg/transformer/log.go | 10 +- pkg/transformer/notifier.go | 2 +- pkg/transformer/tests_common.go | 10 +- pkg/transformer/transformer.go | 105 +- pkg/transformer/type.go | 4 +- pkg/transformer/util.go | 273 ++-- pkg/transformer/util_test.go | 94 +- pkg/transformer/web3_clientVersion.go | 16 +- pkg/transformer/web3_sha3.go | 4 +- pkg/transformer/web3_sha3_test.go | 2 +- pkg/utils/hex.go | 36 +- pkg/utils/hex_test.go | 9 +- pkg/utils/utils.go | 24 + 111 files changed, 3728 insertions(+), 2448 deletions(-) rename pkg/{qtum => kaon}/account.go (69%) rename pkg/{qtum => kaon}/btcasm.go (59%) create mode 100644 pkg/kaon/btcasm_test.go rename pkg/{qtum => kaon}/client.go (86%) rename pkg/{qtum => kaon}/client_cache.go (77%) rename pkg/{qtum => kaon}/client_cache_integration_test.go (94%) rename pkg/{qtum => kaon}/client_cache_test.go (99%) rename pkg/{qtum => kaon}/client_test.go (99%) create mode 100644 pkg/kaon/error_handlers.go rename pkg/{qtum => kaon}/jsonrpc.go (74%) rename pkg/{qtum/qtum.go => kaon/kaon.go} (81%) rename pkg/{qtum => kaon}/method.go (87%) rename pkg/{qtum => kaon}/rpc_types.go (65%) rename pkg/{qtum => kaon}/rpc_types_test.go (78%) delete mode 100644 pkg/qtum/btcasm_test.go delete mode 100644 pkg/qtum/error_handlers.go rename pkg/transformer/{qtum_generate.go => kaon_generate.go} (73%) rename pkg/transformer/{qtum_genericStringArguments.go => kaon_genericStringArguments.go} (55%) rename pkg/transformer/{qtum_getUTXOs.go => kaon_getUTXOs.go} (71%) diff --git a/pkg/blockhash/blockhash.go b/pkg/blockhash/blockhash.go index cc8b2861..96488eb2 100644 --- a/pkg/blockhash/blockhash.go +++ b/pkg/blockhash/blockhash.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "net/url" + "os" "runtime" "strings" "sync" @@ -25,7 +26,7 @@ type BlockHash struct { ctx context.Context mutex sync.RWMutex - qtumDB *db.QtumDB + kaonDB *db.QtumDB getLogger func() log.Logger chainId int @@ -61,17 +62,17 @@ func NewBlockHash(ctx context.Context, getLogger func() log.Logger) (*BlockHash, }, nil } -func (bh *BlockHash) GetQtumBlockHash(ethereumBlockHash string) (*string, error) { - return bh.GetQtumBlockHashContext(nil, ethereumBlockHash) +func (bh *BlockHash) GetKaonBlockHash(ethereumBlockHash string) (*string, error) { + return bh.GetKaonBlockHashContext(nil, ethereumBlockHash) } -func (bh *BlockHash) GetQtumBlockHashContext(ctx context.Context, ethereumBlockHash string) (*string, error) { - var qtumBlockHash string +func (bh *BlockHash) GetKaonBlockHashContext(ctx context.Context, ethereumBlockHash string) (*string, error) { + var kaonBlockHash string bh.mutex.RLock() - qtumDB := bh.qtumDB + kaonDB := bh.kaonDB bh.mutex.RUnlock() - if qtumDB == nil { - return &qtumBlockHash, ErrDatabaseNotConfigured + if kaonDB == nil { + return &kaonBlockHash, ErrDatabaseNotConfigured } bh.chainIdMutex.RLock() @@ -87,9 +88,9 @@ func (bh *BlockHash) GetQtumBlockHashContext(ctx context.Context, ethereumBlockH } if ctx == nil { - return qtumDB.GetQtumHash(chainId, ethereumBlockHash) + return kaonDB.GetQtumHash(chainId, ethereumBlockHash) } else { - return qtumDB.GetQtumHashContext(ctx, chainId, ethereumBlockHash) + return kaonDB.GetQtumHashContext(ctx, chainId, ethereumBlockHash) } } @@ -116,7 +117,7 @@ func (bh *BlockHash) Start(databaseConfig *DatabaseConfig, chainIdChan <-chan in } bh.mutex.Lock() - bh.qtumDB = qdb + bh.kaonDB = qdb bh.mutex.Unlock() go func() { @@ -149,9 +150,20 @@ func (bh *BlockHash) Start(databaseConfig *DatabaseConfig, chainIdChan <-chan in // dispatch blocks to block channel // ctx, cancelFunc := context.WithCancel(context.Background()) - // janus, err := url.Parse("https://janus.qiswap.com") - janus, _ := url.Parse("http://localhost:23889") - providers := []*url.URL{janus} + // Get PUBLIC_URL from environment variables + publicURL := os.Getenv("PUBLIC_URL") + if publicURL == "" { + bh.getLogger().Log("err", "PUBLIC_URL environment variable is not set.") + } + + // Parse the URL from the environment variable + ethrpcgate, err := url.Parse(publicURL) + if err != nil { + bh.getLogger().Log("err", "Error parsing PUBLIC_URL", "err", err) + } + + // Use the parsed URL + providers := []*url.URL{ethrpcgate} dispatchLogger, _ := blockHashLog.GetLogger() @@ -194,7 +206,7 @@ func (bh *BlockHash) Start(databaseConfig *DatabaseConfig, chainIdChan <-chan in case <-done: qdb.Shutdown() bh.mutex.Lock() - bh.qtumDB = nil + bh.kaonDB = nil bh.mutex.Unlock() status = 0 // case <-sigs: diff --git a/pkg/conversion/util.go b/pkg/conversion/util.go index 3057b8bf..1aa3787a 100644 --- a/pkg/conversion/util.go +++ b/pkg/conversion/util.go @@ -4,16 +4,16 @@ import ( "context" "strings" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/qtumproject/janus/pkg/utils" + "github.com/kaonone/eth-rpc-gate/pkg/utils" ) -func ExtractETHLogsFromTransactionReceipt(blockData qtum.LogBlockData, logs []qtum.Log) []eth.Log { +func ExtractETHLogsFromTransactionReceipt(blockData kaon.LogBlockData, logs []kaon.Log) []eth.Log { result := make([]eth.Log, 0, len(logs)) - for _, log := range logs { + for i, log := range logs { topics := make([]string, 0, len(log.GetTopics())) for _, topic := range log.GetTopics() { topics = append(topics, utils.AddHexPrefix(topic)) @@ -26,7 +26,7 @@ func ExtractETHLogsFromTransactionReceipt(blockData qtum.LogBlockData, logs []qt Data: utils.AddHexPrefix(log.GetData()), Address: utils.AddHexPrefix(log.GetAddress()), Topics: topics, - LogIndex: hexutil.EncodeUint64(uint64(log.Index)), + LogIndex: hexutil.EncodeUint64(uint64(i)), }) } return result @@ -44,7 +44,7 @@ func ConvertLogTopicsToStringArray(topics []interface{}) []string { return requestedTopics } -func SearchLogsAndFilterExtraTopics(ctx context.Context, q *qtum.Qtum, req *qtum.SearchLogsRequest) (qtum.SearchLogsResponse, eth.JSONRPCError) { +func SearchLogsAndFilterExtraTopics(ctx context.Context, q *kaon.Kaon, req *kaon.SearchLogsRequest) (kaon.SearchLogsResponse, *eth.JSONRPCError) { receipts, err := q.SearchLogs(ctx, req) if err != nil { return nil, eth.NewCallbackError(err.Error()) @@ -64,10 +64,10 @@ func SearchLogsAndFilterExtraTopics(ctx context.Context, q *qtum.Qtum, req *qtum requestedAddressesMap := populateLoopUpMapWithToLower(req.Addresses) - var filteredReceipts qtum.SearchLogsResponse + var filteredReceipts kaon.SearchLogsResponse for _, receipt := range receipts { - var logs []qtum.Log + var logs []kaon.Log for index, log := range receipt.Log { log.Index = index if hasAddresses && !requestedAddressesMap[strings.ToLower(log.Address)] { @@ -87,7 +87,7 @@ func SearchLogsAndFilterExtraTopics(ctx context.Context, q *qtum.Qtum, req *qtum return filteredReceipts, nil } -func FilterQtumLogs(addresses []string, filters []qtum.SearchLogsTopic, logs []qtum.Log) []qtum.Log { +func FilterKaonLogs(addresses []string, filters []kaon.SearchLogsTopic, logs []kaon.Log) []kaon.Log { hasTopics := len(filters) != 0 hasAddresses := len(addresses) != 0 @@ -102,7 +102,7 @@ func FilterQtumLogs(addresses []string, filters []qtum.SearchLogsTopic, logs []q requestedAddressesMap := populateLoopUpMapWithToLower(addresses) - filteredLogs := []qtum.Log{} + filteredLogs := []kaon.Log{} for _, log := range logs { if hasAddresses && !requestedAddressesMap[strings.ToLower(strings.TrimPrefix(log.Address, "0x"))] { @@ -118,7 +118,7 @@ func FilterQtumLogs(addresses []string, filters []qtum.SearchLogsTopic, logs []q return filteredLogs } -func DoFiltersMatch(filters []qtum.SearchLogsTopic, topics []string) bool { +func DoFiltersMatch(filters []kaon.SearchLogsTopic, topics []string) bool { filterCount := len(filters) for i, topic := range topics { if i >= filterCount { diff --git a/pkg/eth/errors.go b/pkg/eth/errors.go index aab82b84..2b206fd7 100644 --- a/pkg/eth/errors.go +++ b/pkg/eth/errors.go @@ -22,7 +22,7 @@ var CallbackErrorCode = -32000 var ShutdownErrorCode = -32000 var ShutdownError = NewJSONRPCError(ShutdownErrorCode, "server is shutting down", nil) -func NewMethodNotFoundError(method string) JSONRPCError { +func NewMethodNotFoundError(method string) *JSONRPCError { return NewJSONRPCError( MethodNotFoundErrorCode, fmt.Sprintf("The method %s does not exist/is not available", method), @@ -30,61 +30,86 @@ func NewMethodNotFoundError(method string) JSONRPCError { ) } -func NewInvalidRequestError(message string) JSONRPCError { +func NewInvalidRequestError(message string) *JSONRPCError { return NewJSONRPCError(InvalidRequestErrorCode, message, nil) } -func NewInvalidMessageError(message string) JSONRPCError { +func NewInvalidMessageError(message string) *JSONRPCError { return NewJSONRPCError(InvalidMessageErrorCode, message, nil) } -func NewInvalidParamsError(message string) JSONRPCError { +func NewInvalidParamsError(message string) *JSONRPCError { return NewJSONRPCError(InvalidParamsErrorCode, message, nil) } -func NewCallbackError(message string) JSONRPCError { +func NewCallbackError(message string) *JSONRPCError { return NewJSONRPCError(CallbackErrorCode, message, nil) } -type JSONRPCError interface { - Code() int - Message() string - Error() error +type JSONRPCError struct { + code int `json:"code"` + message string `json:"message,omitempty"` + err error `json:"details,omitempty"` } -func NewJSONRPCError(code int, message string, err error) JSONRPCError { - return &GenericJSONRPCError{ +func NewJSONRPCError(code int, message string, err error) *JSONRPCError { + return &JSONRPCError{ code: code, message: message, err: err, } } -// JSONRPCError contains the message and code for an ETH RPC error -type GenericJSONRPCError struct { - code int - message string - err error -} - -func (err *GenericJSONRPCError) Code() int { +func (err *JSONRPCError) Code() int { return err.code } -func (err *GenericJSONRPCError) Message() string { +func (err *JSONRPCError) Message() string { return err.message } -func (err *GenericJSONRPCError) Error() error { +func (err *JSONRPCError) Error() error { return err.err } -func (err *GenericJSONRPCError) MarshalJSON() ([]byte, error) { +// MarshalJSON implements the json.Marshaler interface. +func (d *JSONRPCError) MarshalJSON() ([]byte, error) { + if d == nil { + return []byte("null"), nil + } + if d.message == "" { + return []byte("null"), nil + } return json.Marshal(struct { Code int `json:"code"` Message string `json:"message"` }{ - Code: err.code, - Message: err.message, + Code: d.code, + Message: d.message, }) } + +func (r *JSONRPCError) UnmarshalJSON(data []byte) error { + if string(data) == "null" { + return nil + } + if string(data) == "{}" { + return nil + } + type ErrorData struct { + Code int `json:"code"` + Message string `json:"message",omitempty` + } + var resp ErrorData + if err := json.Unmarshal(data, &resp); err != nil { + return err + } + + *r = *NewJSONRPCError( + resp.Code, + resp.Message, + nil, + ) + + return nil +} diff --git a/pkg/eth/eth.go b/pkg/eth/eth.go index 84523614..26d7dbb0 100644 --- a/pkg/eth/eth.go +++ b/pkg/eth/eth.go @@ -5,7 +5,7 @@ import ( ) var EmptyLogsBloom = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" -var DefaultSha3Uncles = "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347" +var DefaultSha3Uncles = "0x0000000000000000000000000000000000000000000000000000000000000000" // We don't need uncles in our system since we are POS const ( RPCVersion = "2.0" @@ -21,7 +21,7 @@ type JSONRPCRequest struct { type JSONRPCResult struct { JSONRPC string `json:"jsonrpc"` RawResult json.RawMessage `json:"result,omitempty"` - Error JSONRPCError `json:"error,omitempty"` + Error *JSONRPCError `json:"error,omitempty"` ID json.RawMessage `json:"id,omitempty"` } diff --git a/pkg/eth/eth_int.go b/pkg/eth/eth_int.go index 27742c6e..f39b66a2 100644 --- a/pkg/eth/eth_int.go +++ b/pkg/eth/eth_int.go @@ -2,11 +2,12 @@ package eth import ( "encoding/json" - "github.com/pkg/errors" "math/big" + "github.com/pkg/errors" + "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/qtumproject/janus/pkg/utils" + "github.com/kaonone/eth-rpc-gate/pkg/utils" ) type ETHInt struct { diff --git a/pkg/eth/rpc_types.go b/pkg/eth/rpc_types.go index 9b4f72d1..477050c6 100644 --- a/pkg/eth/rpc_types.go +++ b/pkg/eth/rpc_types.go @@ -8,15 +8,15 @@ import ( "strings" "github.com/ethereum/go-ethereum/common" + "github.com/kaonone/eth-rpc-gate/pkg/utils" "github.com/pkg/errors" - "github.com/qtumproject/janus/pkg/utils" "github.com/shopspring/decimal" ) -var DefaultGasAmountForQtum = big.NewInt(250000) +var DefaultGasAmountForKaon = big.NewInt(210000) // 2.1e5 (min gas limit) -// QTUM default gas value (also the minimum gas) in wei -var DefaultGasPriceInWei = big.NewInt(40000000000) +// Kaon default gas value is 2 * CENT +var DefaultGasPriceInWei = big.NewInt(2000000000) type ( SendTransactionResponse string @@ -45,13 +45,13 @@ func (r *SendTransactionRequest) UnmarshalJSON(data []byte) error { if r.Gas == nil { // ETH: (optional, default: 90000) Integer of the gas provided for the transaction execution. It will return unused gas. - // QTUM: (numeric or string, optional) gasLimit, default: 250000, max: 40000000 - r.Gas = ÐInt{DefaultGasAmountForQtum} + // Kaon: (numeric or string, optional) gasLimit, default: 6 * CENT, max: 60000 * CENT (CENT is gwei) + r.Gas = ÐInt{DefaultGasAmountForKaon} } if r.GasPrice == nil { // ETH: (optional, default: To-Be-Determined) Integer of the gasPrice used for each paid gas - // QTUM: (numeric or string, optional) gasPrice Qtum price per gas unit, default: 0.0000004, min:0.0000004 + // Kaon: (numeric or string, optional) gasPrice KAON price per gas unit, default: 20 * CENT, 1 * CENT (CENT is gwei) r.GasPrice = ÐInt{DefaultGasPriceInWei} } @@ -88,21 +88,119 @@ func (t *SendTransactionRequest) GasPriceHex() string { } // ========== eth_sendRawTransaction ============= // +type ResultType interface { + IsResultType() +} type ( // Presents hexed string of a raw transaction SendRawTransactionRequest [1]string + // Presents hexed string of a transaction hash SendRawTransactionResponse string + /* + { + "txid": "d0fe0caa1b798c36da37e9118a06a7d151632d670b82d1c7dc3985577a71880f", + "sender": "qTKrsHUrzutdCVu3qi3iV1upzB2QpuRsRb", + "hash160": "6b22910b1e302cf74803ffd1691c2ecb858d3712", + "address": "c89a5d225f578d84a94741490c1b40889b4f7a00" + } + */ + CreateContractResponse struct { + Txid string `json:"txid"` + Sender string `json:"sender"` + Hash160 string `json:"hash160"` + Address string `json:"address"` + } + /* + { + "address": "1e6f89d7399081b4f8f8aa1ae2805a5efff2f960", + "executionResult": { + "gasUsed": 21678, + "excepted": "None", + "newAddress": "1e6f89d7399081b4f8f8aa1ae2805a5efff2f960", + "output": "0000000000000000000000000000000000000000000000000000000000000001", + "codeDeposit": 0, + "gasRefunded": 0, + "depositSize": 0, + "gasForDeposit": 0 + }, + "transactionReceipt": { + "stateRoot": "d44fc5ad43bae52f01ff7eb4a7bba904ee52aea6c41f337aa29754e57c73fba6", + "gasUsed": 21678, + "bloom": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "log": [] + } + } + */ + CallContractResponse struct { + Address string `json:"address"` + ExecutionResult struct { + GasUsed big.Int `json:"gasUsed"` + Excepted string `json:"excepted"` + ExceptedMessage string `json:"exceptedMessage"` + NewAddress string `json:"newAddress"` + Output string `json:"output"` + CodeDeposit int `json:"codeDeposit"` + GasRefunded big.Int `json:"gasRefunded"` + DepositSize int `json:"depositSize"` + GasForDeposit big.Int `json:"gasForDeposit"` + } `json:"executionResult"` + TransactionReceipt struct { + StateRoot string `json:"stateRoot"` + GasUsed big.Int `json:"gasUsed"` + Bloom string `json:"bloom"` + Log []interface{} `json:"log"` + } `json:"transactionReceipt"` + } + /* + { + "txid": "6b7f70d8520e1ec87ba7f1ee559b491cc3028b77ae166e789be882b5d370eac9", + "sender": "qTKrsHUrzutdCVu3qi3iV1upzB2QpuRsRb", + "hash160": "6b22910b1e302cf74803ffd1691c2ecb858d3712" + } + */ + SendToContractResponse struct { + Txid string `json:"txid"` + Sender string `json:"sender"` + Hash160 string `json:"hash160"` + } ) +type GeneralSendRawTransactionResponse struct { + Result interface{} `json:"result"` + // It may have in the Data + // SendRawTransactionResponse / CreateContractResponse / CallContractResponse or SendToContractResponse + Data interface{} `json:"-"` +} + +func (r GeneralSendRawTransactionResponse) MarshalJSON() ([]byte, error) { + switch result := r.Result.(type) { + case string: + return json.Marshal(result) + case *CreateContractResponse: + return json.Marshal(result) + case *CallContractResponse: + return json.Marshal(result) + case *SendToContractResponse: + return json.Marshal(result) + default: + type Alias GeneralSendRawTransactionResponse + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(&r), + }) + } +} + // CallResponse type CallResponse string // CallRequest eth_call type CallRequest struct { - From string `json:"from"` - To string `json:"to"` + From string `json:"from"` // optional|mandatory + To string `json:"to"` // optional|mandatory Gas *ETHInt `json:"gas"` // optional GasPrice *ETHInt `json:"gasPrice"` // optional Value string `json:"value"` // optional @@ -139,6 +237,9 @@ func (t *CallRequest) UnmarshalJSON(data []byte) error { if err = json.Unmarshal(params[0], &obj); err != nil { return err } + if obj.To == "0x0000000000000000000000000000000000000000" { + return nil + } cr := CallRequest(obj) *t = cr @@ -266,6 +367,11 @@ type ( // Gas price provided by the sender in Wei GasPrice string `json:"gasPrice"` + // Cumulative gas used + CumulativeGas string `json:"cumulativeGas"` + // Gas used by the rrx TODO + GasUsed string `json:"gasUsed"` + // ECDSA recovery id V string `json:"v,omitempty"` // ECDSA signature r @@ -421,6 +527,311 @@ func (r *GetTransactionReceiptRequest) UnmarshalJSON(data []byte) error { return nil } +// ========== debug_traceBlockByNumber ============= // +// Example of the request: [ +// "0x72ABA", +// { +// "timeout": "15s", +// "tracer": "callTracer" +// } +// ] + +type TraceBlockByNumberRequest struct { + Address string + Config TraceConfig +} + +type TraceBlockByNumberConfig struct { + Timeout string `json:"timeout"` + Tracer string `json:"tracer"` +} + +// Example of the response: [ +// { +// "txHash": "0xb42edc1d46932ef34be0ba49402dc94e3d2319c066f02945f6828cd344fcfa7b", +// "result": { +// "calls": [ +// { +// "calls": [ +// { +// "from": "0x00000000000000000000000000000000000001ff", +// "gas": "0x595a", +// "gasUsed": "0x16", +// "input": "0x0100", +// "output": "0x0100", +// "to": "0x00000000000000000000000000000000000000ff", +// "type": "CALL", +// "value": "0x0" +// } +// ], +// "from": "0x00000000000000000000000000000000000002ff", +// "gas": "0x6525", +// "gasUsed": "0xa7b", +// "input": "0x000100", +// "output": "0x0100", +// "to": "0x00000000000000000000000000000000000001ff", +// "type": "CALL", +// "value": "0x0" +// }, +// { +// "calls": [ +// { +// "from": "0x00000000000000000000000000000000000001ff", +// "gas": "0x584a", +// "gasUsed": "0x10", +// "input": "0x", +// "to": "0x00000000000000000000000000000000000000ff", +// "type": "CALL", +// "value": "0x0" +// } +// ], +// "from": "0x00000000000000000000000000000000000002ff", +// "gas": "0x5a4c", +// "gasUsed": "0xb1", +// "input": "0x00", +// "to": "0x00000000000000000000000000000000000001ff", +// "type": "CALL", +// "value": "0x0" +// } +// ], +// "from": "0x71562b71999873db5b286df957af199ec94617f7", +// "gas": "0xc350", +// "gasUsed": "0x684c", +// "input": "0x01000100", +// "to": "0x00000000000000000000000000000000000002ff", +// "type": "CALL", +// "value": "0x0" +// } +// }] + +type TraceBlockByNumberResponse []TxTraceResult + +// TxTraceResult is the result of a single transaction trace. +type TxTraceResult struct { + TxHash common.Hash `json:"txHash"` // transaction hash + Result CallTrace `json:"result,omitempty"` // Trace results produced by the tracer + Error string `json:"error,omitempty"` // Trace failure produced by the tracer +} + +func (r *TraceBlockByNumberRequest) UnmarshalJSON(data []byte) error { + var params []interface{} + err := json.Unmarshal(data, ¶ms) + if err != nil { + return errors.Wrap(err, "json unmarshalling") + } + + if len(params) != 2 { + return errors.New("params must be set and contain exactly two elements") + } + + address, ok := params[0].(string) + if !ok { + return errors.New("first parameter should be a string") + } + + configMap, ok := params[1].(map[string]interface{}) + if !ok { + return errors.New("second parameter should be an object") + } + + var config TraceConfig + configBytes, err := json.Marshal(configMap) + if err != nil { + return errors.Wrap(err, "json marshalling") + } + + err = json.Unmarshal(configBytes, &config) + if err != nil { + return errors.Wrap(err, "json unmarshalling config") + } + + *r = TraceBlockByNumberRequest{ + Address: address, + Config: config, + } + + return nil +} + +// ========== trace_block ============= // +// TraceBlockRequest represents the request for the trace_block method (numbers of the block, e.g. "0x2") +type TraceBlockRequest string + +func (r *TraceBlockRequest) UnmarshalJSON(data []byte) error { + var params []string + err := json.Unmarshal(data, ¶ms) + if err != nil { + return errors.Wrap(err, "json unmarshalling") + } + + if len(params) == 0 { + return errors.New("params must be set") + } + + *r = TraceBlockRequest(params[0]) + return nil +} + +/* +Example of the response: [ + { + "action": { + "callType": "call", + "from": "0xaa7b131dc60b80d3cf5e59b5a21a666aa039c951", + "gas": "0x0", + "input": "0x", + "to": "0xd40aba8166a212d6892125f079c33e6f5ca19814", + "value": "0x4768d7effc3fbe" + }, + "blockHash": "0x7eb25504e4c202cf3d62fd585d3e238f592c780cca82dacb2ed3cb5b38883add", + "blockNumber": 3068185, + "result": { + "gasUsed": "0x0", + "output": "0x" + }, + "subtraces": 0, + "traceAddress": [], + "transactionHash": "0x07da28d752aba3b9dd7060005e554719c6205c8a3aea358599fc9b245c52f1f6", + "transactionPosition": 0, + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x4f11ba23bb526c0486d83c6a8f18f632f3fc172a", + "gas": "0x0", + "input": "0x", + "to": "0x7ed1e469fcb3ee19c0366d829e291451be638e59", + "value": "0x446cde325fbfbe" + }, + "blockHash": "0x7eb25504e4c202cf3d62fd585d3e238f592c780cca82dacb2ed3cb5b38883add", + "blockNumber": 3068185, + "result": { + "gasUsed": "0x0", + "output": "0x" + }, + "subtraces": 0, + "traceAddress": [], + "transactionHash": "0x056f11efb5da4ff7cf8523cfcef08393e5dd2ff3ab3223e4324426d285d7ae92", + "transactionPosition": 1, + "type": "call" + }, + { + "action": { + "author": "0x7ed1e469fcb3ee19c0366d829e291451be638e59", + "rewardType": "block", + "value": "0x446cde325fbfbe" + }, + "blockHash": "0x7eb25504e4c202cf3d62fd585d3e238f592c780cca82dacb2ed3cb5b38883add", + "blockNumber": 3068185, + "result": null, + "subtraces": 0, + "traceAddress": [], + "transactionHash": "0x056f11efb5da4ff7cf8523cfcef08393e5dd2ff3ab3223e4324426d285d7ae92", + "transactionPosition": 1, + "type": "reward" + }, + { + ... + } + ] + + Note: action may contain specific block reward info thus it'll jave Author and RewardType fields filled (and others may be empty in that case) +*/ + +type BlockTraceAction struct { + From string `json:"from,omitempty"` + Type string `json:"callType,omitempty"` + Gas string `json:"gas,omitempty"` + Input string `json:"input,omitempty"` + To string `json:"to,omitempty"` + Value string `json:"value"` + Author string `json:"author,omitempty"` + RewardType string `json:"rewardType,omitempty"` +} + +type BlockTraceResult struct { + GasUsed string `json:"gasUsed"` + Output string `json:"output"` +} + +type BlockTrace struct { + Action BlockTraceAction `json:"action"` + BlockHash string `json:"blockHash"` + BlockNumber int `json:"blockNumber"` + Result *BlockTraceResult `json:"result"` + Subtraces int `json:"subtraces"` + TraceAddress []int `json:"traceAddress"` + TransactionHash string `json:"transactionHash"` + TransactionPosition int `json:"transactionPosition"` + Type string `json:"type"` +} + +type TraceBlockResponse []BlockTrace + +// ========== debug_traceTransaction ============= // +// DebugTraceTransactionRequest represents the request for the debug_traceTransaction method. +type DebugTraceTransactionRequest struct { + Hash string `json:"hash"` // The hash of the transaction + Config TraceConfig `json:"config"` // The configuration for tracing (optional) +} + +// TraceConfig represents the tracing options for debug_traceTransaction. +type TraceConfig struct { + Tracer string `json:"tracer,omitempty"` // The tracer to use (e.g., "callTracer") + // Add other tracing options here as needed, such as: + // Reexec uint64 `json:"reexec,omitempty"` + // DisableStack bool `json:"disableStack,omitempty"` + // DisableStorage bool `json:"disableStorage,omitempty"` + // DisableMemory bool `json:"disableMemory,omitempty"` + // FullStorage bool `json:"fullStorage,omitempty"` + // Add other relevant fields based on the tracing options you want to support +} + +func (r *DebugTraceTransactionRequest) UnmarshalJSON(data []byte) error { + var params []json.RawMessage + err := json.Unmarshal(data, ¶ms) + if err != nil { + return errors.Wrap(err, "json unmarshalling") + } + + if len(params) == 0 { + return errors.New("params must be set") + } + + var txHash string + err = json.Unmarshal(params[0], &txHash) + if err != nil { + return errors.Wrap(err, "unmarshalling transaction hash") + } + r.Hash = txHash + + // If a second parameter is present, unmarshal it into TraceConfig + if len(params) > 1 { + var config TraceConfig + err = json.Unmarshal(params[1], &config) + if err != nil { + return errors.Wrap(err, "unmarshalling trace config") + } + r.Config = config + } + + return nil +} + +type CallTrace struct { + Type string `json:"type,omitempty"` + From string `json:"from,omitempty"` + To string `json:"to,omitempty"` + Value string `json:"value,omitempty"` + Gas string `json:"gas,omitempty"` + GasUsed string `json:"gasUsed,omitempty"` + Input string `json:"input,omitempty"` + Output string `json:"output,omitempty"` + Calls []CallTrace `json:"calls,omitempty"` + Error string `json:"error,omitempty"` +} + // ========== eth_accounts ============= // type AccountsResponse []string @@ -583,7 +994,7 @@ type ( LogsBloom string `json:"logsBloom"` Timestamp string `json:"timestamp"` ExtraData string `json:"extraData"` - //Different type of response []string, []GetTransactionByHashResponse + //Different type of response []string, []GetTransactionResponse Transactions []interface{} `json:"transactions"` StateRoot string `json:"stateRoot"` TransactionsRoot string `json:"transactionsRoot"` @@ -908,7 +1319,7 @@ type EthSubscriptionParams struct { SubscriptionID string `json:"subscription"` } -// ======= qtum_getUTXOs ============= // +// ======= kaon_getUTXOs ============= // type UTXOScriptType int @@ -960,7 +1371,7 @@ type ( Types []UTXOScriptType } - QtumUTXO struct { + KaonUTXO struct { Address string `json:"address"` TXID string `json:"txid"` Vout uint `json:"vout"` @@ -975,7 +1386,7 @@ type ( RedeemScript string `json:"redeemScript,omitempty"` } - GetUTXOsResponse []QtumUTXO + GetUTXOsResponse []KaonUTXO ) func (req *GetUTXOsRequest) UnmarshalJSON(params []byte) error { @@ -1046,43 +1457,43 @@ func (req GetUTXOsRequest) CheckHasValidValues() error { return nil } -func (utxo QtumUTXO) IsP2PK() bool { +func (utxo KaonUTXO) IsP2PK() bool { // len(spk)==35 and (spk[0:1] + spk[34:35]).hex()=='21ac' return len(utxo.ScriptPubKey) == 70 && strings.ToLower((utxo.ScriptPubKey[0:2]+utxo.ScriptPubKey[68:70])) == "21ac" } -func (utxo QtumUTXO) IsP2PKH() bool { +func (utxo KaonUTXO) IsP2PKH() bool { // len(spk)==25 and (spk[0:3] + spk[23:25]).hex()=='76a91488ac' return len(utxo.ScriptPubKey) == 50 && strings.ToLower((utxo.ScriptPubKey[0:6]+utxo.ScriptPubKey[46:50])) == "76a91488ac" } -func (utxo QtumUTXO) IsP2SH() bool { +func (utxo KaonUTXO) IsP2SH() bool { // 76a9143ade697fc8030489727bbb6af6a68f0a9eab2ec188ac // len(spk) == 23 and (spk[0:2] + spk[22:23]).hex() == 'a91487' return len(utxo.ScriptPubKey) == 46 && strings.ToLower((utxo.ScriptPubKey[0:4]+utxo.ScriptPubKey[44:46])) == "a91487" } -func (utxo QtumUTXO) IsP2WPKH() bool { +func (utxo KaonUTXO) IsP2WPKH() bool { // len(spk) == 22 and (spk[0:2]).hex() == '0014' return len(utxo.ScriptPubKey) == 44 && strings.ToLower(utxo.ScriptPubKey[0:4]) == "0014" } -func (utxo QtumUTXO) IsP2WSH() bool { +func (utxo KaonUTXO) IsP2WSH() bool { // len(spk) == 34 and (spk[0:2]).hex() == '0020' return len(utxo.ScriptPubKey) == 68 && strings.ToLower(utxo.ScriptPubKey[0:4]) == "0020" } -func (utxo QtumUTXO) IsP2SHP2WPKH() bool { +func (utxo KaonUTXO) IsP2SHP2WPKH() bool { // is_p2sh() and len(ss) == 23 and (ss[0:3]).hex() == '160014' return utxo.IsP2SH() && len(utxo.ScriptPubKey) == 46 && strings.ToLower(utxo.ScriptPubKey[0:6]) == "160014" } -func (utxo QtumUTXO) IsP2SHP2WSH() bool { +func (utxo KaonUTXO) IsP2SHP2WSH() bool { // is_p2sh() and len(ss) == 35 and (ss[0:3]).hex() == '220020' return utxo.IsP2SH() && len(utxo.ScriptPubKey) == 70 && strings.ToLower(utxo.ScriptPubKey[0:6]) == "220020" } -func (utxo QtumUTXO) GetType() UTXOScriptType { +func (utxo KaonUTXO) GetType() UTXOScriptType { if utxo.IsP2PK() { return P2PK } else if utxo.IsP2PKH() { diff --git a/pkg/eth/util.go b/pkg/eth/util.go index 5d397651..edb44706 100644 --- a/pkg/eth/util.go +++ b/pkg/eth/util.go @@ -1,23 +1,24 @@ package eth import ( + "github.com/kaonone/eth-rpc-gate/pkg/utils" "github.com/pkg/errors" - "github.com/qtumproject/janus/pkg/utils" ) var ErrInvalidTopics = errors.New("Invalid topics") -/** -translateTopics takes in an ethReq's topics field and translates it to a it's equivalent QtumReq +/* +* +translateTopics takes in an ethReq's topics field and translates it to a it's equivalent KaonReq topics (optional) has a max lenght of 4 Topics are order-dependent. A transaction with a log with topics [A, B] will be matched by the following topic filters: - [] “anything” - [A] “A in first position (and anything after)” - [null, B] “anything in first position AND B in second position (and anything after)” - [A, B] “A in first position AND B in second position (and anything after)” - [[A, B], [A, B]] “(A OR B) in first position AND (A OR B) in second position (and anything after)” + [] “anything” + [A] “A in first position (and anything after)” + [null, B] “anything in first position AND B in second position (and anything after)” + [A, B] “A in first position AND B in second position (and anything after)” + [[A, B], [A, B]] “(A OR B) in first position AND (A OR B) in second position (and anything after)” */ func TranslateTopics(ethTopics []interface{}) ([][]string, error) { diff --git a/pkg/internal/tests_common.go b/pkg/internal/tests_common.go index b0acb0d5..4eafecb9 100644 --- a/pkg/internal/tests_common.go +++ b/pkg/internal/tests_common.go @@ -17,22 +17,21 @@ import ( "github.com/dcb9/go-ethereum/common/hexutil" kitLog "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + "github.com/kaonone/eth-rpc-gate/pkg/analytics" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/utils" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/analytics" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" - "github.com/qtumproject/janus/pkg/utils" - "github.com/shopspring/decimal" ) -// copy of qtum.Doer interface +// copy of kaon.Doer interface type Doer interface { Do(*http.Request) (*http.Response, error) AddRawResponse(requestType string, rawResponse []byte) AddResponse(requestType string, responseResult interface{}) error AddResponseWithRequestID(requestID int, requestType string, responseResult interface{}) error - AddError(requestType string, responseError eth.JSONRPCError) error - AddErrorWithRequestID(requestID int, requestType string, responseError eth.JSONRPCError) error + AddError(requestType string, responseError *eth.JSONRPCError) error + AddErrorWithRequestID(requestID int, requestType string, responseError *eth.JSONRPCError) error } func NewDoerMappedMock() *doerMappedMock { @@ -102,7 +101,7 @@ func NewEchoWithContext(ctx context.Context) echo.Context { return echo.New().NewContext((&http.Request{}).WithContext(ctx), nil) } -func prepareRawResponse(requestID int, responseResult interface{}, responseError eth.JSONRPCError) ([]byte, error) { +func prepareRawResponse(requestID int, responseResult interface{}, responseError *eth.JSONRPCError) ([]byte, error) { requestIDRaw, err := json.Marshal(requestID) if err != nil { return nil, err @@ -188,7 +187,7 @@ func (d *doerMappedMock) AddResponseWithRequestID(requestID int, requestType str return nil } -func (d *doerMappedMock) AddError(requestType string, responseError eth.JSONRPCError) error { +func (d *doerMappedMock) AddError(requestType string, responseError *eth.JSONRPCError) error { d.mutex.Lock() defer d.mutex.Unlock() requestID := d.latestId + 1 @@ -202,7 +201,7 @@ func (d *doerMappedMock) AddError(requestType string, responseError eth.JSONRPCE return nil } -func (d *doerMappedMock) AddErrorWithRequestID(requestID int, requestType string, responseError eth.JSONRPCError) error { +func (d *doerMappedMock) AddErrorWithRequestID(requestID int, requestType string, responseError *eth.JSONRPCError) error { d.mutex.Lock() defer d.mutex.Unlock() responseRaw, err := prepareRawResponse(requestID, nil, responseError) @@ -230,28 +229,28 @@ func parseRequestFromBody(request *http.Request) (*eth.JSONRPCRequest, error) { return &requestJSON, err } -func CreateMockedClient(doerInstance Doer) (qtumClient *qtum.Qtum, err error) { +func CreateMockedClient(doerInstance Doer) (kaonClient *kaon.Kaon, err error) { return CreateMockedClientForNetwork(doerInstance, "test") } -func CreateMockedClientForNetwork(doerInstance Doer, network string) (qtumClient *qtum.Qtum, err error) { +func CreateMockedClientForNetwork(doerInstance Doer, network string) (kaonClient *kaon.Kaon, err error) { logger := kitLog.NewLogfmtLogger(os.Stdout) if !isDebugEnvironmentVariableSet() { logger = level.NewFilter(logger, level.AllowWarn()) } - qtumJSONRPC, err := qtum.NewClient( + kaonJSONRPC, err := kaon.NewClient( true, "http://user:pass@mocked", - qtum.SetDoer(doerInstance), - qtum.SetDebug(isDebugEnvironmentVariableSet()), - qtum.SetLogger(logger), - qtum.SetAnalytics(analytics.NewAnalytics(10)), + kaon.SetDoer(doerInstance), + kaon.SetDebug(isDebugEnvironmentVariableSet()), + kaon.SetLogger(logger), + kaon.SetAnalytics(analytics.NewAnalytics(10)), ) if err != nil { return } - qtumClient, err = qtum.New(qtumJSONRPC, network) + kaonClient, err = kaon.New(kaonJSONRPC, network) return } @@ -280,10 +279,11 @@ var ( Nonce: "0x0", Value: "0x0", Input: "0x020000000159c0514feea50f915854d9ec45bc6458bb14419c78b17e7be3f7fd5f563475b5010000006a473044022072d64a1f4ea2d54b7b05050fc853ab192c91cc5ca17e23007867f92f2ab59d9202202b8c9ab9348c8edbb3b98b1788382c8f37642ec9bd6a4429817ab79927319200012103520b1500a400483f19b93c4cb277a2f29693ea9d6739daaf6ae6e971d29e3140feffffff02000000000000000063010403400d0301644440c10f190000000000000000000000006b22910b1e302cf74803ffd1691c2ecb858d3712000000000000000000000000000000000000000000000000000000000000000a14be528c8378ff082e4ba43cb1baa363dbf3f577bfc260e66272970100001976a9146b22910b1e302cf74803ffd1691c2ecb858d371288acb00f0000", - From: "0x7926223070547d2d15b2ef5e7383e541c338ffe9", + From: "0x1CE507204a6fC8fd6aA7e54D1481d30ACB0Dbead", To: "0x0000000000000000000000000000000000000000", Gas: "0x0", GasPrice: "0x0", + CumulativeGas: "0x0", R: "0xf000000000000000000000000000000000000000000000000000000000000000", S: "0xf000000000000000000000000000000000000000000000000000000000000000", V: "0x25", @@ -305,7 +305,7 @@ var ( TotalDifficulty: "0x4", LogsBloom: eth.EmptyLogsBloom, ExtraData: "0x0000000000000000000000000000000000000000000000000000000000000000", - GasLimit: utils.AddHexPrefix(qtum.DefaultBlockGasLimit), + GasLimit: utils.AddHexPrefix(kaon.DefaultBlockGasLimit), GasUsed: "0x0", Timestamp: "0x5b95ebd0", Transactions: []interface{}{ @@ -330,7 +330,7 @@ var ( TotalDifficulty: "0x4", LogsBloom: eth.EmptyLogsBloom, ExtraData: "0x0000000000000000000000000000000000000000000000000000000000000000", - GasLimit: utils.AddHexPrefix(qtum.DefaultBlockGasLimit), + GasLimit: utils.AddHexPrefix(kaon.DefaultBlockGasLimit), GasUsed: "0x0", Timestamp: "0x5b95ebd0", Transactions: []interface{}{"0x3208dc44733cbfa11654ad5651305428de473ef1e61a1ec07b0c1a5f4843be91", @@ -353,7 +353,7 @@ var ( TotalDifficulty: "0x4", LogsBloom: eth.EmptyLogsBloom, ExtraData: "0x0000000000000000000000000000000000000000000000000000000000000000", - GasLimit: utils.AddHexPrefix(qtum.DefaultBlockGasLimit), + GasLimit: utils.AddHexPrefix(kaon.DefaultBlockGasLimit), GasUsed: "0x0", Timestamp: "0x5b95ebd0", Transactions: []interface{}{ @@ -364,7 +364,7 @@ var ( Uncles: []string{}, } - GetBlockResponse = qtum.GetBlockResponse{ + GetBlockResponse = kaon.GetBlockResponse{ Hash: GetTransactionByHashBlockHash, Confirmations: 1, Strippedsize: 584, @@ -386,7 +386,7 @@ var ( Flags: "proof-of-stake", Proofhash: "15bd6006ecbab06708f705ecf68664b78b388e4d51416cdafb019d5b90239877", Modifier: "a79c00d1d570743ca8135a173d535258026d26bafbc5f3d951c3d33486b1f120", - Txs: []string{"3208dc44733cbfa11654ad5651305428de473ef1e61a1ec07b0c1a5f4843be91", + Txs: []interface{}{"3208dc44733cbfa11654ad5651305428de473ef1e61a1ec07b0c1a5f4843be91", "8fcd819194cce6a8454b2bec334d3448df4f097e9cdc36707bfd569900268950"}, Nextblockhash: "d7758774cfdd6bab7774aa891ae035f1dc5a2ff44240784b5e7bdfd43a7a6ec1", Signature: "3045022100a6ab6c2b14b1f73e734f1a61d4d22385748e48836492723a6ab37cdf38525aba022014a51ecb9e51f5a7a851641683541fec6f8f20205d0db49e50b2a4e5daed69d2", @@ -408,7 +408,7 @@ func CreateTransactionByHashResponse() eth.GetBlockByHashResponse { TotalDifficulty: "0x4", LogsBloom: eth.EmptyLogsBloom, ExtraData: "0x0000000000000000000000000000000000000000000000000000000000000000", - GasLimit: utils.AddHexPrefix(qtum.DefaultBlockGasLimit), + GasLimit: utils.AddHexPrefix(kaon.DefaultBlockGasLimit), GasUsed: "0x0", Timestamp: "0x5b95ebd0", Transactions: []interface{}{"0x3208dc44733cbfa11654ad5651305428de473ef1e61a1ec07b0c1a5f4843be91", @@ -418,31 +418,31 @@ func CreateTransactionByHashResponse() eth.GetBlockByHashResponse { } } -func QtumTransactionReceipt(logs []qtum.Log) qtum.TransactionReceipt { - return qtum.TransactionReceipt{ +func KaonTransactionReceipt(logs []kaon.Log) kaon.TransactionReceipt { + return kaon.TransactionReceipt{ BlockHash: GetTransactionByHashBlockHexHash, BlockNumber: GetTransactionByHashBlockNumberInteger, TransactionHash: GetTransactionByHashResponseData.Hash, TransactionIndex: hexutil.MustDecodeUint64(GetTransactionByHashResponseData.TransactionIndex), From: GetTransactionByHashResponseData.From, To: GetTransactionByHashResponseData.To, - CumulativeGasUsed: hexutil.MustDecodeUint64(GetTransactionByHashResponseData.Gas), - GasUsed: hexutil.MustDecodeUint64(GetTransactionByHashResponseData.Gas), + CumulativeGasUsed: *hexutil.MustDecodeBig(GetTransactionByHashResponseData.CumulativeGas), + GasUsed: *hexutil.MustDecodeBig(GetTransactionByHashResponseData.Gas), ContractAddress: GetTransactionByHashResponseData.To, Log: logs, } } -func QtumWaitForLogsEntry(log qtum.Log) qtum.WaitForLogsEntry { - return qtum.WaitForLogsEntry{ +func KaonWaitForLogsEntry(log kaon.Log) kaon.WaitForLogsEntry { + return kaon.WaitForLogsEntry{ BlockHash: GetTransactionByHashBlockHexHash, BlockNumber: GetTransactionByHashBlockNumberInteger, TransactionHash: GetTransactionByHashResponseData.Hash, TransactionIndex: hexutil.MustDecodeUint64(GetTransactionByHashResponseData.TransactionIndex), From: GetTransactionByHashResponseData.From, To: GetTransactionByHashResponseData.To, - CumulativeGasUsed: hexutil.MustDecodeUint64(GetTransactionByHashResponseData.Gas), - GasUsed: hexutil.MustDecodeUint64(GetTransactionByHashResponseData.Gas), + CumulativeGasUsed: *hexutil.MustDecodeBig(GetTransactionByHashResponseData.CumulativeGas), + GasUsed: *hexutil.MustDecodeBig(GetTransactionByHashResponseData.Gas), ContractAddress: strings.TrimPrefix(GetTransactionByHashResponseData.To, "0x"), Topics: log.Topics, Data: log.Data, @@ -450,18 +450,18 @@ func QtumWaitForLogsEntry(log qtum.Log) qtum.WaitForLogsEntry { } func SetupGetBlockByHashResponses(t *testing.T, mockedClientDoer Doer) { - SetupGetBlockByHashResponsesWithVouts(t, []*qtum.DecodedRawTransactionOutV{}, mockedClientDoer) + SetupGetBlockByHashResponsesWithVouts(t, []*kaon.DecodedRawTransactionOutV{}, mockedClientDoer) } -func SetupGetBlockByHashResponsesWithVouts(t *testing.T, vouts []*qtum.DecodedRawTransactionOutV, mockedClientDoer Doer) { +func SetupGetBlockByHashResponsesWithVouts(t *testing.T, vouts []*kaon.DecodedRawTransactionOutV, mockedClientDoer Doer) { //preparing answer to "getblockhash" - getBlockHashResponse := qtum.GetBlockHashResponse(GetTransactionByHashBlockHexHash) - err := mockedClientDoer.AddResponse(qtum.MethodGetBlockHash, getBlockHashResponse) + getBlockHashResponse := kaon.GetBlockHashResponse(GetTransactionByHashBlockHexHash) + err := mockedClientDoer.AddResponse(kaon.MethodGetBlockHash, getBlockHashResponse) if err != nil { t.Fatal(err) } - getBlockHeaderResponse := qtum.GetBlockHeaderResponse{ + getBlockHeaderResponse := kaon.GetBlockHeaderResponse{ Hash: GetTransactionByHashBlockHash, Confirmations: 1, Height: 3983, @@ -481,19 +481,19 @@ func SetupGetBlockByHashResponsesWithVouts(t *testing.T, vouts []*qtum.DecodedRa Proofhash: "15bd6006ecbab06708f705ecf68664b78b388e4d51416cdafb019d5b90239877", Modifier: "a79c00d1d570743ca8135a173d535258026d26bafbc5f3d951c3d33486b1f120", } - err = mockedClientDoer.AddResponse(qtum.MethodGetBlockHeader, getBlockHeaderResponse) + err = mockedClientDoer.AddResponse(kaon.MethodGetBlockHeader, getBlockHeaderResponse) if err != nil { t.Fatal(err) } - err = mockedClientDoer.AddResponse(qtum.MethodGetBlock, GetBlockResponse) + err = mockedClientDoer.AddResponse(kaon.MethodGetBlock, GetBlockResponse) if err != nil { t.Fatal(err) } - getTransactionResponse := qtum.GetTransactionResponse{ - Amount: decimal.NewFromFloat(0.20689141), - Fee: decimal.NewFromFloat(-0.2012), + getTransactionResponse := kaon.GetTransactionResponse{ + Amount: kaon.NewFromFloat(0.20689141), + Fee: kaon.NewFromFloat(-0.2012), Confirmations: 2, BlockHash: GetTransactionByHashBlockHash, BlockIndex: 2, @@ -502,72 +502,71 @@ func SetupGetBlockByHashResponsesWithVouts(t *testing.T, vouts []*qtum.DecodedRa Time: 1533092879, ReceivedAt: 1533092879, Bip125Replaceable: "no", - Details: []*qtum.TransactionDetail{{Account: "", - Category: "send", - Amount: decimal.NewFromInt(0), + Details: []*kaon.TransactionDetail{{Category: "send", + Amount: kaon.NewFromInt(0), Vout: 0, - Fee: decimal.NewFromFloat(-0.2012), + Fee: kaon.NewFromFloat(-0.2012), Abandoned: false}}, Hex: "020000000159c0514feea50f915854d9ec45bc6458bb14419c78b17e7be3f7fd5f563475b5010000006a473044022072d64a1f4ea2d54b7b05050fc853ab192c91cc5ca17e23007867f92f2ab59d9202202b8c9ab9348c8edbb3b98b1788382c8f37642ec9bd6a4429817ab79927319200012103520b1500a400483f19b93c4cb277a2f29693ea9d6739daaf6ae6e971d29e3140feffffff02000000000000000063010403400d0301644440c10f190000000000000000000000006b22910b1e302cf74803ffd1691c2ecb858d3712000000000000000000000000000000000000000000000000000000000000000a14be528c8378ff082e4ba43cb1baa363dbf3f577bfc260e66272970100001976a9146b22910b1e302cf74803ffd1691c2ecb858d371288acb00f0000", } - err = mockedClientDoer.AddResponse(qtum.MethodGetTransaction, getTransactionResponse) + err = mockedClientDoer.AddResponse(kaon.MethodGetTransaction, getTransactionResponse) if err != nil { t.Fatal(err) } - decodedRawTransactionResponse := qtum.DecodedRawTransactionResponse{ + decodedRawTransactionResponse := kaon.DecodedRawTransactionResponse{ ID: "11e97fa5877c5df349934bafc02da6218038a427e8ed081f048626fa6eb523f5", Hash: "d0fe0caa1b798c36da37e9118a06a7d151632d670b82d1c7dc3985577a71880f", Size: 552, Vsize: 552, Version: 2, Locktime: 608, - Vins: []*qtum.DecodedRawTransactionInV{{ + Vins: []*kaon.DecodedRawTransactionInV{{ TxID: "7f5350dc474f2953a3f30282c1afcad2fb61cdcea5bd949c808ecc6f64ce1503", Vout: 0, - ScriptSig: qtum.DecodedRawTransactionScriptSig{ - Asm: "3045022100af4de764705dbd3c0c116d73fe0a2b78c3fab6822096ba2907cfdae2bb28784102206304340a6d260b364ef86d6b19f2b75c5e55b89fb2f93ea72c05e09ee037f60b[ALL] 03520b1500a400483f19b93c4cb277a2f29693ea9d6739daaf6ae6e971d29e3140", + ScriptSig: kaon.DecodedRawTransactionScriptSig{ + ASM: "3045022100af4de764705dbd3c0c116d73fe0a2b78c3fab6822096ba2907cfdae2bb28784102206304340a6d260b364ef86d6b19f2b75c5e55b89fb2f93ea72c05e09ee037f60b[ALL] 03520b1500a400483f19b93c4cb277a2f29693ea9d6739daaf6ae6e971d29e3140", Hex: "483045022100af4de764705dbd3c0c116d73fe0a2b78c3fab6822096ba2907cfdae2bb28784102206304340a6d260b364ef86d6b19f2b75c5e55b89fb2f93ea72c05e09ee037f60b012103520b1500a400483f19b93c4cb277a2f29693ea9d6739daaf6ae6e971d29e3140", }, }}, Vouts: vouts, } - err = mockedClientDoer.AddResponse(qtum.MethodDecodeRawTransaction, decodedRawTransactionResponse) + err = mockedClientDoer.AddResponse(kaon.MethodDecodeRawTransaction, decodedRawTransactionResponse) if err != nil { t.Fatal(err) } - getTransactionReceiptResponse := qtum.GetTransactionReceiptResponse{} - err = mockedClientDoer.AddResponse(qtum.MethodGetTransactionReceipt, &getTransactionReceiptResponse) + getTransactionReceiptResponse := kaon.GetTransactionReceiptResponse{} + err = mockedClientDoer.AddResponse(kaon.MethodGetTransactionReceipt, &getTransactionReceiptResponse) if err != nil { t.Fatal(err) } // TODO: Get an actual response for this (only addresses are used in this test though) - getRawTransactionResponse := qtum.GetRawTransactionResponse{ - Vins: []qtum.RawTransactionVin{ + getRawTransactionResponse := kaon.GetRawTransactionResponse{ + Vins: []kaon.RawTransactionVin{ { Address: "QXeZZ5MsAF5pPrPy47ZFMmtCpg7RExT4mi", }, }, - Vouts: []qtum.RawTransactionVout{ + Vouts: []kaon.RawTransactionVout{ { - Details: qtum.RawTransactionVoutDetails{ + Details: kaon.RawTransactionVoutDetails{ Addresses: []string{ - "7926223070547d2d15b2ef5e7383e541c338ffe9", // This address is hex format but should be base58, but it doesn't appear to be in use right now anyway + "1CE507204a6fC8fd6aA7e54D1481d30ACB0Dbead", // This address is hex format but should be base58, but it doesn't appear to be in use right now anyway }, }, }, }, } - err = mockedClientDoer.AddResponse(qtum.MethodGetRawTransaction, &getRawTransactionResponse) + err = mockedClientDoer.AddResponse(kaon.MethodGetRawTransaction, &getRawTransactionResponse) if err != nil { t.Fatal(err) } } // Function to provide informative debug text on mismatching values between two structs of same type. -// TODO: Handle unexported struct fields, like in TestEthValueToQtumAmount (pkg/transformer/util_test) +// TODO: Handle unexported struct fields, like in TestEthValueToKaonAmount (pkg/transformer/util_test) func DeepCompareStructs(want interface{}, got interface{}, indentStr string, traceStr string) (string, bool) { report := "" isEqual := true diff --git a/pkg/internal/tests_transformer.go b/pkg/internal/tests_transformer.go index 3c97ab8a..0eb11465 100644 --- a/pkg/internal/tests_transformer.go +++ b/pkg/internal/tests_transformer.go @@ -1,13 +1,13 @@ package internal import ( + "github.com/kaonone/eth-rpc-gate/pkg/eth" "github.com/labstack/echo" "github.com/pkg/errors" - "github.com/qtumproject/janus/pkg/eth" ) type ETHProxy interface { - Request(*eth.JSONRPCRequest, echo.Context) (interface{}, eth.JSONRPCError) + Request(*eth.JSONRPCRequest, echo.Context) (interface{}, *eth.JSONRPCError) Method() string } @@ -15,7 +15,7 @@ type mockTransformer struct { proxies map[string]ETHProxy } -func (t *mockTransformer) Transform(req *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (t *mockTransformer) Transform(req *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { proxy, ok := t.proxies[req.Method] if !ok { return nil, eth.NewCallbackError("couldn't get proxy") @@ -55,7 +55,7 @@ func NewMockETHProxy(method string, response interface{}) ETHProxy { } } -func (e *mockETHProxy) Request(*eth.JSONRPCRequest, echo.Context) (interface{}, eth.JSONRPCError) { +func (e *mockETHProxy) Request(*eth.JSONRPCRequest, echo.Context) (interface{}, *eth.JSONRPCError) { return e.response, nil } diff --git a/pkg/qtum/account.go b/pkg/kaon/account.go similarity index 69% rename from pkg/qtum/account.go rename to pkg/kaon/account.go index 2c2c274e..3673edc3 100644 --- a/pkg/qtum/account.go +++ b/pkg/kaon/account.go @@ -1,4 +1,4 @@ -package qtum +package kaon import ( "encoding/hex" @@ -32,21 +32,21 @@ func (a *Account) ToHexAddress() string { return hex.EncodeToString(keyid) } -var qtumMainNetParams = chaincfg.MainNetParams -var qtumTestNetParams = chaincfg.MainNetParams +var kaonMainNetParams = chaincfg.MainNetParams +var kaonTestNetParams = chaincfg.MainNetParams func init() { - qtumMainNetParams.PubKeyHashAddrID = 58 - qtumMainNetParams.ScriptHashAddrID = 50 + kaonMainNetParams.PubKeyHashAddrID = 58 + kaonMainNetParams.ScriptHashAddrID = 50 - qtumTestNetParams.PubKeyHashAddrID = 120 - qtumTestNetParams.ScriptHashAddrID = 110 + kaonTestNetParams.PubKeyHashAddrID = 120 + kaonTestNetParams.ScriptHashAddrID = 110 } func (a *Account) ToBase58Address(isMain bool) (string, error) { - params := &qtumMainNetParams + params := &kaonMainNetParams if !isMain { - params = &qtumTestNetParams + params = &kaonTestNetParams } addr, err := btcutil.NewAddressPubKey(a.SerializePubKey(), params) diff --git a/pkg/qtum/btcasm.go b/pkg/kaon/btcasm.go similarity index 59% rename from pkg/qtum/btcasm.go rename to pkg/kaon/btcasm.go index 1b8f44f3..63b90ca7 100644 --- a/pkg/qtum/btcasm.go +++ b/pkg/kaon/btcasm.go @@ -1,12 +1,12 @@ -package qtum +package kaon import ( - "encoding/hex" "fmt" - "strings" + "math/big" + "strconv" + "github.com/kaonone/eth-rpc-gate/pkg/utils" "github.com/pkg/errors" - "github.com/qtumproject/btcd/txscript" ) type ( @@ -20,8 +20,35 @@ type ( } ) -func ParseCallASM(parts []string) (*ContractInvokeInfo, error) { +// Given a hex string, reverse the order of the bytes +// Used in special cases when gasLimit and gasPrice are 'bigendian hex encoded' +func reversePartToHex(s string) (string, error) { + runes := []rune(s) + for i, j := 0, len(runes)-1; i < j; i, j = i+2, j-2 { + runes[i], runes[i+1], runes[j-1], runes[j] = runes[j-1], runes[j], runes[i], runes[i+1] + } + partInt, err := strconv.ParseInt(string(runes), 16, 64) + if err != nil { + return "", err + } + partHex := strconv.FormatInt(partInt, 16) + return partHex, nil +} + +func ParseP2PKHReciever(parts []string) (*string, error) { + // OP_DUP + // OP_HASH160_COMPAT + // OP_PUBKEYHASH - zZkaonAddr - base58 reciever addr + // OP_EQUALVERIFY + // OP_CHECKSIG + if len(parts) != 5 { + return nil, errors.New(fmt.Sprintf("invalid Pay2PKH script for parts 5: %v", parts)) + } + return &parts[2], nil +} + +func ParseCallASM(parts []string) (*ContractInvokeInfo, error) { // "4 25548 40 8588b2c50000000000000000000000000000000000000000000000000000000000000000 57946bb437560b13275c32a468c6fd1e0c2cdd48 OP_CAL" // 4 // EVM version @@ -35,13 +62,21 @@ func ParseCallASM(parts []string) (*ContractInvokeInfo, error) { return nil, errors.New(fmt.Sprintf("invalid OP_CALL script for parts 6: %v", parts)) } - gasLimit, err := convertToBigEndian(parts[1]) + //! For some TXs we get the following string with GasPrice and/or GasLimit encoded as 'big endian' hex: + //"4 90d0030000000000 2800000000000000 a9059cbb0000000000000000000000008e60e0b8371c0312cfc703e5e28bc57dfa0674fd0000000000000000000000000000000000000000000000000000000005f5e100 f2703e93f87b846a7aacec1247beaec1c583daa4 OP_CALL" + //! Current fix checks if GasLimit or GasPrice are hex encoded, then reverts the order of the bytes + //! in GasPrice and GasLimit fields and returns the correct hex values. + // i.e. gasLimit = "90d0030000000000" is returned as "0x3d090" + //! This approach will fail to detect the case where the GasPrice and GasLimit are encoded as hex but 'stringBase10ToHex' does not return an error. + // TODO: research alternative approach to fix this. + gasLimit, gasPrice, err := parseGasFields(parts[1], parts[2]) if err != nil { return nil, err } return &ContractInvokeInfo{ - GasPrice: parts[2], + // From: parts[1], + GasPrice: gasPrice, GasLimit: gasLimit, CallData: parts[3], To: parts[4], @@ -52,13 +87,8 @@ func ParseCallASM(parts []string) (*ContractInvokeInfo, error) { func ParseCallSenderASM(parts []string) (*ContractInvokeInfo, error) { // See: https://github.com/qtumproject/qips/issues/6 - // "1 7926223070547d2d15b2ef5e7383e541c338ffe9 69463043021f3ba540f52e0bae0c608c3d7135424fb683c77ee03217fcfe0af175c586aadc02200222e460a42268f02f130bc46f3ef62f228dd8051756dc13693332423515fcd401210299d391f528b9edd07284c7e23df8415232a8ce41531cf460a390ce32b4efd112 OP_SENDER 4 40000000 40 60fe47b10000000000000000000000000000000000000000000000000000000000000319 9e11fba86ee5d0ba4996b0d1973de6b694f4fc95 OP_CALL" - - if len(parts) != 10 { - return nil, errors.New(fmt.Sprintf("invalid create_sender script for parts 10: %v", parts)) - } - - // 1 // address type of the pubkeyhash (public key hash) + // "1 1CE507204a6fC8fd6aA7e54D1481d30ACB0Dbead 69463043021f3ba540f52e0bae0c608c3d7135424fb683c77ee03217fcfe0af175c586aadc02200222e460a42268f02f130bc46f3ef62f228dd8051756dc13693332423515fcd401210299d391f528b9edd07284c7e23df8415232a8ce41531cf460a390ce32b4efd112 OP_SENDER 4 40000000 40 60fe47b10000000000000000000000000000000000000000000000000000000000000319 9e11fba86ee5d0ba4996b0d1973de6b694f4fc95 OP_CALL" + // 1 // address type of the pubkeyhash (public key hash) // Address // sender's pubkeyhash address // {signature, pubkey} // serialized scriptSig // OP_SENDER @@ -69,14 +99,18 @@ func ParseCallSenderASM(parts []string) (*ContractInvokeInfo, error) { // Contract Address // contract address // OP_CALL - gasLimit, err := convertToBigEndian(parts[5]) + if len(parts) != 10 { + return nil, errors.New(fmt.Sprintf("invalid create_sender script for parts 10: %v", parts)) + } + + gasLimit, gasPrice, err := parseGasFields(parts[5], parts[6]) if err != nil { return nil, err } return &ContractInvokeInfo{ From: parts[1], - GasPrice: parts[6], + GasPrice: gasPrice, GasLimit: gasLimit, CallData: parts[7], To: parts[8], @@ -85,36 +119,40 @@ func ParseCallSenderASM(parts []string) (*ContractInvokeInfo, error) { } func ParseCreateASM(parts []string) (*ContractInvokeInfo, error) { - + // OP_CREATE prefixed by OP_SENDER always have this structure: + // + // 1 // address type of the pubkeyhash (public key hash) + // Address // sender's pubkeyhash address + // {signature, pubkey} // serialized scriptSig + // OP_SENDER // 4 // EVM version // 100000 // gas limit // 10 // gas price // 1234 // data to be sent by the contract // OP_CREATE - if len(parts) != 5 { - return nil, errors.New(fmt.Sprintf("invalid OP_CREATE script for parts 5: %v", len(parts))) + if len(parts) < 5 { + return nil, nil } - gasLimit, err := convertToBigEndian(parts[1]) + gasLimit, gasPrice, err := parseGasFields(parts[1], parts[2]) if err != nil { return nil, err } - info := &ContractInvokeInfo{ - GasPrice: parts[2], + From: parts[1], + GasPrice: gasPrice, GasLimit: gasLimit, CallData: parts[3], } return info, nil - } func ParseCreateSenderASM(parts []string) (*ContractInvokeInfo, error) { // See: https://github.com/qtumproject/qips/issues/6 // https://blog.qtum.org/qip-5-add-op-sender-opcode-571511802938 - // "1 7926223070547d2d15b2ef5e7383e541c338ffe9 6a473044022067ca66b0308ae16aeca7a205ce0490b44a61feebe5632710b52aabde197f9e4802200e8beec61a58dbe1279a9cdb68983080052ae7b9997bc863b7c5623e4cb55fd + // "1 1CE507204a6fC8fd6aA7e54D1481d30ACB0Dbead 6a473044022067ca66b0308ae16aeca7a205ce0490b44a61feebe5632710b52aabde197f9e4802200e8beec61a58dbe1279a9cdb68983080052ae7b9997bc863b7c5623e4cb55fd // b01210299d391f528b9edd07284c7e23df8415232a8ce41531cf460a390ce32b4efd112 OP_SENDER 4 6721975 100 6060604052341561000f57600080fd5b60008054600160a060020a033316600160a060020a03199091161790556101de8061003b6000 // 396000f300606060405263ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630900f010811461005d578063445df0ac1461007e5780638da5cb5b146100a3578063fdacd576146100d257600080fd5b341561 // 006857600080fd5b61007c600160a060020a03600435166100e8565b005b341561008957600080fd5b61009161017d565b60405190815260200160405180910390f35b34156100ae57600080fd5b6100b6610183565b604051600160a060020a039091168152 @@ -136,42 +174,41 @@ func ParseCreateSenderASM(parts []string) (*ContractInvokeInfo, error) { return nil, errors.New(fmt.Sprintf("invalid create_sender script for parts 9: %v", len(parts))) } - gasLimit, err := convertToBigEndian(parts[5]) + gasLimit, gasPrice, err := parseGasFields(parts[5], parts[6]) if err != nil { return nil, err } - info := &ContractInvokeInfo{ From: parts[1], - GasPrice: parts[6], + GasPrice: gasPrice, GasLimit: gasLimit, CallData: parts[7], } return info, nil } -// function disasm converts the hex string (from the pubkey) to an asm string -func DisasmScript(scriptHex string) (string, error) { - scriptBytes, err := hex.DecodeString(scriptHex) - if err != nil { - return "", err +func stringBase10ToHex(str string) (string, error) { + var v big.Int + _, ok := v.SetString(str, 0) + if !ok { + return "", errors.Errorf("Failed to parse big.Int: %s", str) } - disasm, err := txscript.DisasmString(scriptBytes) - if err != nil { - return "", err - } - return disasm, nil + + return utils.AddHexPrefix(v.Text(16)), nil } -// convertToBigEndian is a helper function to convert 'gasLimit' hex to big endian -func convertToBigEndian(hex string) (string, error) { - if len(hex)%2 != 0 { - return "", fmt.Errorf("invalid hex string") - } - var result string - for i := len(hex); i > 0; i -= 2 { - result += hex[i-2 : i] +func parseGasFields(gasLimitPart, gasPricePart string) (string, string, error) { + gasLimit, err1 := stringBase10ToHex(utils.AddHexPrefix(gasLimitPart)) + gasPrice, err2 := stringBase10ToHex(utils.AddHexPrefix(gasPricePart)) + if err1 != nil || err2 != nil { + gasLimit, err1 = reversePartToHex(gasLimitPart) + if err1 != nil { + return "", "", err1 + } + gasPrice, err2 = reversePartToHex(gasPricePart) + if err2 != nil { + return "", "", err2 + } } - // trim leading zeros before returning - return strings.TrimLeft(result, "0"), nil + return gasLimit, gasPrice, nil } diff --git a/pkg/kaon/btcasm_test.go b/pkg/kaon/btcasm_test.go new file mode 100644 index 00000000..e1e79141 --- /dev/null +++ b/pkg/kaon/btcasm_test.go @@ -0,0 +1,93 @@ +package kaon + +import ( + "encoding/json" + "reflect" + "strings" + "testing" +) + +func TestParseCallSenderASM(t *testing.T) { + samStr := "1 1CE507204a6fC8fd6aA7e54D1481d30ACB0Dbead 69463043021f3ba540f52e0bae0c608c3d7135424fb683c77ee03217fcfe0af175c586aadc02200222e460a42268f02f130bc46f3ef62f228dd8051756dc13693332423515fcd401210299d391f528b9edd07284c7e23df8415232a8ce41531cf460a390ce32b4efd112 OP_SENDER 4 40000000 40 60fe47b10000000000000000000000000000000000000000000000000000000000000319 9e11fba86ee5d0ba4996b0d1973de6b694f4fc95 OP_CALL" + got, err := ParseCallSenderASM(strings.Split(samStr, " ")) + if err != nil { + t.Error(err) + } + want := &ContractInvokeInfo{ + From: "1CE507204a6fC8fd6aA7e54D1481d30ACB0Dbead", + GasLimit: "2625a00", + GasPrice: "28", + CallData: "60fe47b10000000000000000000000000000000000000000000000000000000000000319", + To: "9e11fba86ee5d0ba4996b0d1973de6b694f4fc95", + } + if !reflect.DeepEqual(got, want) { + t.Errorf( + "parse transaction call sam error\ninput: %s\nwant: %s\ngot: %s", + samStr, + string(mustMarshalIndent(want, "", " ")), + string(mustMarshalIndent(got, "", " ")), + ) + } +} + +func TestParseParseCreateSenderASM(t *testing.T) { + samStr := "1 1CE507204a6fC8fd6aA7e54D1481d30ACB0Dbead 6a473044022067ca66b0308ae16aeca7a205ce0490b44a61feebe5632710b52aabde197f9e4802200e8beec61a58dbe1279a9cdb68983080052ae7b9997bc863b7c5623e4cb55fdb01210299d391f528b9edd07284c7e23df8415232a8ce41531cf460a390ce32b4efd112 OP_SENDER 4 6721975 100 6060604052341561000f57600080fd5b60008054600160a060020a033316600160a060020a03199091161790556101de8061003b6000396000f300606060405263ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630900f010811461005d578063445df0ac1461007e5780638da5cb5b146100a3578063fdacd576146100d257600080fd5b341561006857600080fd5b61007c600160a060020a03600435166100e8565b005b341561008957600080fd5b61009161017d565b60405190815260200160405180910390f35b34156100ae57600080fd5b6100b6610183565b604051600160a060020a03909116815260200160405180910390f35b34156100dd57600080fd5b61007c600435610192565b6000805433600160a060020a03908116911614156101795781905080600160a060020a031663fdacd5766001546040517c010000000000000000000000000000000000000000000000000000000063ffffffff84160281526004810191909152602401600060405180830381600087803b151561016457600080fd5b6102c65a03f1151561017557600080fd5b5050505b5050565b60015481565b600054600160a060020a031681565b60005433600160a060020a03908116911614156101af5760018190555b505600a165627a7a72305820b6a912c5b5115d1a5412235282372dc4314f325bac71ee6c8bd18f658d7ed1ad0029 OP_CREATE" + got, err := ParseCreateSenderASM(strings.Split(samStr, " ")) + if err != nil { + t.Error(err) + } + want := &ContractInvokeInfo{ + From: "1CE507204a6fC8fd6aA7e54D1481d30ACB0Dbead", + GasLimit: "6691b7", + GasPrice: "64", + CallData: "6060604052341561000f57600080fd5b60008054600160a060020a033316600160a060020a03199091161790556101de8061003b6000396000f300606060405263ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630900f010811461005d578063445df0ac1461007e5780638da5cb5b146100a3578063fdacd576146100d257600080fd5b341561006857600080fd5b61007c600160a060020a03600435166100e8565b005b341561008957600080fd5b61009161017d565b60405190815260200160405180910390f35b34156100ae57600080fd5b6100b6610183565b604051600160a060020a03909116815260200160405180910390f35b34156100dd57600080fd5b61007c600435610192565b6000805433600160a060020a03908116911614156101795781905080600160a060020a031663fdacd5766001546040517c010000000000000000000000000000000000000000000000000000000063ffffffff84160281526004810191909152602401600060405180830381600087803b151561016457600080fd5b6102c65a03f1151561017557600080fd5b5050505b5050565b60015481565b600054600160a060020a031681565b60005433600160a060020a03908116911614156101af5760018190555b505600a165627a7a72305820b6a912c5b5115d1a5412235282372dc4314f325bac71ee6c8bd18f658d7ed1ad0029", + To: "", + } + if !reflect.DeepEqual(got, want) { + t.Errorf( + "parse transaction call sam error\ninput: %s\nwant: %s\ngot: %s", + samStr, + string(mustMarshalIndent(want, "", " ")), + string(mustMarshalIndent(got, "", " ")), + ) + } +} + +func TestParseCallASM(t *testing.T) { + // EVMversion := "4" + // gasLimit := "250000" + // gasPrice := "40" + byteCode := "a9059cbb0000000000000000000000008e60e0b8371c0312cfc703e5e28bc57dfa0674fd0000000000000000000000000000000000000000000000000000000005f5e100" + contractAddr := "f2703e93f87b846a7aacec1247beaec1c583daa4" + // opcode := "OP_CALL" + + samStr := "4 90d0030000000000 2800000000000000 a9059cbb0000000000000000000000008e60e0b8371c0312cfc703e5e28bc57dfa0674fd0000000000000000000000000000000000000000000000000000000005f5e100 f2703e93f87b846a7aacec1247beaec1c583daa4 OP_CALL" + + got, err := ParseCallASM(strings.Split(samStr, " ")) + if err != nil { + t.Error(err) + } + want := &ContractInvokeInfo{ + From: "", + GasLimit: "3d090", + GasPrice: "28", + CallData: byteCode, + To: contractAddr, + } + if !reflect.DeepEqual(got, want) { + t.Errorf( + "parse transaction call sam error\ninput: %s\nwant: %s\ngot: %s", + samStr, + string(mustMarshalIndent(want, "", " ")), + string(mustMarshalIndent(got, "", " ")), + ) + } +} + +func mustMarshalIndent(v interface{}, prefix, indent string) []byte { + res, err := json.MarshalIndent(v, prefix, indent) + if err != nil { + panic(err) + } + return res +} diff --git a/pkg/qtum/client.go b/pkg/kaon/client.go similarity index 86% rename from pkg/qtum/client.go rename to pkg/kaon/client.go index 017d2e25..3854ce2b 100644 --- a/pkg/qtum/client.go +++ b/pkg/kaon/client.go @@ -1,4 +1,4 @@ -package qtum +package kaon import ( "bytes" @@ -19,18 +19,18 @@ import ( "github.com/go-kit/log" "github.com/go-kit/log/level" + "github.com/kaonone/eth-rpc-gate/pkg/analytics" + "github.com/kaonone/eth-rpc-gate/pkg/blockhash" "github.com/pkg/errors" - "github.com/qtumproject/janus/pkg/analytics" - "github.com/qtumproject/janus/pkg/blockhash" ) var FLAG_GENERATE_ADDRESS_TO = "REGTEST_GENERATE_ADDRESS_TO" var FLAG_IGNORE_UNKNOWN_TX = "IGNORE_UNKNOWN_TX" var FLAG_DISABLE_SNIPPING_LOGS = "DISABLE_SNIPPING_LOGS" -var FLAG_HIDE_QTUMD_LOGS = "HIDE_QTUMD_LOGS" +var FLAG_HIDE_KAOND_LOGS = "HIDE_KAOND_LOGS" var FLAG_MATURE_BLOCK_HEIGHT_OVERRIDE = "FLAG_MATURE_BLOCK_HEIGHT_OVERRIDE" -var maximumRequestTime = 10000 +var maximumRequestTime = int((6 * time.Second).Milliseconds()) var maximumBackoff = (2 * time.Second).Milliseconds() type ErrorHandler func(context.Context, error) error @@ -86,18 +86,21 @@ func NewClient(isMain bool, rpcURL string, opts ...func(*Client) error) (*Client } tr := &http.Transport{ - MaxIdleConns: 16, - MaxIdleConnsPerHost: 16, - MaxConnsPerHost: 16, - IdleConnTimeout: 60 * time.Second, - DisableKeepAlives: false, + MaxIdleConns: 16, + MaxIdleConnsPerHost: 16, + MaxConnsPerHost: 16, + IdleConnTimeout: 100 * time.Second, + TLSHandshakeTimeout: 15 * time.Second, + ExpectContinueTimeout: 15 * time.Second, + DisableKeepAlives: false, DialContext: (&net.Dialer{ - Timeout: 60 * time.Second, + Timeout: 120 * time.Second, + KeepAlive: 40 * time.Second, }).DialContext, } httpClient := &http.Client{ - Timeout: 10 * time.Second, + Timeout: 30 * time.Second, Transport: tr, } @@ -163,7 +166,7 @@ func (c *Client) RequestWithContext(ctx context.Context, method string, params i c.GetDebugLogger().Log("method", method, "params", params, "result", result, "error", err) return errors.Wrap(err, "couldn't unmarshal response result field") } - if c.IsDebugEnabled() && !c.GetFlagBool(FLAG_HIDE_QTUMD_LOGS) { + if c.IsDebugEnabled() && !c.GetFlagBool(FLAG_HIDE_KAOND_LOGS) { c.printRPCRequest(method, params) c.printCachedRPCResponse(cachedResult) } @@ -184,6 +187,8 @@ func (c *Client) RequestWithContext(ctx context.Context, method string, params i resp, err = c.Do(ctx, req) if err != nil { errorHandlerErr := c.errorHandler(ctx, err) + + check_timeout := strings.Contains(err.Error(), "context deadline exceeded") retry := false if errorHandlerErr != nil && i != max-1 { // only allow recovering from a specific error once @@ -191,11 +196,13 @@ func (c *Client) RequestWithContext(ctx context.Context, method string, params i handledErrors[err] = true retry = true } + } else if check_timeout && i != max-1 { + retry = true } - if (retry || strings.Contains(err.Error(), ErrQtumWorkQueueDepth.Error())) && i != max-1 { + if (retry || strings.Contains(err.Error(), ErrKaonWorkQueueDepth.Error())) && i != max-1 { requestString := marshalToString(req) backoffTime := computeBackoff(i, true) - c.GetLogger().Log("msg", fmt.Sprintf("QTUM process busy, backing off for %f seconds", backoffTime.Seconds()), "request", requestString) + c.GetLogger().Log("msg", fmt.Sprintf("Kaon process busy, backing off for %f seconds", backoffTime.Seconds()), "request", requestString) // TODO check if this works as expected var done <-chan struct{} if c.ctx != nil { @@ -208,10 +215,10 @@ func (c *Client) RequestWithContext(ctx context.Context, method string, params i case <-done: return errors.WithMessage(ctx.Err(), "context cancelled") } - c.GetLogger().Log("msg", "Retrying QTUM command") + c.GetLogger().Log("msg", "Retrying Kaon command") } else { if i != 0 { - c.GetLogger().Log("msg", fmt.Sprintf("Giving up on QTUM RPC call after %d tries since its busy", i+1)) + c.GetLogger().Log("msg", fmt.Sprintf("Giving up on Kaon RPC call after %d tries since its busy", i+1)) } return err } @@ -244,8 +251,8 @@ func (c *Client) Do(ctx context.Context, req *JSONRPCRequest) (*SuccessJSONRPCRe debugLogger.Log("method", req.Method) - if c.IsDebugEnabled() && !c.GetFlagBool(FLAG_HIDE_QTUMD_LOGS) && c.logWriter != nil { - fmt.Fprintf(c.logWriter, "=> qtum RPC request\n%s\n", reqBody) + if c.IsDebugEnabled() && !c.GetFlagBool(FLAG_HIDE_KAOND_LOGS) && c.logWriter != nil { + fmt.Fprintf(c.logWriter, "=> Kaon RPC request\n%s\n", reqBody) } respBody, err := c.do(ctx, bytes.NewReader(reqBody)) @@ -254,7 +261,7 @@ func (c *Client) Do(ctx context.Context, req *JSONRPCRequest) (*SuccessJSONRPCRe return nil, errors.Wrap(err, "Client#do") } - if c.IsDebugEnabled() && !c.GetFlagBool(FLAG_HIDE_QTUMD_LOGS) { + if c.IsDebugEnabled() && !c.GetFlagBool(FLAG_HIDE_KAOND_LOGS) { formattedBody, err := ReformatJSON(respBody) formattedBodyStr := string(formattedBody) if !c.GetFlagBool(FLAG_DISABLE_SNIPPING_LOGS) { @@ -265,24 +272,25 @@ func (c *Client) Do(ctx context.Context, req *JSONRPCRequest) (*SuccessJSONRPCRe } if err == nil && c.logWriter != nil { - fmt.Fprintf(c.logWriter, "<= qtum RPC response\n%s\n", formattedBodyStr) + fmt.Fprintf(c.logWriter, "<= Kaon RPC response\n%s\n", formattedBodyStr) } } res, err := c.responseBodyToResult(respBody) if err != nil { defer c.failure() - if len(respBody) == 0 { + if respBody == nil || len(respBody) == 0 { debugLogger.Log("Empty response") return nil, errors.Wrap(err, "empty response") } if IsKnownError(err) { return nil, err } - if string(respBody) == ErrQtumWorkQueueDepth.Error() { - // QTUM http server queue depth reached, need to retry - return nil, ErrQtumWorkQueueDepth + if string(respBody) == ErrKaonWorkQueueDepth.Error() { + // Kaon http server queue depth reached, need to retry + return nil, ErrKaonWorkQueueDepth } + if strings.Contains(string(respBody), "503 Service Unavailable") { // server was shutdown debugLogger.Log("msg", "Server responded with 503") @@ -353,7 +361,7 @@ func (c *Client) do(ctx context.Context, body io.Reader) ([]byte, error) { reader, err := ioutil.ReadAll(resp.Body) if err != nil { - return nil, errors.Wrap(err, "ioutil error in qtum client package") + return nil, errors.Wrap(err, "ioutil error in kaon client package") } return reader, nil } @@ -438,7 +446,7 @@ func SetLogWriter(logWriter io.Writer) func(*Client) error { func SetLogger(l log.Logger) func(*Client) error { return func(c *Client) error { - c.logger = log.WithPrefix(l, "component", "qtum.Client") + c.logger = log.WithPrefix(l, "component", "kaon.Client") return nil } } @@ -466,16 +474,16 @@ func SetIgnoreUnknownTransactions(ignore bool) func(*Client) error { } } -func SetDisableSnippingQtumRpcOutput(disable bool) func(*Client) error { +func SetDisableSnippingKaonRpcOutput(disable bool) func(*Client) error { return func(c *Client) error { c.SetFlag(FLAG_DISABLE_SNIPPING_LOGS, !disable) return nil } } -func SetHideQtumdLogs(hide bool) func(*Client) error { +func SetHideKaondLogs(hide bool) func(*Client) error { return func(c *Client) error { - c.SetFlag(FLAG_HIDE_QTUMD_LOGS, hide) + c.SetFlag(FLAG_HIDE_KAOND_LOGS, hide) return nil } } @@ -616,13 +624,13 @@ func checkRPCURL(u string) error { return errors.New("RPC URL must be set") } - qtumRPC, err := url.Parse(u) + kaonRPC, err := url.Parse(u) if err != nil { - return errors.Errorf("QTUM_RPC URL: %s", u) + return errors.Errorf("KAON_RPC URL: %s", u) } - if qtumRPC.User == nil { - return errors.Errorf("QTUM_RPC URL (must specify user & password): %s", u) + if kaonRPC.User == nil { + return errors.Errorf("KAON_RPC URL (must specify user & password): %s", u) } return nil @@ -639,21 +647,21 @@ func (c *Client) printCachedRPCResponse(cachedResponse []byte) { } if err == nil && c.logWriter != nil { - fmt.Fprintf(c.logWriter, "<= qtum (CACHED) RPC response\n%s\n", formattedBodyStr) + fmt.Fprintf(c.logWriter, "<= Kaon (CACHED) RPC response\n%s\n", formattedBodyStr) } } func (c *Client) printRPCRequest(method string, params interface{}) { req, err := c.NewRPCRequest(method, params) if err != nil { - fmt.Fprintf(c.logWriter, "=> qtum RPC request\n%s\n", err.Error()) + fmt.Fprintf(c.logWriter, "=> Kaon RPC request\n%s\n", err.Error()) } reqBody, err := json.MarshalIndent(req, "", " ") if err != nil { - fmt.Fprintf(c.logWriter, "=> qtum RPC request\n%s\n", err.Error()) + fmt.Fprintf(c.logWriter, "=> Kaon RPC request\n%s\n", err.Error()) } debugLogger := c.GetDebugLogger() debugLogger.Log("method", req.Method) - fmt.Fprintf(c.logWriter, "=> qtum RPC request\n%s\n", reqBody) + fmt.Fprintf(c.logWriter, "=> Kaon RPC request\n%s\n", reqBody) } diff --git a/pkg/qtum/client_cache.go b/pkg/kaon/client_cache.go similarity index 77% rename from pkg/qtum/client_cache.go rename to pkg/kaon/client_cache.go index 7ab07f0b..59567ed6 100644 --- a/pkg/qtum/client_cache.go +++ b/pkg/kaon/client_cache.go @@ -1,4 +1,4 @@ -package qtum +package kaon import ( "context" @@ -13,30 +13,34 @@ import ( ) // sets the timeout for flushing out the cashed memory -const CACHABLE_METHOD_CACHE_TIMEOUT = time.Second * 15 +const CACHABLE_METHOD_CACHE_TIMEOUT = time.Second * 30 const ( - QtumMethodGetblock = "getblock" - QtumMethodGetblockhash = "getblockhash" - QtumMethodGetblockheader = "getblockheader" - QtumMethodGetblockchaininfo = "getblockchaininfo" - QtumMethodGethexaddress = "gethexaddress" - QtumMethodGetrawtransaction = "getrawtransaction" - QtumMethodGettransaction = "gettransaction" - QtumMethodGettxout = "gettxout" - QtumMethodDecoderawtransaction = "decoderawtransaction" + KaonMethodGetblock = "getblock" + KaonMethodGetblockhash = "getblockhash" + KaonMethodGetblockheader = "getblockheader" + KaonMethodGetblockchaininfo = "getblockchaininfo" + KaonMethodGethexaddress = "gethexaddress" + KaonMethodGetrawtransaction = "getrawtransaction" + KaonMethodGettransaction = "gettransaction" + KaonMethodGettxout = "gettxout" + KaonMethodDecoderawtransaction = "decoderawtransaction" + KaonMethodGetTransactionHashByEthHash = "gettxidbyethhash" + UltMethodFromHexAddress = "fromhexaddress" ) var cachable_methods = []string{ - QtumMethodGetblock, - // QtumMethodGetblockhash, - // QtumMethodGetblockheader, - // QtumMethodGetblockchaininfo, - QtumMethodGethexaddress, - QtumMethodGetrawtransaction, - // QtumMethodGettransaction, - QtumMethodGettxout, - QtumMethodDecoderawtransaction, + KaonMethodGetblock, + KaonMethodGetblockhash, + KaonMethodGetblockheader, + KaonMethodGetblockchaininfo, + KaonMethodGethexaddress, + KaonMethodGetrawtransaction, + KaonMethodGettransaction, + KaonMethodGettxout, + KaonMethodDecoderawtransaction, + KaonMethodGetTransactionHashByEthHash, + UltMethodFromHexAddress, } // stores the rpc response for 'method' and 'params' in the cache diff --git a/pkg/qtum/client_cache_integration_test.go b/pkg/kaon/client_cache_integration_test.go similarity index 94% rename from pkg/qtum/client_cache_integration_test.go rename to pkg/kaon/client_cache_integration_test.go index c8f94344..9ea582fb 100644 --- a/pkg/qtum/client_cache_integration_test.go +++ b/pkg/kaon/client_cache_integration_test.go @@ -1,4 +1,4 @@ -package qtum +package kaon import ( "bytes" @@ -20,9 +20,9 @@ var logWriter io.Writer = &logBuffer var logger = log.NewLogfmtLogger(logWriter) func TestCacheWithClient(t *testing.T) { - qtumMockServer := NewQtumMockServer(mockJsonRPCResponse) - URL := "http://qtumuser:qtumpass@127.0.0.1:6969" - defer qtumMockServer.Close() + kaonMockServer := NewKaonMockServer(mockJsonRPCResponse) + URL := "http://kaonuser:kaonpass@127.0.0.1:6969" + defer kaonMockServer.Close() client, err := NewClient( true, URL, @@ -31,13 +31,13 @@ func TestCacheWithClient(t *testing.T) { SetLogger(logger), SetContext(context.Background()), ) - client.URL = qtumMockServer.URL + client.URL = kaonMockServer.URL if err != nil { t.Fatal(err) } var result interface{} - t.Run("Qtum RPC getblock call processed succesfully", func(t *testing.T) { + t.Run("Kaon RPC getblock call processed succesfully", func(t *testing.T) { err = client.Request(test_method, test_params, &result) if err != nil { t.Fatal(err) @@ -63,8 +63,8 @@ func TestCacheWithClient(t *testing.T) { assertResponseBody(t, result, test_expectedResult) outputLog := logBuffer.String() - if !strings.Contains(outputLog, "qtum (CACHED) RPC response") { - t.Errorf("\nexpected: %s\n\n, got: %s", "qtum (CACHED) RPC response", outputLog) + if !strings.Contains(outputLog, "kaon (CACHED) RPC response") { + t.Errorf("\nexpected: %s\n\n, got: %s", "kaon (CACHED) RPC response", outputLog) } }) @@ -126,7 +126,7 @@ func TestCacheWithClient(t *testing.T) { SetLogger(logger), SetContext(ctx), ) - client.URL = qtumMockServer.URL + client.URL = kaonMockServer.URL if err != nil { t.Fatal(err) } @@ -174,7 +174,7 @@ func TestCacheWithClient(t *testing.T) { SetLogger(logger), SetContext(ctx), ) - client.URL = qtumMockServer.URL + client.URL = kaonMockServer.URL if err != nil { t.Fatal(err) } @@ -213,7 +213,7 @@ func TestCacheWithClient(t *testing.T) { } -func NewQtumMockServer(body []byte) *httptest.Server { +func NewKaonMockServer(body []byte) *httptest.Server { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Write(body) diff --git a/pkg/qtum/client_cache_test.go b/pkg/kaon/client_cache_test.go similarity index 99% rename from pkg/qtum/client_cache_test.go rename to pkg/kaon/client_cache_test.go index 7acbc036..da4ac41e 100644 --- a/pkg/qtum/client_cache_test.go +++ b/pkg/kaon/client_cache_test.go @@ -1,4 +1,4 @@ -package qtum +package kaon import ( "testing" diff --git a/pkg/qtum/client_test.go b/pkg/kaon/client_test.go similarity index 99% rename from pkg/qtum/client_test.go rename to pkg/kaon/client_test.go index 2dabfe73..41ce6ca6 100644 --- a/pkg/qtum/client_test.go +++ b/pkg/kaon/client_test.go @@ -1,4 +1,4 @@ -package qtum +package kaon import ( "testing" diff --git a/pkg/kaon/error_handlers.go b/pkg/kaon/error_handlers.go new file mode 100644 index 00000000..2f940d1c --- /dev/null +++ b/pkg/kaon/error_handlers.go @@ -0,0 +1,76 @@ +package kaon + +import ( + "context" + "errors" + "sync" + "time" +) + +var errorHandlers map[error]errorHandler +var ErrErrorHandlerFailed = errors.New("failed to recover from error") + +type errorHandler func(ctx context.Context, state *errorState, method *Method) error + +func newErrorState() *errorState { + return &errorState{ + state: make(map[string]interface{}), + } +} + +type errorState struct { + mutex sync.RWMutex + state map[string]interface{} +} + +func (e *errorState) Get(variable string) interface{} { + e.mutex.RLock() + defer e.mutex.RUnlock() + + return e.state[variable] +} + +func (e *errorState) Put(variable string, value interface{}) { + e.mutex.Lock() + defer e.mutex.Unlock() + + e.state[variable] = value +} + +func errWalletNotFoundHandler(ctx context.Context, state *errorState, method *Method) error { + if state.Get("createwallet") != nil { + return ErrErrorHandlerFailed + } + + req := CreateWalletRequest([]string{"wallet"}) + _, err := method.CreateWallet(ctx, &req) + + if err == nil { + state.Put("createwallet", true) + go func() { + select { + case <-time.After(1 * time.Minute): + // expire after a little bit - in case the Kaon node changes + state.Put("createwallet", false) + case <-ctx.Done(): + return + } + }() + } + + if err == ErrWalletError { + req := LoadWalletRequest([]string{"wallet"}) + _, err = method.LoadWallet(ctx, &req) + + if err == nil { + state.Put("createwallet", true) + } + } + + return err +} + +func init() { + errorHandlers = make(map[error]errorHandler) + errorHandlers[ErrWalletNotFound] = errWalletNotFoundHandler +} diff --git a/pkg/qtum/jsonrpc.go b/pkg/kaon/jsonrpc.go similarity index 74% rename from pkg/qtum/jsonrpc.go rename to pkg/kaon/jsonrpc.go index eae6afa0..cdf0ea9b 100644 --- a/pkg/qtum/jsonrpc.go +++ b/pkg/kaon/jsonrpc.go @@ -1,11 +1,11 @@ -package qtum +package kaon import ( "encoding/json" "errors" "fmt" - "github.com/qtumproject/janus/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/eth" ) const ( @@ -13,42 +13,41 @@ const ( ) const ( - MethodGetHexAddress = "gethexaddress" - MethodFromHexAddress = "fromhexaddress" - MethodSendToContract = "sendtocontract" - MethodGetTransactionReceipt = "gettransactionreceipt" - MethodGetTransaction = "gettransaction" - MethodGetPeerInfo = "getpeerinfo" - MethodGetNetworkInfo = "getnetworkinfo" - MethodGetRawTransaction = "getrawtransaction" - MethodCreateContract = "createcontract" - MethodSendToAddress = "sendtoaddress" - MethodCallContract = "callcontract" - MethodDecodeRawTransaction = "decoderawtransaction" - MethodGetTransactionOut = "gettxout" - MethodGetBlockCount = "getblockcount" - MethodGetBlockChainInfo = "getblockchaininfo" - MethodSearchLogs = "searchlogs" - MethodWaitForLogs = "waitforlogs" - MethodGetBlockHash = "getblockhash" - MethodGetBlockHeader = "getblockheader" - MethodGetBlock = "getblock" - MethodGetAddressesByAccount = "getaddressesbyaccount" - MethodGetAccountInfo = "getaccountinfo" - MethodGenerateToAddress = "generatetoaddress" - MethodListUnspent = "listunspent" - MethodGetStorage = "getstorage" - MethodCreateRawTx = "createrawtransaction" - MethodSignRawTx = "signrawtransactionwithwallet" - MethodSendRawTx = "sendrawtransaction" - MethodGetStakingInfo = "getstakinginfo" - MethodGetAddressBalance = "getaddressbalance" - MethodGetAddressUTXOs = "getaddressutxos" - MethodCreateWallet = "createwallet" - MethodLoadWallet = "loadwallet" - MethodUnloadWallet = "unloadwallet" - MethodListWallets = "listwallets" - MethodListWalletDir = "listwalletdir" + MethodGetHexAddress = "gethexaddress" + MethodFromHexAddress = "fromhexaddress" + MethodSendToContract = "sendtocontract" + MethodGetTransactionReceipt = "gettransactionreceipt" + MethodGetTransaction = "gettransaction" + MethodGetTransactionHashByEthHash = "gettxidbyethhash" + MethodGetPeerInfo = "getpeerinfo" + MethodGetNetworkInfo = "getnetworkinfo" + MethodGetRawTransaction = "getrawtransaction" + MethodCreateContract = "createcontract" + MethodSendToAddress = "sendtoaddress" + MethodCallContract = "callcontract" + MethodGasPrice = "gasprice" + MethodDecodeRawTransaction = "decoderawtransaction" + MethodGetTransactionOut = "gettxout" + MethodGetBlockCount = "getblockcount" + MethodGetBlockChainInfo = "getblockchaininfo" + MethodSearchLogs = "searchlogs" + MethodWaitForLogs = "waitforlogs" + MethodGetBlockHash = "getblockhash" + MethodGetBlockHeader = "getblockheader" + MethodGetBlock = "getblock" + MethodGetAddressesByAccount = "getaddressesbyaccount" + MethodGetAccountInfo = "getaccountinfo" + MethodGenerateToAddress = "generatetoaddress" + MethodListUnspent = "listunspent" + MethodGetStorage = "getstorage" + MethodCreateRawTx = "createrawtransaction" + MethodSignRawTx = "signrawtransactionwithwallet" + MethodSendRawTx = "sendrawtransaction" + MethodGetStakingInfo = "getstakinginfo" + MethodGetAddressBalance = "getaddressbalance" + MethodGetAddressUTXOs = "getaddressutxos" + MethodCreateWallet = "createwallet" + MethodLoadWallet = "loadwallet" ) type JSONRPCRequest struct { @@ -77,7 +76,7 @@ type JSONRPCError struct { } func (err *JSONRPCError) Error() string { - return fmt.Sprintf("qtum [code: %d] %s", err.Code, err.Message) + return fmt.Sprintf("Kaon [code: %d] %s", err.Code, err.Message) } // Tries to associate returned error with one of already known (implemented) errors, @@ -104,7 +103,7 @@ func GetErrorCode(err error) int { return errorCode } -func GetErrorResponse(err error) eth.JSONRPCError { +func GetErrorResponse(err error) *eth.JSONRPCError { errorCode := GetErrorCode(err) if errorCode == 0 { return nil @@ -116,7 +115,7 @@ func GetErrorResponse(err error) eth.JSONRPCError { var ( errorCodeMap = map[int]error{} errorToCodeMap = map[error]int{} - // taken from https://github.com/qtumproject/qtum/blob/master/src/rpc/protocol.h + // taken from https://github.com/kaonaonkaonb/master/src/rpc/protocol.h // Standard JSON-RPC 2.0 errors ErrInvalidRequest = errors.New("invalid request") // -32600 // RPC_METHOD_NOT_FOUND is internally mapped to HTTP_NOT_FOUND (404). @@ -173,9 +172,9 @@ var ( ErrForbiddenBySafeMode = errors.New("server is in safe mode, and command is not allowed in safe mode") // -2 // Http server work queue is full, returned as a raw string, not inside a JSON response - ErrQtumWorkQueueDepth = errors.New("Work queue depth exceeded") - // Sometimes truffle is too quick for qtumd and truffle gives up after one error - // couldn't proxy eth_blockNumber request: Client#do: Post \"***qtum:3889\": dial tcp: lookup qtum: Try again + ErrKaonWorkQueueDepth = errors.New("Work queue depth exceeded") + // Sometimes truffle is too quick for kaond and truffle gives up after one error + // couldn't proxy eth_blockNumber request: Client#do: Post \"***kaon:51474\": dial tcp: lookup kaon: Try again ErrTryAgain = errors.New("Try again") // TODO: add // - insufficient balance diff --git a/pkg/qtum/qtum.go b/pkg/kaon/kaon.go similarity index 81% rename from pkg/qtum/qtum.go rename to pkg/kaon/kaon.go index 515ed58d..d8a10e51 100644 --- a/pkg/qtum/qtum.go +++ b/pkg/kaon/kaon.go @@ -1,4 +1,4 @@ -package qtum +package kaon import ( "context" @@ -10,11 +10,11 @@ import ( "sync" "time" + "github.com/kaonone/eth-rpc-gate/pkg/utils" "github.com/pkg/errors" - "github.com/qtumproject/janus/pkg/utils" ) -type Qtum struct { +type Kaon struct { *Client *Method chainMutex sync.RWMutex @@ -35,12 +35,12 @@ const ( var AllChains = []string{ChainMain, ChainRegTest, ChainTest, ChainAuto, ChainUnknown} -func New(c *Client, chain string) (*Qtum, error) { +func New(c *Client, chain string) (*Kaon, error) { if !utils.InStrSlice(AllChains, chain) { - return nil, errors.Errorf("Invalid qtum chain: '%s'", chain) + return nil, errors.Errorf("Invalid Kaon chain: '%s'", chain) } - qtum := &Qtum{ + kaon := &Kaon{ Client: c, Method: &Method{Client: c}, chain: chain, @@ -49,17 +49,17 @@ func New(c *Client, chain string) (*Qtum, error) { c.SetErrorHandler(func(ctx context.Context, err error) error { if errorHandler, ok := errorHandlers[err]; ok { - return errorHandler(ctx, qtum, qtum.errorState, qtum.Method) + return errorHandler(ctx, kaon.errorState, kaon.Method) } return nil }) - qtum.detectChain() + kaon.detectChain() - return qtum, nil + return kaon, nil } -func (c *Qtum) detectChain() { +func (c *Kaon) detectChain() { c.chainMutex.Lock() if c.queryingChain || // already querying (c.chain != ChainAuto && c.chain != "") { // specified in command line arguments @@ -73,7 +73,7 @@ func (c *Qtum) detectChain() { go c.detectingChain() } -func (c *Qtum) detectingChain() { +func (c *Kaon) detectingChain() { // detect chain we are pointing at for i := 0; ; i++ { blockchainInfo, err := c.GetBlockChainInfo(c.ctx) @@ -111,7 +111,7 @@ func (c *Qtum) detectingChain() { } } -func (c *Qtum) Chain() string { +func (c *Kaon) Chain() string { c.chainMutex.RLock() queryingChain := c.queryingChain queryingComplete := c.queryingComplete @@ -134,37 +134,37 @@ func (c *Qtum) Chain() string { return c.chain } -func (c *Qtum) ChainId() int { +func (c *Kaon) ChainId() int { var chainId int switch strings.ToLower(c.Chain()) { case "main": - chainId = 81 - case "test": - chainId = 8889 + chainId = 11987 case "regtest": - chainId = 8890 + chainId = 11988 + case "test": + chainId = 11989 default: - chainId = 8890 + chainId = 11989 c.GetDebugLogger().Log("msg", fmt.Sprintf("Unknown chain %d", chainId)) } return chainId } -func (c *Qtum) GetMatureBlockHeight() int { +func (c *Kaon) GetMatureBlockHeight() int { blockHeightOverride := c.GetFlagInt(FLAG_MATURE_BLOCK_HEIGHT_OVERRIDE) if blockHeightOverride != nil { return *blockHeightOverride } - return 2000 + return 10 } -func (c *Qtum) CanGenerate() bool { +func (c *Kaon) CanGenerate() bool { return c.Chain() == ChainRegTest } -func (c *Qtum) GenerateIfPossible() { +func (c *Kaon) GenerateIfPossible() { if !c.CanGenerate() { return } @@ -179,9 +179,9 @@ func (c *Qtum) GenerateIfPossible() { type HexAddressPrefix string const ( - PrefixMainChainAddress HexAddressPrefix = "3a" - PrefixTestChainAddress HexAddressPrefix = "78" - PrefixRegTestChainAddress HexAddressPrefix = PrefixTestChainAddress + PrefixMainChainAddress HexAddressPrefix = "UniM" // 0x55 0x6e 0x69 0x4d + PrefixTestChainAddress HexAddressPrefix = "UniT" // 0x55 0x6e 0x69 0x54 + PrefixRegTestChainAddress HexAddressPrefix = "UniP" // 0x55 0x6e 0x69 0x70 ) // Returns decoded hexed string prefix, as ready to use slice of bytes diff --git a/pkg/qtum/method.go b/pkg/kaon/method.go similarity index 87% rename from pkg/qtum/method.go rename to pkg/kaon/method.go index ad2c84e1..109c987d 100644 --- a/pkg/qtum/method.go +++ b/pkg/kaon/method.go @@ -1,11 +1,13 @@ -package qtum +package kaon import ( "context" "encoding/json" "math/big" - "github.com/qtumproject/janus/pkg/utils" + "github.com/pkg/errors" + + "github.com/kaonone/eth-rpc-gate/pkg/utils" ) type Method struct { @@ -65,6 +67,26 @@ func (m *Method) SignMessage(addr string, msg string) (string, error) { return signature, nil } +func (m *Method) GetTransactionHashByEthHash(ctx context.Context, txID string) (*GetTransactionHashByEthHashResponse, error) { + var ( + req = GetTransactionHashByEthHashRequest{ + TxID: txID, + } + resp = new(GetTransactionHashByEthHashResponse) + ) + err := m.RequestWithContext(ctx, MethodGetTransactionHashByEthHash, &req, resp) + if err != nil { + if m.IsDebugEnabled() { + m.GetDebugLogger().Log("function", "MethodGetTransactionHashByEthHash", "Transaction ID", txID, "error", err) + } + return nil, err + } + if m.IsDebugEnabled() { + m.GetDebugLogger().Log("function", "MethodGetTransactionHashByEthHash", "Transaction ID", txID, "result", marshalToString(resp)) + } + return resp, nil +} + func (m *Method) GetTransaction(ctx context.Context, txID string) (*GetTransactionResponse, error) { var ( req = GetTransactionRequest{ @@ -139,9 +161,9 @@ func (m *Method) DecodeRawTransaction(ctx context.Context, hex string) (*Decoded func (m *Method) GetTransactionOut(ctx context.Context, hash string, voutNumber int, mempoolIncluded bool) (*GetTransactionOutResponse, error) { var ( req = GetTransactionOutRequest{ - Hash: hash, - VoutNumber: voutNumber, - MempoolIncluded: mempoolIncluded, + hash, + voutNumber, + mempoolIncluded, } resp = new(GetTransactionOutResponse) ) @@ -186,15 +208,24 @@ func (m *Method) GetMining(ctx context.Context) (resp *GetMiningResponse, err er return } -// hard coded for now as there is only the minimum gas price -func (m *Method) GetGasPrice(ctx context.Context) (*big.Int, error) { - // 40 satoshi - minimumGas := big.NewInt(0x28) - m.GetDebugLogger().Log("Message", "GetGasPrice is hardcoded to "+minimumGas.String()) - return minimumGas, nil +func (m *Method) GetGasPrice(ctx context.Context) (result *big.Int, err error) { + var resp GetBlockCountResponse + err = m.RequestWithContext(ctx, MethodGasPrice, nil, &resp) + if err != nil && m.IsDebugEnabled() { + m.GetDebugLogger().Log("function", "GetGasPrice", "error", err) + // rollback to default + // 1 CENT (gwei) + result = big.NewInt(1e9) + } else { + result = resp.Int + m.GetDebugLogger().Log("function", "GetGasPrice", "msg", "got gas price", "gasPrice", result) + } + + m.GetDebugLogger().Log("Message", "GetGasPrice is "+result.String()) + return result, nil } -// hard coded 0x1 due to the unique nature of Qtums UTXO system, might +// hard coded 0x1 due to the unique nature of Kaons UTXO system, might func (m *Method) GetTransactionCount(ctx context.Context, address string, status string) (*big.Int, error) { // eventually might work this out to see if there's any transactions pending for an address in the mempool // for now just always return 1 @@ -218,6 +249,7 @@ func (m *Method) GetBlockChainInfo(ctx context.Context) (resp GetBlockChainInfoR if err != nil && m.IsDebugEnabled() { m.GetDebugLogger().Log("function", "GetBlockChainInfo", "error", err) } + return resp, err } @@ -232,10 +264,14 @@ func (m *Method) GetBlockHeader(ctx context.Context, hash string) (resp *GetBloc return } -func (m *Method) GetBlock(ctx context.Context, hash string) (resp *GetBlockResponse, err error) { +func (m *Method) GetBlock(ctx context.Context, hash string, fullTransaction bool) (resp *GetBlockResponse, err error) { req := GetBlockRequest{ - Hash: hash, + Hash: hash, + Verbosity: true, } + // if fullTransaction { // false not supported now + // req.Verbosity = true + // } err = m.RequestWithContext(ctx, MethodGetBlock, &req, &resp) if err != nil && m.IsDebugEnabled() { m.GetDebugLogger().Log("function", "GetBlock", "Hash", hash, "error", err) @@ -248,8 +284,7 @@ func (m *Method) Generate(ctx context.Context, blockNum int, maxTries *int) (res var qAddress string if len(m.Accounts) == 0 && generateToAccount == nil { - // return nil, errors.New("you must specify QTUM accounts") - qAddress = "qW28njWueNpBXYWj2KDmtFG2gbLeALeHfV" + return nil, errors.New("you must specify Kaon accounts") } else { if generateToAccount == nil { acc := Account{m.Accounts[0]} @@ -289,7 +324,7 @@ func (m *Method) Generate(ctx context.Context, blockNum int, maxTries *int) (res } /** - * Note that QTUM searchlogs api returns all logs in a transaction receipt if any log matches a topic + * Note that Kaon searchlogs api returns all logs in a transaction receipt if any log matches a topic * While Ethereum behaves differently and will only return logs where topics match */ func (m *Method) SearchLogs(ctx context.Context, req *SearchLogsRequest) (receipts SearchLogsResponse, err error) { @@ -384,7 +419,7 @@ func (m *Method) GetAddressBalance(ctx context.Context, req *GetAddressBalanceRe return } -func (m *Method) SendRawTransaction(ctx context.Context, req *SendRawTransactionRequest) (resp *SendRawTransactionResponse, err error) { +func (m *Method) SendRawTransaction(ctx context.Context, req *SendRawTransactionRequest) (resp *GeneralSendRawTransactionResponse, err error) { if err := m.RequestWithContext(ctx, MethodSendRawTx, req, &resp); err != nil { if m.IsDebugEnabled() { m.GetDebugLogger().Log("function", "SendRawTransaction", "error", err) @@ -461,42 +496,3 @@ func (m *Method) LoadWallet(ctx context.Context, req *LoadWalletRequest) (resp * } return } - -func (m *Method) UnloadWallet(ctx context.Context, req *UnloadWalletRequest) (resp *UnloadWalletResponse, err error) { - if err := m.RequestWithContext(ctx, MethodUnloadWallet, *req, &resp); err != nil { - if m.IsDebugEnabled() { - m.GetDebugLogger().Log("function", "UnloadWallet", "error", err) - } - return nil, err - } - if m.IsDebugEnabled() { - m.GetDebugLogger().Log("function", "UnloadWallet", "msg", "Successfully unloaded wallet") - } - return -} - -func (m *Method) ListWallets(ctx context.Context, req *ListWalletsRequest) (resp *ListWalletsResponse, err error) { - if err := m.RequestWithContext(ctx, MethodListWallets, *req, &resp); err != nil { - if m.IsDebugEnabled() { - m.GetDebugLogger().Log("function", "ListWallets", "error", err) - } - return nil, err - } - if m.IsDebugEnabled() { - m.GetDebugLogger().Log("function", "ListWallets", "msg", "Successfully listed wallets") - } - return -} - -func (m *Method) ListWalletDir(ctx context.Context, req *ListWalletDirRequest) (resp *ListWalletDirResponse, err error) { - if err := m.RequestWithContext(ctx, MethodListWalletDir, *req, &resp); err != nil { - if m.IsDebugEnabled() { - m.GetDebugLogger().Log("function", "ListWalletDir", "error", err) - } - return nil, err - } - if m.IsDebugEnabled() { - m.GetDebugLogger().Log("function", "ListWalletDir", "msg", "Successfully listed wallet directory") - } - return -} diff --git a/pkg/qtum/rpc_types.go b/pkg/kaon/rpc_types.go similarity index 65% rename from pkg/qtum/rpc_types.go rename to pkg/kaon/rpc_types.go index 9f798767..40842085 100644 --- a/pkg/qtum/rpc_types.go +++ b/pkg/kaon/rpc_types.go @@ -1,4 +1,4 @@ -package qtum +package kaon import ( "encoding/json" @@ -6,11 +6,76 @@ import ( "strconv" "strings" + "github.com/kaonone/eth-rpc-gate/pkg/utils" "github.com/pkg/errors" - "github.com/qtumproject/janus/pkg/utils" "github.com/shopspring/decimal" ) +// Amount is a custom type to handle big integers with automatic scaling. +type Amount struct { + decimal.Decimal +} + +var ZeroAmount = NewAmount(0, 1) + +// UnmarshalJSON is a custom unmarshaler that scales the number by 10^18. +func (a *Amount) UnmarshalJSON(data []byte) error { + // Temporary variable for unmarshaling + var d decimal.Decimal + if err := json.Unmarshal(data, &d); err != nil { + return err + } + + // Scale by 10^18 + scaleFactor := decimal.NewFromInt(1e18) + scaled := d.Mul(scaleFactor) + + // Assign the scaled value to Amount + a.Decimal = scaled + + return nil +} + +func NewAmount(value int64, exp int32) Amount { + d := decimal.New(value, exp) + return Amount{Decimal: d} +} + +func TransformAmount(d decimal.Decimal) Amount { + return Amount{Decimal: d} +} + +// NewFromFloat creates a new Amount from a float64. +func NewFromFloat(value float64) Amount { + d := decimal.NewFromFloat(value) + // Apply scaling if needed, e.g., multiply by 10^18 + scaleFactor := decimal.NewFromInt(1e18) + scaled := d.Mul(scaleFactor) + return Amount{Decimal: scaled} +} + +// NewFromString creates a new Amount from a string. +func NewFromString(value string) (Amount, error) { + d, err := decimal.NewFromString(value) + if err != nil { + return Amount{}, err + } + // Apply scaling if needed, e.g., multiply by 10^18 + scaleFactor := decimal.NewFromInt(1e18) + scaled := d.Mul(scaleFactor) + return Amount{Decimal: scaled}, nil +} + +// NewFromString creates a new Amount from a string. +func NewFromInt(value int64) Amount { + d := decimal.NewFromInt(value) + + // Apply scaling if needed, e.g., multiply by 10^18 + scaleFactor := decimal.NewFromInt(1e18) + scaled := d.Mul(scaleFactor) + return Amount{Decimal: scaled} +} + // TODO: Wipe these out when it comes time to change over from floats to integers, and change SendToContractRequest to not use strings where numerics will do // Todo: Go and fix the need for a custom json unmarshall in the non raw versions of these types @@ -35,12 +100,12 @@ const ( ) type SendToContractRawRequest struct { - ContractAddress string `json:"contractAddress"` - Datahex string `json:"data"` - Amount decimal.Decimal `json:"amount"` - GasLimit *big.Int `json:"gasLimit"` - GasPrice string `json:"gasPrice"` - SenderAddress string `json:"senderaddress"` + ContractAddress string `json:"contractAddress"` + Datahex string `json:"data"` + Amount Amount `json:"amount"` + GasLimit *big.Int `json:"gasLimit"` + GasPrice string `json:"gasPrice"` + SenderAddress string `json:"senderaddress"` } type CreateContractRawRequest struct { @@ -74,82 +139,94 @@ type ( "difficulty": 4.656542373906925e-10, "mediantime": 1533096368, "verificationprogress": 1, + "initialblockdownload": false, "chainwork": "0000000000000000000000000000000000000000000000000000000000002054", + "size_on_disk": 3103111212, "pruned": false, - "softforks": [ - { - "id": "bip34", - "version": 2, - "reject": { - "status": true - } - }, - { - "id": "bip66", - "version": 3, - "reject": { - "status": true - } - }, - { - "id": "bip65", - "version": 4, - "reject": { - "status": true - } - } - ], - "bip9_softforks": { - "csv": { - "status": "active", - "startTime": 0, - "timeout": 999999999999, - "since": 432 - }, - "segwit": { - "status": "active", - "startTime": 0, - "timeout": 999999999999, - "since": 432 - } - } + "pruneheight": 0, + "automatic_pruning": false, + "prune_target_size": 0, + "softforks": { + "csv": { + "type": "buried|bip9|other" + "bip9": { + "status": "defined|started|lockedIn|active|failed", + "bit": 1, + "start_time": 0, + "timeout": 999999999999, + "since": 432 + "statistics": { + "period": 2, + "threshold": 0, + "elapsed": 1, + "count": 10223, + "possible": true + } + }, + "height": 10, + "active": false + }, + "segwit": { + "type": "buried|bip9|other" + "bip9": { + "status": "defined|started|lockedIn|active|failed", + "bit": 1, + "start_time": 0, + "timeout": 999999999999, + "since": 432 + "statistics": { + "period": 2, + "threshold": 0, + "elapsed": 1, + "count": 10223, + "possible": true + } + }, + "height": 10, + "active": false + }. + "XXXX": {...} + }, + "warnings" : "str" } */ GetBlockChainInfoResponse struct { - Bestblockhash string `json:"bestblockhash"` - Bip9Softforks struct { - Csv struct { - Since int64 `json:"since"` - StartTime int64 `json:"startTime"` - Status string `json:"status"` - Timeout int64 `json:"timeout"` - } `json:"csv"` + Chain string `json:"chain"` + Blocks int64 `json:"blocks"` + Headers int64 `json:"headers"` + Bestblockhash string `json:"bestblockhash"` + Difficulty float64 `json:"difficulty"` + Mediantime int64 `json:"mediantime"` + Verificationprogress float64 `json:"verificationprogress"` + Initialblockdownload bool `json:"initialblockdownload"` + Chainwork string `json:"chainwork"` + SizeOnDisk int64 `json:"size_on_disk"` + Pruned bool `json:"pruned"` + PruneHeight int64 `json:"pruneheight"` + AutomaticPruning bool `json:"automatic_pruning"` + PruneTargetSize int64 `json:"prune_target_size"` + Softforks map[string]struct { Segwit struct { - Since int64 `json:"since"` - StartTime int64 `json:"startTime"` - Status string `json:"status"` - Timeout int64 `json:"timeout"` + Type string `json:"type"` + Bip9 struct { + Status string `json:"status"` + Bit int64 `json:"bit"` + StartTime int64 `json:"start_time"` + Timout int64 `json:"timeout"` + Since int64 `json:"since"` + Statistics struct { + Period int64 `json:"period"` + Threshold int64 `json:"threshold"` + Elapsed int64 `json:"elapsed"` + Count int64 `json:"count"` + Possible bool `json:"possible"` + } `json:"statistics"` + } `json:"bip9"` + Height int64 `json:"height"` + Active bool `json:"active"` } `json:"segwit"` - } `json:"bip9_softforks"` - Blocks int64 `json:"blocks"` - Chain string `json:"chain"` - Chainwork string `json:"chainwork"` - Difficulty float64 `json:"difficulty"` - Headers int64 `json:"headers"` - Mediantime int64 `json:"mediantime"` - Pruned bool `json:"pruned"` - Softforks map[string]struct { - Type string `json:"type"` - Active bool `json:"active"` - Height int64 `json:"height"` - Bip9 struct { - Status string `json:"status"` - StartTime int64 `json:"start_time"` - Timout int64 `json:"timeout"` - Since int64 `json:"since"` - } `json:"bip9"` } `json:"softforks"` - Verificationprogress float64 `json:"verificationprogress"` + Warnings string `json:"warnings"` } ) @@ -170,7 +247,7 @@ func (l Log) GetData() string { type ( SendToAddressRequest struct { Address string - Amount decimal.Decimal + Amount Amount SenderAddress string } SendToAddressResponse string @@ -178,15 +255,15 @@ type ( func (r *SendToAddressRequest) MarshalJSON() ([]byte, error) { /* - 1. "address" (string, required) The qtum address to send to. - 2. "amount" (numeric or string, required) The amount in QTUM to send. eg 0.1 + 1. "address" (string, required) The Kaon address to send to. + 2. "amount" (numeric or string, required) The amount in Kaon to send. eg 0.1 3. "comment" (string, optional) A comment used to store what the transaction is for. This is not part of the transaction, just kept in your wallet. 4. "comment_to" (string, optional) A comment to store the name of the person or organization to which you're sending the transaction. This is not part of the transaction, just kept in your wallet. 5. subtractfeefromamount (boolean, optional, default=false) The fee will be deducted from the amount being sent. - The recipient will receive less qtums than you enter in the amount field. + The recipient will receive less KAONs than you enter in the amount field. 6. replaceable (boolean, optional) Allow this transaction to be replaced by a transaction with higher fees via BIP 125 7. conf_target (numeric, optional) Confirmation target (in blocks) 8. "estimate_mode" (string, optional, default=UNSET) The fee estimate mode, must be one of: @@ -195,7 +272,7 @@ func (r *SendToAddressRequest) MarshalJSON() ([]byte, error) { "CONSERVATIVE" 9. "avoid_reuse" (boolean, optional, default=true) Avoid spending from dirty addresses; addresses are considered dirty if they have previously been used in a transaction - 10. "senderaddress" (string, optional) The quantum address that will be used to send money from. + 10. "senderaddress" (string, optional) The Kaon address that will be used to send money from. 11."changeToSender" (bool, optional, default=false) Return the change to the sender. */ return json.Marshal([]interface{}{ @@ -219,7 +296,7 @@ type ( SendToContractRequest struct { ContractAddress string Datahex string - Amount decimal.Decimal + Amount Amount GasLimit *big.Int GasPrice string SenderAddress string @@ -243,10 +320,10 @@ func (r *SendToContractRequest) MarshalJSON() ([]byte, error) { /* 1. "contractaddress" (string, required) The contract address that will receive the funds and data. 2. "datahex" (string, required) data to send. - 3. "amount" (numeric or string, optional) The amount in QTUM to send. eg 0.1, default: 0 + 3. "amount" (numeric or string, optional) The amount in KAON to send. eg 0.1, default: 0 4. gasLimit (numeric or string, optional) gasLimit, default: 250000, max: 40000000 - 5. gasPrice (numeric or string, optional) gasPrice Qtum price per gas unit, default: 0.0000004, min:0.0000004 - 6. "senderaddress" (string, optional) The quantum address that will be used as sender. + 5. gasPrice (numeric or string, optional) gasPrice KAON price per gas unit, default: 0.0000004, min:0.0000004 + 6. "senderaddress" (string, optional) The Kaon address that will be used as sender. 7. "broadcast" (bool, optional, default=true) Whether to broadcast the transaction or not. 8. "changeToSender" (bool, optional, default=true) Return the change to the sender. */ @@ -290,8 +367,8 @@ func (r *CreateContractRequest) MarshalJSON() ([]byte, error) { /* 1. "bytecode" (string, required) contract bytcode. 2. gasLimit (numeric or string, optional) gasLimit, default: 2500000, max: 40000000 - 3. gasPrice (numeric or string, optional) gasPrice QTUM price per gas unit, default: 0.0000004, min:0.0000004 - 4. "senderaddress" (string, optional) The quantum address that will be used to create the contract. + 3. gasPrice (numeric or string, optional) gasPrice KAON price per gas unit, default: 0.0000004, min:0.0000004 + 4. "senderaddress" (string, optional) The Kaon address that will be used to create the contract. 5. "broadcast" (bool, optional, default=true) Whether to broadcast the transaction or not. 6. "changeToSender" (bool, optional, default=true) Return the change to the sender. */ @@ -337,19 +414,19 @@ type ( CallContractResponse struct { Address string `json:"address"` ExecutionResult struct { - GasUsed int `json:"gasUsed"` - Excepted string `json:"excepted"` - ExceptedMessage string `json:"exceptedMessage"` - NewAddress string `json:"newAddress"` - Output string `json:"output"` - CodeDeposit int `json:"codeDeposit"` - GasRefunded int `json:"gasRefunded"` - DepositSize int `json:"depositSize"` - GasForDeposit int `json:"gasForDeposit"` + GasUsed big.Int `json:"gasUsed"` + Excepted string `json:"excepted"` + ExceptedMessage string `json:"exceptedMessage"` + NewAddress string `json:"newAddress"` + Output string `json:"output"` + CodeDeposit int `json:"codeDeposit"` + GasRefunded big.Int `json:"gasRefunded"` + DepositSize int `json:"depositSize"` + GasForDeposit big.Int `json:"gasForDeposit"` } `json:"executionResult"` TransactionReceipt struct { StateRoot string `json:"stateRoot"` - GasUsed int `json:"gasUsed"` + GasUsed big.Int `json:"gasUsed"` Bloom string `json:"bloom"` Log []interface{} `json:"log"` } `json:"transactionReceipt"` @@ -468,23 +545,24 @@ type ( Vouts []*DecodedRawTransactionOutV `json:"vout"` } DecodedRawTransactionInV struct { - TxID string `json:"txid"` - Vout int64 `json:"vout"` - ScriptSig DecodedRawTransactionScriptSig `json:"scriptSig"` - Txinwitness []string `json:"txinwitness"` - Sequence int64 `json:"sequence"` + Address string `json:"address"` + TxID string `json:"txid"` + Vout int64 `json:"vout"` + PreviousVoutPubkey DecodedRawTransactionScriptSig `json:"previousPubkey"` + ScriptSig DecodedRawTransactionScriptSig `json:"scriptSig"` + Txinwitness []string `json:"txinwitness"` + Sequence int64 `json:"sequence"` } DecodedRawTransactionOutV struct { - Value decimal.Decimal `json:"value"` - ValueSatoshi decimal.Decimal `json:"valueSat"` + Value Amount `json:"value"` N int64 `json:"n"` ScriptPubKey DecodedRawTransactionScriptPubKey `json:"scriptPubKey"` } // TODO: Make these two generic? Same struct is also present in other RPC data types DecodedRawTransactionScriptSig struct { - Asm string `json:"asm"` + ASM string `json:"asm"` Hex string `json:"hex"` } @@ -497,11 +575,11 @@ type ( } ) -// Calculates transaction total amount of Qtum +// Calculates transaction total amount of KAON func (resp *DecodedRawTransactionResponse) CalcAmount() decimal.Decimal { var amount decimal.Decimal for _, out := range resp.Vouts { - amount = amount.Add(out.Value) + amount = amount.Add(out.Value.Decimal) } return amount } @@ -511,25 +589,18 @@ type ContractInfo struct { To string GasLimit string GasPrice string - GasUsed string UserInput string } // TODO: complete func (resp *DecodedRawTransactionResponse) ExtractContractInfo() (_ ContractInfo, isContractTx bool, _ error) { - // TODO: discuss - // ? Can Vouts have several contracts + // Break if Vouts have several contracts var info *ContractInfo for _, vout := range resp.Vouts { - - scriptAsm, err := DisasmScript(vout.ScriptPubKey.Hex) - if err != nil { - return ContractInfo{}, false, errors.WithMessage(err, "failed to disasm script") - } var ( - script = strings.Split(scriptAsm, " ") + script = strings.Split(vout.ScriptPubKey.ASM, " ") finalOp = script[len(script)-1] ) @@ -571,15 +642,10 @@ func (resp *DecodedRawTransactionResponse) ExtractContractInfo() (_ ContractInfo } } info = &ContractInfo{ - From: createInfo.From, - To: createInfo.To, - GasLimit: createInfo.GasLimit, - - GasPrice: createInfo.GasPrice, - - // TODO: researching - GasUsed: "0x0", - + From: createInfo.From, + To: createInfo.To, + GasLimit: createInfo.GasLimit, + GasPrice: createInfo.GasPrice, UserInput: createInfo.CallData, } @@ -595,102 +661,126 @@ func (resp *DecodedRawTransactionResponse) ExtractContractInfo() (_ ContractInfo return *info, true, nil } - return ContractInfo{}, false, nil + // Let's try a standard trx parsing method + for _, vin := range resp.Vins { + fromAddress := "" + if vin.Address == "" { + var ( + script = strings.Split(vin.PreviousVoutPubkey.ASM, " ") + finalOp = script[len(script)-1] + ) + if finalOp != "OP_CHECKSIG" { + continue // We do not support non-standard money transfers + } + sender, err := ParseP2PKHReciever(script) + if err != nil { + continue + } -} + // P2Sh address(such as MUrenj2sPqEVTiNbHQ2RARiZYyTAAeKiDX) and BECH32 address (such as qc1qkt33x6hkrrlwlr6v59wptwy6zskyrjfe40y0lx) + // will cause ConvertKaonAddress to fall + // but we not support them for now + fromAddressIn, err := utils.ConvertKaonAddress(*sender) -func (resp *DecodedRawTransactionResponse) IsContractCreation() bool { - for _, vout := range resp.Vouts { - if strings.HasSuffix(vout.ScriptPubKey.ASM, "OP_CREATE") { - return true - } - } - return false -} + if err != nil { + continue + } + fromAddress = fromAddressIn + } else { -// Get address from first OP_SENDER script operation found in Vouts, if any. Can also be used to check for presence of said op. -// TODO: Refactor to use btcasm functionality as in func ExtractContractInfo above? Or just deprecate this func entirely, because it's only relevant for already handled contract TXs anyway? -func (resp *DecodedRawTransactionResponse) GetOpSenderAddress() (address string, _ error) { - for _, vout := range resp.Vouts { - // OP_SENDER is only valid in scripts ending in ether OP_CREATE or OP_CALL - if strings.HasSuffix(vout.ScriptPubKey.ASM, "OP_CREATE") || strings.HasSuffix(vout.ScriptPubKey.ASM, "OP_CALL") { - var scriptChunks = strings.Split(vout.ScriptPubKey.ASM, " ") - - // OP_CREATE prefixed by OP_SENDER always have this structure: - // - // 1 // address type of the pubkeyhash (public key hash) - // Address // sender's pubkeyhash address - // {signature, pubkey} //serialized scriptSig - // OP_SENDER - // 4 // EVM version - // 100000 //gas limit - // 10 //gas price - // 1234 // data to be sent by the contract - // OP_CREATE - var isOpCreateWithOpSender = len(scriptChunks) == 9 - - // OP_CALL prefixed by OP_SENDER always have this structure: - // - // 1 // address type of the pubkeyhash (public key hash) - // Address // sender's pubkeyhash address - // {signature, pubkey} // serialized scriptSig - // OP_SENDER - // 4 // EVM version - // 100000 // gas limit - // 10 // gas price - // 1234 // data to be sent by the contract - // Contract Address // contract address - // OP_CALL - var isOpCallWithOpSender = len(scriptChunks) == 10 - - // Note: This check isn't redundant with the initial opcode check, since both opcodes are valid without OP_SENDER prefix - if isOpCreateWithOpSender || isOpCallWithOpSender { - // Address type, only support 1 for now - // TODO: Instead of throeing an error, should it keep going to see if another Vout has OP_SENDER with a valid address? - // TODO: Is type "1" called "push data"? - // TODO: This should be logged according to task - if scriptChunks[0] != "1" { - return "", errors.New("OP_SENDER address if of invalid type (only type 1 is supported currently)") - } + // P2Sh address(such as MUrenj2sPqEVTiNbHQ2RARiZYyTAAeKiDX) and BECH32 address (such as qc1qkt33x6hkrrlwlr6v59wptwy6zskyrjfe40y0lx) + // will cause ConvertKaonAddress to fall + // but we not support them for now + fromAddressIn, err := utils.ConvertKaonAddress(vin.Address) - // TODO: Is it necessary to check that the first three ASM entries are valid, as done in QtumJ? + if err != nil { + continue + } + fromAddress = fromAddressIn + } - // TODO: These following sanity checks are present in the QtumJ code used as reference, but will probably always pass for valid blockchain data. - // If Janus is stable and performance is a concern these can probably be safely removed - if scriptChunks[3] != "OP_SENDER" { - return "", errors.New("Expected opcode OP_SENDER missing or malformatted (This should probably never happen with valid blockchain data)") - } + if int(vin.Vout) >= len(resp.Vouts) { + continue - if isOpCreateWithOpSender && scriptChunks[8] != "OP_CREATE" { - return "", errors.New("Expected opcode OP_CREATE missing or malformatted (This should probably never happen with valid blockchain data)") - } + // TODO: probably we still may be able to solve it in that case + // research + // return ContractInfo{ + // From: fromAddress, + // }, false, nil + } - if isOpCallWithOpSender && scriptChunks[9] != "OP_CALL" { - return "", errors.New("Expected opcode OP_CALL missing or malformatted (This should probably never happen with valid blockchain data)") + var ( + vout = resp.Vouts[vin.Vout] + reciever = "" + ) + for _, address := range vout.ScriptPubKey.Addresses { + if address != "" { + // P2Sh address(such as MUrenj2sPqEVTiNbHQ2RARiZYyTAAeKiDX) and BECH32 address (such as qc1qkt33x6hkrrlwlr6v59wptwy6zskyrjfe40y0lx) + // will cause ConvertKaonAddress to fall + // but we not support them for now + hex, err := utils.ConvertKaonAddress(address) + if err == nil { + reciever = hex + break } + } + } + + if reciever == "" { + var ( + script = strings.Split(vout.ScriptPubKey.ASM, " ") + finalOp = script[len(script)-1] + ) + if finalOp != "OP_CHECKSIG" { + continue // We do not support non-standard money transfers + } + recieverParsed, err := ParseP2PKHReciever(script) + if err != nil { + continue + } - // TODO: This should already be in hex/eth format, but should we also add a hex prefix? - var opSenderAddress = scriptChunks[1] + // P2Sh address(such as MUrenj2sPqEVTiNbHQ2RARiZYyTAAeKiDX) and BECH32 address (such as qc1qkt33x6hkrrlwlr6v59wptwy6zskyrjfe40y0lx) + // will cause ConvertKaonAddress to fall + // but we not support them for now + recieverIn, err := utils.ConvertKaonAddress(*recieverParsed) - return opSenderAddress, nil + if err != nil { + continue } + reciever = recieverIn + } + + return ContractInfo{ + From: fromAddress, + To: reciever, + }, false, nil + } + + return ContractInfo{}, false, nil +} + +func (resp *DecodedRawTransactionResponse) IsContractCreation() bool { + for _, vout := range resp.Vouts { + if strings.HasSuffix(vout.ScriptPubKey.ASM, "OP_CREATE") { + return true } } - return "", errors.New("No script with OP_SENDER found in Vouts") + return false } // ========== GetTransactionOut ============= // type ( - GetTransactionOutRequest struct { - Hash string `json:"txid"` - VoutNumber int `json:"n"` - MempoolIncluded bool `json:"include_mempool"` - } + // GetTransactionOutRequest struct { + // Hash string `json:"txid"` + // VoutNumber int `json:"n"` + // MempoolIncluded bool `json:"include_mempool"` + // } + GetTransactionOutRequest []interface{} // TODO: Make ScriptPubKey into a separate struct (or use generic variant?) for ease of use? GetTransactionOutResponse struct { - BestBlockHash string `json:"bestblock"` - ConfirmationsNum int `json:"confirmations"` - Amount float64 `json:"value"` + BestBlockHash string `json:"bestblock"` + ConfirmationsNum int `json:"confirmations"` + Amount Amount `json:"value"` ScriptPubKey struct { ASM string `json:"asm"` Hex string `json:"hex"` @@ -741,15 +831,16 @@ type ( } */ TransactionReceipt struct { - BlockHash string `json:"blockHash"` - BlockNumber uint64 `json:"blockNumber"` - TransactionHash string `json:"transactionHash"` - TransactionIndex uint64 `json:"transactionIndex"` - From string `json:"from"` + BlockHash string `json:"blockHash"` + BlockNumber uint64 `json:"blockNumber"` + TransactionHash string `json:"transactionHash"` + TransactionIndex uint64 `json:"transactionIndex"` + From string `json:"from"` + To string `json:"to"` + CumulativeGasUsed big.Int `json:"cumulativeGasUsed"` + GasUsed big.Int `json:"gasUsed"` + EffectiveGasPrice big.Int `json:"effectiveGasPrice"` // NOTE: will be null for a contract creation transaction - To string `json:"to"` - CumulativeGasUsed uint64 `json:"cumulativeGasUsed"` - GasUsed uint64 `json:"gasUsed"` // TODO: discuss // ? May be a contract transaction created by non-contract @@ -827,6 +918,25 @@ func (r *GetBlockCountResponse) UnmarshalJSON(data []byte) error { return nil } +// ========== GetGasPrice ============= // + +type ( + GetGasPricetResponse struct { + *big.Int + } +) + +func (r *GetGasPricetResponse) UnmarshalJSON(data []byte) error { + var i *big.Int + err := json.Unmarshal(data, &i) + if err != nil { + return err + } + + r.Int = i + return nil +} + // ========== GetHashrate & GetMining ============= // type ( @@ -879,48 +989,50 @@ type ( Verbose bool } GetRawTransactionResponse struct { - Hex string `json:"hex"` - ID string `json:"txid"` - Hash string `json:"hash"` - Size int64 `json:"size"` - Vsize int64 `json:"vsize"` - Version int64 `json:"version"` - Weight int64 `json:"weight"` - - BlockHash string `json:"blockhash"` - Confirmations int64 `json:"confirmations"` - Time int64 `json:"time"` - BlockTime int64 `json:"blocktime"` + Hex string `json:"hex"` + ID string `json:"txid"` + Hash string `json:"hash"` + Size int64 `json:"size"` + Vsize int64 `json:"vsize"` + Version int64 `json:"version"` + Weight int64 `json:"weight"` + Generated bool `json:"generated"` + + BlockHash string `json:"blockhash"` + BlockIndex int `json:"blockindex"` + TransactionIndex int `json:"index"` + Confirmations int64 `json:"confirmations"` + Time int64 `json:"time"` + BlockTime int64 `json:"blocktime"` OP_SENDER string `json:"OP_SENDER"` Vins []RawTransactionVin `json:"vin"` Vouts []RawTransactionVout `json:"vout"` + GasPrice big.Int `json:"gasPrice"` + Locktime int64 `json:"locktime"` + // Unused fields: // - "in_active_chain" - // - "locktime" } RawTransactionVin struct { - ID string `json:"txid"` - VoutN int64 `json:"vout"` - Amount float64 `json:"value"` - AmountSatoshi int64 `json:"valueSat"` - Address string `json:"address"` + ID string `json:"txid"` + VoutN int64 `json:"vout"` + Amount Amount `json:"value"` + Address string `json:"address"` // TODO: temporary solution ScriptSig DecodedRawTransactionScriptSig `json:"scriptSig"` // Additional fields: - // - "scriptSig" // - "sequence" // - "txinwitness" } // TODO: Make details into a separate struct (or use generic scriptPubKey?) for ease of use? RawTransactionVout struct { - Amount float64 `json:"value"` - AmountSatoshi int64 `json:"valueSat"` - Details RawTransactionVoutDetails `json:"scriptPubKey"` + Amount Amount `json:"value"` + Details RawTransactionVoutDetails `json:"scriptPubKey"` // Additional fields: // - "n" @@ -929,7 +1041,7 @@ type ( RawTransactionVoutDetails struct { Address string `json:"address"` Addresses []string `json:"addresses"` - Asm string `json:"asm"` + ASM string `json:"asm"` Hex string `json:"hex"` // ReqSigs interface{} `json:"reqSigs"` Type string `json:"type"` @@ -955,22 +1067,76 @@ func (r *GetRawTransactionRequest) MarshalJSON() ([]byte, error) { }) } +// Calculates transaction total amount of KAON +func (resp *GetRawTransactionResponse) CalcAmount() decimal.Decimal { + var amount decimal.Decimal + for _, out := range resp.Vouts { + amount = amount.Add(out.Amount.Decimal) + } + return amount +} + func (r *GetRawTransactionResponse) IsPending() bool { return r.BlockHash == "" } -func (r *GetRawTransactionResponse) GetMiningFeeInQTUM() float64 { - var vinsTotals float64 - var voutsTotals float64 +func (r *GetRawTransactionResponse) GetMiningFeeInKAON() (*big.Int, error) { + var fee decimal.Decimal + + // when sending KAON, the first vout will be the target + // the second will be change from the vin, it will be returned to the same account + if len(r.Vouts) > 0 { + + var valueIn decimal.Decimal + var valueOut decimal.Decimal + + for _, vin := range r.Vins { + valueIn = vin.Amount.Add(valueIn) + } + + for _, vout := range r.Vouts { + valueOut = vout.Amount.Add(valueOut) + + } + + if valueIn.Cmp(decimal.Zero) == 0 { // generated + fee = decimal.Zero + } else { - for _, in := range r.Vins { - vinsTotals += in.Amount + fee = valueIn.Sub(valueOut) + } + } else { + fee = decimal.Zero } - for _, out := range r.Vouts { - voutsTotals += out.Amount + + feeBigInt, errEncode := utils.ToBigInt(&fee) + if errEncode != nil { + return nil, errEncode } - return vinsTotals - voutsTotals + return feeBigInt, nil +} + +// ========== GetTransactionHashByEthHash ============= // + +type ( + GetTransactionHashByEthHashRequest struct { + TxID string + } + + /* + KAON trx hash + */ + GetTransactionHashByEthHashResponse string +) + +func (r GetTransactionHashByEthHashRequest) MarshalJSON() ([]byte, error) { + /* + 1. "TxID" (string, required) The transaction hash + */ + return json.Marshal([]interface{}{ + string(r.TxID), + }) } // ========== GetTransaction ============= // @@ -1007,11 +1173,12 @@ type ( } */ GetTransactionResponse struct { - Amount decimal.Decimal `json:"amount"` - Fee decimal.Decimal `json:"fee"` + Amount Amount `json:"amount"` + Fee Amount `json:"fee"` Confirmations int64 `json:"confirmations"` BlockHash string `json:"blockhash"` BlockIndex int64 `json:"blockindex"` + TransactionIndex int64 `json:"index"` BlockTime int64 `json:"blocktime"` ID string `json:"txid"` Time int64 `json:"time"` @@ -1020,22 +1187,21 @@ type ( Details []*TransactionDetail `json:"details"` Hex string `json:"hex"` Generated bool `json:"generated"` + GasPrice big.Int `json:"gasPrice"` } TransactionDetail struct { // TODO: research/discuss - // ! Field is deprecated - Account string `json:"account"` Address string `json:"address"` // Represents transaction direction: `send` or `receive` - Category string `json:"category"` - Amount decimal.Decimal `json:"amount"` + Category string `json:"category"` + Amount Amount `json:"amount"` // Comment value Label string `json:"label"` Vout int64 `json:"vout"` // NOTE: // - Negative value // - Presetned only for `send` transaction category - Fee decimal.Decimal `json:"fee"` + Fee Amount `json:"fee"` // TODO: discuss // ? What's the meaning // @@ -1185,7 +1351,7 @@ type ( "0000000000000000000000000000000000000000000000000000000000000004": "000000000000000000000000000000000000000000000000000000000000000a" }, "c2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b": { - "0000000000000000000000000000000000000000000000000000000000000003": "0000000000000000000000007926223070547d2d15b2ef5e7383e541c338ffe9" + "0000000000000000000000000000000000000000000000000000000000000003": "0000000000000000000000001CE507204a6fC8fd6aA7e54D1481d30ACB0Dbead" } }, "code": "0x..." @@ -1193,7 +1359,7 @@ type ( */ GetAccountInfoResponse struct { Address string `json:"address"` - Balance int `json:"balance"` + Balance big.Int `json:"balance"` Storage json.RawMessage `json:"storage"` Code string `json:"code"` } @@ -1216,7 +1382,7 @@ type ( /* [ - "qUbxboqjBRp96j3La8D1RYkyqx5uQbJPoW" + "ar2SzdHghSgeacypPn7zfDe3qfKAEwimus" ] */ GetAddressesByAccountResponse []string @@ -1301,7 +1467,8 @@ type ( "previousblockhash": "6d7d56af09383301e1bb32a97d4a5c0661d62302c06a778487d919b7115543be", "flags": "proof-of-stake", "proofhash": "15bd6006ecbab06708f705ecf68664b78b388e4d51416cdafb019d5b90239877", - "modifier": "a79c00d1d570743ca8135a173d535258026d26bafbc5f3d951c3d33486b1f120" + "modifier": "a79c00d1d570743ca8135a173d535258026d26bafbc5f3d951c3d33486b1f120", + "gasUsed": 2698989 } */ GetBlockHeaderResponse struct { @@ -1323,6 +1490,8 @@ type ( Flags string `json:"flags"` Proofhash string `json:"proofhash"` Modifier string `json:"modifier"` + Proposer string `json:"proposer"` + GasUsed big.Int `json:"gasUsed"` } ) @@ -1341,7 +1510,7 @@ func (r *GetBlockHeaderResponse) IsGenesisBlock() bool { type ( GetBlockRequest struct { Hash string - Verbosity *int + Verbosity bool } /* @@ -1357,10 +1526,40 @@ type ( "merkleroot": "0b5f03dc9d456c63c587cc554b70c1232449be43d1df62bc25a493b04de90334", "hashStateRoot": "3e49216e58f1ad9e6823b5095dc532f0a6cc44943d36ff4a7b1aa474e172d672", "hashUTXORoot": "130a3e712d9f8b06b83f5ebf02b27542fb682cdff3ce1af1c17b804729d88a47", + "tx": [ "3208dc44733cbfa11654ad5651305428de473ef1e61a1ec07b0c1a5f4843be91", "8fcd819194cce6a8454b2bec334d3448df4f097e9cdc36707bfd569900268950" ], + ... OR + "tx": [ + { + "txid": "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", + "hash": "abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890", + "version": 1, + "size": 234, + "vsize": 123, + "weight": 567, + "locktime": 0, + "vin": [ + { + "coinbase": "031234567890abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + "sequence": 4294967295 + } + ], + "vout": [ + { + "value": 12.345, + "n": 0, + "scriptPubKey": ... + // ... additional vout transactions if available + } + ], + // ... additional details of the transaction if available + } + // ... additional transactions in the block if available + ], + "time": 1536551888, "mediantime": 1536551728, "nonce": 0, @@ -1376,45 +1575,372 @@ type ( } */ GetBlockResponse struct { - Hash string `json:"hash"` - Confirmations int `json:"confirmations"` - Strippedsize int `json:"strippedsize"` - Size int `json:"size"` - Weight int `json:"weight"` - Height int `json:"height"` - Version int `json:"version"` - VersionHex string `json:"versionHex"` - Merkleroot string `json:"merkleroot"` - HashStateRoot string `json:"hashStateRoot"` - HashUTXORoot string `json:"hashUTXORoot"` - Txs []string `json:"tx"` - Time int `json:"time"` - Mediantime int `json:"mediantime"` - Nonce int `json:"nonce"` - Bits string `json:"bits"` - Difficulty float64 `json:"difficulty"` - Chainwork string `json:"chainwork"` - Previousblockhash string `json:"previousblockhash"` - Nextblockhash string `json:"nextblockhash"` - Flags string `json:"flags"` - Proofhash string `json:"proofhash"` - Modifier string `json:"modifier"` - Signature string `json:"signature"` + Hash string `json:"hash"` + Confirmations int `json:"confirmations"` + Strippedsize int `json:"strippedsize"` + Size int `json:"size"` + Weight int `json:"weight"` + Height int `json:"height"` + Version int `json:"version"` + VersionHex string `json:"versionHex"` + Merkleroot string `json:"merkleroot"` + HashStateRoot string `json:"hashStateRoot"` + HashUTXORoot string `json:"hashUTXORoot"` + Txs []interface{} `json:"tx"` + Time int `json:"time"` + Mediantime int `json:"mediantime"` + Nonce int `json:"nonce"` + Bits string `json:"bits"` + Difficulty float64 `json:"difficulty"` + Chainwork string `json:"chainwork"` + Previousblockhash string `json:"previousblockhash"` + Proposer string `json:"Proposer"` + Nextblockhash string `json:"nextblockhash"` + Flags string `json:"flags"` + Proofhash string `json:"proofhash"` + Modifier string `json:"modifier"` + Signature string `json:"signature"` + } + + BlockTransactionDetails struct { + Hex string `json:"hex"` + ID string `json:"txid"` + Hash string `json:"hash"` + Size int64 `json:"size"` + Vsize int64 `json:"vsize"` + Version int64 `json:"version"` + Weight int64 `json:"weight"` + Generated bool `json:"generated"` + + BlockHash string `json:"blockhash"` + BlockIndex int `json:"blockindex"` + TransactionIndex int `json:"index"` + Confirmations int64 `json:"confirmations"` + Time int64 `json:"time"` + BlockTime int64 `json:"blocktime"` + + OP_SENDER string `json:"OP_SENDER"` + + Vins []BlockTransactionVin `json:"vin"` + Vouts []BlockTransactionVout `json:"vout"` + + GasPrice big.Int `json:"gasPrice"` + Locktime int64 `json:"locktime"` + + // Unused fields: + // - "in_active_chain" + + } + + BlockTransactionVin struct { + Address string `json:"address"` + TxID string `json:"txid"` + Vout int64 `json:"vout"` + PreviousVoutPubkey BlockTransactionScriptSig `json:"previousPubkey"` + ScriptSig BlockTransactionScriptSig `json:"scriptSig"` + Txinwitness []string `json:"txinwitness"` + Sequence int64 `json:"sequence"` + Value Amount `json:"value"` + } + + BlockTransactionVout struct { + Value Amount `json:"value"` + N int64 `json:"n"` + ScriptPubKey BlockTransactionScriptPubKey `json:"scriptPubKey"` + } + + // TODO: Make these two generic? Same struct is also present in other RPC data types + BlockTransactionScriptSig struct { + ASM string `json:"asm"` + Hex string `json:"hex"` + } + + BlockTransactionScriptPubKey struct { + ASM string `json:"asm"` + Hex string `json:"hex"` + ReqSigs int64 `json:"reqSigs"` + Type string `json:"type"` + Addresses []string `json:"addresses"` } ) func (r *GetBlockRequest) MarshalJSON() ([]byte, error) { - verbosity := 1 - if r.Verbosity != nil { - verbosity = *r.Verbosity - } return json.Marshal([]interface{}{ r.Hash, - verbosity, + r.Verbosity, }) } +func (r *BlockTransactionDetails) UnmarshalJSON(data []byte) error { + if string(data) == "[]" { + return EmptyResponseErr + } + type Response BlockTransactionDetails + var resp Response + if err := json.Unmarshal(data, &resp); err != nil { + return err + } + + *r = BlockTransactionDetails(resp) + + return nil +} + +func (r *BlockTransactionDetails) IsPending() bool { + return r.BlockHash == "" +} + +func (r *BlockTransactionDetails) GetMiningFeeInKAON() (*big.Int, error) { + if r.Generated { + return big.NewInt(0), nil + } + + var fee decimal.Decimal + + // when sending KAON, the first vout will be the target + // the second will be change from the vin, it will be returned to the same account + if len(r.Vouts) > 0 { + + var valueIn decimal.Decimal + var valueOut decimal.Decimal + + for _, vin := range r.Vins { + valueIn = vin.Value.Add(valueIn) + } + + for _, vout := range r.Vouts { + valueOut = vout.Value.Add(valueOut) + + } + if valueIn.Cmp(decimal.Zero) == 0 { // generated + fee = decimal.Zero + } else { + + fee = valueIn.Sub(valueOut) + } + } else { + fee = decimal.Zero + } + + feeBigInt, errEncode := utils.ToBigInt(&fee) + if errEncode != nil { + return nil, errEncode + } + + return feeBigInt, nil +} + +// Calculates transaction total amount of KAON +func (resp *BlockTransactionDetails) CalcAmount() decimal.Decimal { + var amount decimal.Decimal + for _, out := range resp.Vouts { + amount = amount.Add(out.Value.Decimal) + } + return amount +} + +func (resp *BlockTransactionDetails) ExtractContractInfo() (_ ContractInfo, isContractTx bool, _ error) { + // Break if Vouts have several contracts + + var info *ContractInfo + + for _, vout := range resp.Vouts { + var ( + script = strings.Split(vout.ScriptPubKey.ASM, " ") + finalOp = script[len(script)-1] + ) + + switch finalOp { + case "OP_CALL": + if info != nil { + return ContractInfo{}, false, errors.New("Duplicate OP_CALL/OP_CREATE vouts") + } + callInfo, err := ParseCallSenderASM(script) + // OP_CALL with OP_SENDER has the script type "nonstandard" + if err != nil { + // Check for OP_CALL without OP_SENDER + callInfo, err = ParseCallASM(script) + if err != nil { + return ContractInfo{}, false, errors.WithMessage(err, "couldn't parse call sender ASM") + } + } + info = &ContractInfo{ + From: callInfo.From, + To: callInfo.To, + GasLimit: callInfo.GasLimit, + GasPrice: callInfo.GasPrice, + UserInput: callInfo.CallData, + } + + return *info, true, nil + + case "OP_CREATE": + if info != nil { + return ContractInfo{}, false, errors.New("Duplicate OP_CALL/OP_CREATE vouts") + } + // OP_CALL with OP_SENDER has the script type "create_sender" + createInfo, err := ParseCreateSenderASM(script) + if err != nil { + // Check for OP_CREATE without OP_SENDER + createInfo, err = ParseCreateASM(script) + if err != nil { + return ContractInfo{}, false, errors.WithMessage(err, "couldn't parse create sender ASM") + } + } + info = &ContractInfo{ + From: createInfo.From, + To: createInfo.To, + GasLimit: createInfo.GasLimit, + GasPrice: createInfo.GasPrice, + UserInput: createInfo.CallData, + } + + return *info, true, nil + + case "OP_SPEND": + // TODO: complete + return ContractInfo{}, true, errors.New("OP_SPEND contract parsing partially implemented") + + case "OP_CHECKSIG": + if !resp.Generated { // generated trxes does not have valuable vins data so process what do we have + continue + } + + if vout.ScriptPubKey.Type != "pubkey" && vout.ScriptPubKey.Type != "pubkeyhash" { + continue // do not support other types + } + + var ( + reciever = "" + ) + for _, address := range vout.ScriptPubKey.Addresses { + if address != "" { + // P2Sh address(such as MUrenj2sPqEVTiNbHQ2RARiZYyTAAeKiDX) and BECH32 address (such as qc1qkt33x6hkrrlwlr6v59wptwy6zskyrjfe40y0lx) + // will cause ConvertKaonAddress to fall + // but we not support them for now + hex, err := utils.ConvertKaonAddress(address) + if err == nil { + reciever = hex + break + } + } + } + + return ContractInfo{ + From: "", + To: reciever, + }, false, nil + } + + } + + if info != nil { + return *info, true, nil + } + + if resp.Generated { + return ContractInfo{}, false, nil + } + + // Let's try a standard trx parsing method + for i, vin := range resp.Vins { + fromAddress := "" + if vin.Address == "" { + var ( + script = strings.Split(vin.PreviousVoutPubkey.ASM, " ") + finalOp = script[len(script)-1] + ) + if finalOp != "OP_CHECKSIG" { + continue // We do not support non-standard money transfers + } + sender, err := ParseP2PKHReciever(script) + if err != nil { + continue + } + + // P2Sh address(such as MUrenj2sPqEVTiNbHQ2RARiZYyTAAeKiDX) and BECH32 address (such as qc1qkt33x6hkrrlwlr6v59wptwy6zskyrjfe40y0lx) + // will cause ConvertKaonAddress to fall + // but we not support them for now + fromAddressIn, err := utils.ConvertKaonAddress(*sender) + + if err != nil { + continue + } + fromAddress = fromAddressIn + } else { + + // P2Sh address(such as MUrenj2sPqEVTiNbHQ2RARiZYyTAAeKiDX) and BECH32 address (such as qc1qkt33x6hkrrlwlr6v59wptwy6zskyrjfe40y0lx) + // will cause ConvertKaonAddress to fall + // but we not support them for now + fromAddressIn, err := utils.ConvertKaonAddress(vin.Address) + + if err != nil { + continue + } + fromAddress = fromAddressIn + } + + if int(vin.Vout) >= len(resp.Vouts) { + continue + + // TODO: probably we still may be able to solve it in that case + // research + // return ContractInfo{ + // From: fromAddress, + // }, false, nil + } + + var ( + vout = resp.Vouts[i] + reciever = "" + ) + for _, address := range vout.ScriptPubKey.Addresses { + if address != "" { + // P2Sh address(such as MUrenj2sPqEVTiNbHQ2RARiZYyTAAeKiDX) and BECH32 address (such as qc1qkt33x6hkrrlwlr6v59wptwy6zskyrjfe40y0lx) + // will cause ConvertKaonAddress to fall + // but we not support them for now + hex, err := utils.ConvertKaonAddress(address) + if err == nil { + reciever = hex + break + } + } + } + + if reciever == "" { + var ( + script = strings.Split(vout.ScriptPubKey.ASM, " ") + finalOp = script[len(script)-1] + ) + if finalOp != "OP_CHECKSIG" { + continue // We do not support non-standard money transfers + } + recieverParsed, err := ParseP2PKHReciever(script) + if err != nil { + continue + } + + // P2Sh address(such as MUrenj2sPqEVTiNbHQ2RARiZYyTAAeKiDX) and BECH32 address (such as qc1qkt33x6hkrrlwlr6v59wptwy6zskyrjfe40y0lx) + // will cause ConvertKaonAddress to fall + // but we not support them for now + recieverIn, err := utils.ConvertKaonAddress(*recieverParsed) + + if err != nil { + continue + } + reciever = recieverIn + } + + return ContractInfo{ + From: fromAddress, + To: reciever, + }, false, nil + } + + return ContractInfo{}, false, nil +} + // ========CreateRawTransaction=========// type ( /* @@ -1434,7 +1960,7 @@ type ( accepted as second parameter. [ { (json object) - "address": amount, (numeric or string, required) A key-value pair. The key (string) is the qtum address, the value (float or string) is the amount in QTUM + "address": amount, (numeric or string, required) A key-value pair. The key (string) is the Kaon address, the value (float or string) is the amount in KAON }, { (json object) "data": "hex", (string, required) A key-value pair. The key must be "data", the value is hex-encoded data @@ -1442,16 +1968,16 @@ type ( { (json object) (send to contract) "contractAddress": "hex", (string, required) Valid contract address (valid hash160 hex data) "data": "hex", (string, required) Hex data to add in the call output - "amount": amount, (numeric or string, optional, default=0) Value in QTUM to send with the call, should be a valid amount, default 0 + "amount": amount, (numeric or string, optional, default=0) Value in KAON to send with the call, should be a valid amount, default 0 "gasLimit": n, (numeric) The gas limit for the transaction "gasPrice": n, (numeric) The gas price for the transaction - "senderaddress": "hex", (string) The qtum address that will be used to create the contract. + "senderaddress": "hex", (string) The Kaon address that will be used to create the contract. }, { (json object) (create contract) "bytecode": "hex", (string, required) contract bytcode. "gasLimit": n, (numeric) The gas limit for the transaction "gasPrice": n, (numeric) The gas price for the transaction - "senderaddress": "hex", (string) The qtum address that will be used to create the contract. + "senderaddress": "hex", (string) The Kaon address that will be used to create the contract. }, ... ] @@ -1499,28 +2025,6 @@ type ( } ) -// ======== sendrawtransaction ========= // - -type ( - // Presents hexed string of a raw transcation - SendRawTransactionRequest [1]string - // Presents hexed string of a transaction hash - SendRawTransactionResponse struct { - Result string `json:"result"` - } -) - -func (r *SendRawTransactionResponse) UnmarshalJSON(data []byte) error { - var result string - err := json.Unmarshal(data, &result) - if err != nil { - return err - } - - r.Result = result - return nil -} - // ========== GetAddressUTXOs ============= // type ( @@ -1528,8 +2032,8 @@ type ( Arguments: 1. Input params (json object, required) Json object { - "addresses": [ (json array, required) The qtum addresses - "address", (string) The qtum address + "addresses": [ (json array, required) The Kaon addresses + "address", (string) The Kaon address ... ], "chainInfo": bool, (boolean, optional) Include chain info with results @@ -1551,13 +2055,13 @@ type ( } UTXO struct { - Address string `json:"address"` - TXID string `json:"txid"` - OutputIndex uint `json:"outputIndex"` - Script string `json:"script"` - Satoshis decimal.Decimal `json:"satoshis"` - Height *big.Int `json:"height"` - IsStake bool `json:"isStake"` + Address string `json:"address"` + TXID string `json:"txid"` + OutputIndex uint `json:"outputIndex"` + Script string `json:"script"` + Satoshis Amount `json:"satoshis"` + Height *big.Int `json:"height"` + IsStake bool `json:"isStake"` } GetAddressUTXOsResponse []UTXO @@ -1591,19 +2095,19 @@ type ( Arguments: 1. minconf (numeric, optional, default=1) The minimum confirmations to filter 2. maxconf (numeric, optional, default=9999999) The maximum confirmations to filter - 3. "addresses" (string) A json array of qtum addresses to filter + 3. "addresses" (string) A json array of Kaon addresses to filter [ - "address" (string) qtum address + "address" (string) Kaon address ,... ] 4. include_unsafe (bool, optional, default=true) Include outputs that are not safe to spend See description of "safe" attribute below. 5. query_options (json, optional) JSON with query options { - "minimumAmount" (numeric or string, default=0) Minimum value of each UTXO in QTUM - "maximumAmount" (numeric or string, default=unlimited) Maximum value of each UTXO in QTUM + "minimumAmount" (numeric or string, default=0) Minimum value of each UTXO in KAON + "maximumAmount" (numeric or string, default=unlimited) Maximum value of each UTXO in KAON "maximumCount" (numeric or string, default=unlimited) Maximum number of UTXOs - "minimumSumAmount" (numeric or string, default=unlimited) Minimum sum value of all UTXOs in QTUM + "minimumSumAmount" (numeric or string, default=unlimited) Minimum sum value of all UTXOs in KAON } */ ListUnspentRequest struct { @@ -1614,9 +2118,9 @@ type ( } ListUnspentQueryOptions struct { // Applies to each UTXO - MinAmount decimal.Decimal + MinAmount Amount // Applies to each UTXO - MaxAmount decimal.Decimal + MaxAmount Amount MaxNumToReturn int // Returns only those UTXOs, which total amount // is greater than or equal `MinSumAmount` @@ -1624,7 +2128,7 @@ type ( // NOTE: it doesn't consider amount of all // UTXOs, that is not all UTXOs may be // returned, but a limited number of UTXOs - MinSumAmount decimal.Decimal + MinSumAmount Amount } /* @@ -1632,10 +2136,10 @@ type ( { "txid" : "txid", (string) the transaction id "vout" : n, (numeric) the vout value - "address" : "address", (string) the qtum address + "address" : "address", (string) the Kaon address "account" : "account", (string) DEPRECATED. The associated account, or "" for the default account "scriptPubKey" : "key", (string) the script key - "amount" : x.xxx, (numeric) the transaction output amount in QTUM + "amount" : x.xxx, (numeric) the transaction output amount in KAON "confirmations" : n, (numeric) The number of confirmations "redeemScript" : n (string) The redeemScript if scriptPubKey is P2SH "spendable" : xxx, (bool) Whether we have the private keys to spend this output @@ -1651,7 +2155,7 @@ type ( { "txid": "a8d97ae8bb819cd4aa98ed2ddaef4969783aee845461a9ea5a88184ad58f44fe", "vout": 2, - "address": "qUbxboqjBRp96j3La8D1RYkyqx5uQbJPoW", + "address": "ar2SzdHghSgeacypPn7zfDe3qfKAEwimus", "account": "", "scriptPubKey": "210299d391f528b9edd07284c7e23df8415232a8ce41531cf460a390ce32b4efd112ac", "amount": 15007.10682200, @@ -1663,29 +2167,20 @@ type ( ] */ ListUnspentResponse []struct { - Address string `json:"address"` - Txid string `json:"txid"` - Vout uint `json:"vout"` - Amount decimal.Decimal `json:"amount"` - Safe bool `json:"safe"` - Spendable bool `json:"spendable"` - Solvable bool `json:"solvable"` - Label string `json:"label"` - Confirmations int `json:"confirmations"` - ScriptPubKey string `json:"scriptPubKey"` - RedeemScript string `json:"redeemScript"` + Address string `json:"address"` + Txid string `json:"txid"` + Vout uint `json:"vout"` + Amount Amount `json:"amount"` + Safe bool `json:"safe"` + Spendable bool `json:"spendable"` + Solvable bool `json:"solvable"` + Label string `json:"label"` + Confirmations int `json:"confirmations"` + ScriptPubKey string `json:"scriptPubKey"` + RedeemScript string `json:"redeemScript"` } ) -func NewListUnspentRequest(options ListUnspentQueryOptions, addresses ...string) *ListUnspentRequest { - return &ListUnspentRequest{ - MinConf: 1, - MaxConf: 99999999, - Addresses: addresses, - QueryOptions: options, - } -} - func (r *ListUnspentRequest) MarshalJSON() ([]byte, error) { params := []interface{}{ r.MinConf, @@ -1741,9 +2236,9 @@ type ( /* Arguments: - 1. addresses (json array, required) The qtum addresses + 1. addresses (json array, required) The Kaon addresses [ - "address", (string) The qtum address + "address", (string) The Kaon address ... ] Result: @@ -1753,19 +2248,19 @@ type ( } */ GetAddressBalanceRequest struct { - Addresses []string `json:"addresses"` + Address string } GetAddressBalanceResponse struct { - Balance uint64 `json:"balance"` - Received uint64 `json:"received"` - Immature int64 `json:"immature"` + Balance big.Int `json:"balance"` + Received big.Int `json:"received"` + Immature big.Int `json:"immature"` } ) func (req *GetAddressBalanceRequest) MarshalJSON() ([]byte, error) { - params := []map[string][]string{ - {"addresses": req.Addresses}, + params := []interface{}{ + req.Address, } return json.Marshal(params) } @@ -1856,8 +2351,8 @@ type ( Connections int64 `json:"connections"` NetworkActive bool `json:"networkactive"` Networks []NetworkInfoNetworkInfo `json:"networks"` - RelayFee decimal.Decimal `json:"relayfee"` - IncrementalFee decimal.Decimal `json:"incrementalfee"` + RelayFee Amount `json:"relayfee"` + IncrementalFee Amount `json:"incrementalfee"` LocalAddresses []NetworkInfoLocalAddress `json:"localaddresses"` Warnings string `json:"warnings"` } @@ -1900,9 +2395,9 @@ type ( From string `json:"from"` // (does this apply to waitforlogs or only searchlogs?) // NOTE: will be null for a contract creation transaction - To string `json:"to"` - CumulativeGasUsed uint64 `json:"cumulativeGasUsed"` - GasUsed uint64 `json:"gasUsed"` + To string `json:"to"` + CumulativeGasUsed big.Int `json:"cumulativeGasUsed"` + GasUsed big.Int `json:"gasUsed"` // (does this apply to waitforlogs or only searchlogs?) // TODO: discuss - @@ -1997,29 +2492,64 @@ type ( } ) -// ========= unloadwallet ======== // -type ( - UnloadWalletRequest []string - UnloadWalletResponse struct { - Warning string `json:"warning"` - } -) +// ======== sendrawtransaction ========= // -// ========= listwallets ========= // type ( - ListWalletsRequest []string - ListWalletsResponse []string -) + // Presents hexed string of a raw transcation + SendRawTransactionRequest [1]string -// ======== listwalletdir ======== // + GeneralSendRawTransactionResponse struct { + // Error *string `json:"error"` + // ID string `json:"id"` + Result string `json:"result"` -type ListWalletDirWallet struct { - Name string `json:"name"` -} + // It may have in the Data + // SendRawTransactionResponse / CreateContractResponse / CallContractResponse or SendToContractResponse + Data interface{} `json:"-"` + } -type ( - ListWalletDirRequest []string - ListWalletDirResponse struct { - Wallets []ListWalletDirWallet `json:"wallets"` + // Presents hexed string of a transaction hash + SendRawTransactionResponse struct { + Result string `json:"result"` } ) + +func (r *GeneralSendRawTransactionResponse) UnmarshalJSON(data []byte) error { + var err error + + // Check for unique identifiers in `data` and unmarshal the specific parts + if strings.Contains(string(data), "txid") && strings.Contains(string(data), "address") { + var createContractResponse CreateContractResponse + err = json.Unmarshal(data, &createContractResponse) + if err != nil { + return err + } + r.Data = createContractResponse + } else if strings.Contains(string(data), "executionResult") { + var callContractResponse CallContractResponse + err = json.Unmarshal(data, &callContractResponse) + if err != nil { + return err + } + r.Data = callContractResponse + } else if strings.Contains(string(data), "txid") { + var sendToContractResponse SendToContractResponse + err = json.Unmarshal(data, &sendToContractResponse) + if err != nil { + return err + } + r.Data = sendToContractResponse + } else { + // SendRawTransactionResponse is a string + // If no unique identifier is present, assume it's SendRawTransactionResponse + var sendRawTransactionResponse string + err = json.Unmarshal(data, &sendRawTransactionResponse) + if err != nil { + return err + } + r.Result = sendRawTransactionResponse + r.Data = sendRawTransactionResponse + } + + return nil +} diff --git a/pkg/qtum/rpc_types_test.go b/pkg/kaon/rpc_types_test.go similarity index 78% rename from pkg/qtum/rpc_types_test.go rename to pkg/kaon/rpc_types_test.go index 8c5f8a71..6742e8c7 100644 --- a/pkg/qtum/rpc_types_test.go +++ b/pkg/kaon/rpc_types_test.go @@ -1,14 +1,62 @@ -package qtum +package kaon import ( "encoding/json" "math/big" - "reflect" + "strings" "testing" - "github.com/shopspring/decimal" + "github.com/pkg/errors" ) +func (resp *DecodedRawTransactionResponse) GetOpSenderAddress() (address string, _ error) { + for _, vout := range resp.Vouts { + // OP_SENDER is only valid in scripts ending in ether OP_CREATE or OP_CALL + if strings.HasSuffix(vout.ScriptPubKey.ASM, "OP_CREATE") || strings.HasSuffix(vout.ScriptPubKey.ASM, "OP_CALL") { + var scriptChunks = strings.Split(vout.ScriptPubKey.ASM, " ") + + // OP_CREATE prefixed by OP_SENDER always have this structure: + // + // 1 // address type of the pubkeyhash (public key hash) + // Address // sender's pubkeyhash address + // {signature, pubkey} //serialized scriptSig + // OP_SENDER + // 4 // EVM version + // 100000 //gas limit + // 10 //gas price + // 1234 // data to be sent by the contract + // OP_CREATE + var isOpCreateWithOpSender = len(scriptChunks) == 9 || len(scriptChunks) == 16 + + // OP_CALL prefixed by OP_SENDER always have this structure: + // + // 1 // address type of the pubkeyhash (public key hash) + // Address // sender's pubkeyhash address + // {signature, pubkey} // serialized scriptSig + // OP_SENDER + // 4 // EVM version + // 100000 // gas limit + // 10 // gas price + // 1234 // data to be sent by the contract + // Contract Address // contract address + // OP_CALL + var isOpCallWithOpSender = len(scriptChunks) == 10 || len(scriptChunks) == 17 + + // Note: This check isn't redundant with the initial opcode check, since both opcodes are valid without OP_SENDER prefix + if isOpCreateWithOpSender || isOpCallWithOpSender { + // Address type, only support 1 for now + if scriptChunks[0] != "1" { + return "", errors.New("OP_SENDER address if of invalid type (only type 1 is supported currently)") + } + var opSenderAddress = scriptChunks[1] + + return opSenderAddress, nil + } + } + } + return "", errors.New("No script with OP_SENDER found in Vouts") +} + func TestSearchLogsRequestFiltersTopicsIfAllNull(t *testing.T) { expected := `[1,2,{"addresses":["0x1","0x2"]},null,1]` minConfs := uint(1) @@ -127,12 +175,12 @@ func TestGetOpSenderAddressWithOpCreate(t *testing.T) { testData := DecodedRawTransactionResponse{ Vouts: []*DecodedRawTransactionOutV{{ ScriptPubKey: DecodedRawTransactionScriptPubKey{ - ASM: "1 69b004ac2b3993bf2fdf56b02746a1f57997420d 6a4730440220780bd9116bc36405bedc19d58cafb6e1cbe776c44c558aba93c7ecd86fba08a40220072d475b177721c35fa2013377ab00a00a5eabacc09d001d95a39eb75eaeae0301210375870ec95337038109498653660971764cef604873bc29dd92773bd3baddc56e OP_SENDER 4 2500000 40 60806040526100106008600a610141565b61001e90633b9aca00610154565b60005534801561002d57600080fd5b50600080543382526001602052604090912055610173565b634e487b7160e01b600052601160045260246000fd5b600181815b8085111561009657816000190482111561007c5761007c610045565b8085161561008957918102915b93841c9390800290610060565b509250929050565b6000826100ad5750600161013b565b816100ba5750600061013b565b81600181146100d057600281146100da576100f6565b600191505061013b565b60ff8411156100eb576100eb610045565b50506001821b61013b565b5060208310610133831016604e8410600b8410161715610119575081810a61013b565b610123838361005b565b806000190482111561013757610137610045565b0290505b92915050565b600061014d838361009e565b9392505050565b600081600019048311821515161561016e5761016e610045565b500290565b6106e0806101826000396000f3fe6080604052600436106100855760003560e01c806306fdde0314610094578063095ea7b3146100de57806318160ddd1461010e57806323b872dd14610132578063313ce567146101525780635a3b7e421461017957806370a08231146101ae57806395d89b41146101db578063a9059cbb1461020a578063dd62ed3e1461022a57600080fd5b3661008f57600080fd5b600080fd5b3480156100a057600080fd5b506100c860405180604001604052806008815260200167145490c8151154d560c21b81525081565b6040516100d5919061050a565b60405180910390f35b3480156100ea57600080fd5b506100fe6100f936600461057b565b610262565b60405190151581526020016100d5565b34801561011a57600080fd5b5061012460005481565b6040519081526020016100d5565b34801561013e57600080fd5b506100fe61014d3660046105a5565b610315565b34801561015e57600080fd5b50610167600881565b60405160ff90911681526020016100d5565b34801561018557600080fd5b506100c860405180604001604052806009815260200168546f6b656e20302e3160b81b81525081565b3480156101ba57600080fd5b506101246101c93660046105e1565b60016020526000908152604090205481565b3480156101e757600080fd5b506100c86040518060400160405280600381526020016251544360e81b81525081565b34801561021657600080fd5b506100fe61022536600461057b565b61042d565b34801561023657600080fd5b506101246102453660046105fc565b600260209081526000928352604080842090915290825290205481565b6000826001600160a01b03811661027857600080fd5b8215806102a657503360009081526002602090815260408083206001600160a01b0388168452909152902054155b6102af57600080fd5b3360008181526002602090815260408083206001600160a01b03891680855290835292819020879055518681529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a35060019392505050565b6000836001600160a01b03811661032b57600080fd5b836001600160a01b03811661033f57600080fd5b6001600160a01b038616600090815260026020908152604080832033845290915290205461036d90856104c8565b6001600160a01b0387166000818152600260209081526040808320338452825280832094909455918152600190915220546103a890856104c8565b6001600160a01b0380881660009081526001602052604080822093909355908716815220546103d790856104eb565b6001600160a01b03808716600081815260016020526040908190209390935591519088169060008051602061068b833981519152906104199088815260200190565b60405180910390a350600195945050505050565b6000826001600160a01b03811661044357600080fd5b3360009081526001602052604090205461045d90846104c8565b33600090815260016020526040808220929092556001600160a01b0386168152205461048990846104eb565b6001600160a01b03851660008181526001602052604090819020929092559051339060008051602061068b833981519152906103039087815260200190565b6000818310156104da576104da61062f565b6104e4828461065b565b9392505050565b6000806104f88385610672565b9050838110156104e4576104e461062f565b600060208083528351808285015260005b818110156105375785810183015185820160400152820161051b565b81811115610549576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b038116811461057657600080fd5b919050565b6000806040838503121561058e57600080fd5b6105978361055f565b946020939093013593505050565b6000806000606084860312156105ba57600080fd5b6105c38461055f565b92506105d16020850161055f565b9150604084013590509250925092565b6000602082840312156105f357600080fd5b6104e48261055f565b6000806040838503121561060f57600080fd5b6106188361055f565b91506106266020840161055f565b90509250929050565b634e487b7160e01b600052600160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60008282101561066d5761066d610645565b500390565b6000821982111561068557610685610645565b50019056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212204f0b7715a86df24f99b5c5614a27135476c273daed593651ad8a700c8be258cd64736f6c634300080b0033 OP_CREATE", + ASM: "1 57ed9afd4668ab81b648e68d2a76227434d6a8ee 6a4730440220780bd9116bc36405bedc19d58cafb6e1cbe776c44c558aba93c7ecd86fba08a40220072d475b177721c35fa2013377ab00a00a5eabacc09d001d95a39eb75eaeae0301210375870ec95337038109498653660971764cef604873bc29dd92773bd3baddc56e OP_SENDER 4 2500000 40 60806040526100106008600a610141565b61001e90633b9aca00610154565b60005534801561002d57600080fd5b50600080543382526001602052604090912055610173565b634e487b7160e01b600052601160045260246000fd5b600181815b8085111561009657816000190482111561007c5761007c610045565b8085161561008957918102915b93841c9390800290610060565b509250929050565b6000826100ad5750600161013b565b816100ba5750600061013b565b81600181146100d057600281146100da576100f6565b600191505061013b565b60ff8411156100eb576100eb610045565b50506001821b61013b565b5060208310610133831016604e8410600b8410161715610119575081810a61013b565b610123838361005b565b806000190482111561013757610137610045565b0290505b92915050565b600061014d838361009e565b9392505050565b600081600019048311821515161561016e5761016e610045565b500290565b6106e0806101826000396000f3fe6080604052600436106100855760003560e01c806306fdde0314610094578063095ea7b3146100de57806318160ddd1461010e57806323b872dd14610132578063313ce567146101525780635a3b7e421461017957806370a08231146101ae57806395d89b41146101db578063a9059cbb1461020a578063dd62ed3e1461022a57600080fd5b3661008f57600080fd5b600080fd5b3480156100a057600080fd5b506100c860405180604001604052806008815260200167145490c8151154d560c21b81525081565b6040516100d5919061050a565b60405180910390f35b3480156100ea57600080fd5b506100fe6100f936600461057b565b610262565b60405190151581526020016100d5565b34801561011a57600080fd5b5061012460005481565b6040519081526020016100d5565b34801561013e57600080fd5b506100fe61014d3660046105a5565b610315565b34801561015e57600080fd5b50610167600881565b60405160ff90911681526020016100d5565b34801561018557600080fd5b506100c860405180604001604052806009815260200168546f6b656e20302e3160b81b81525081565b3480156101ba57600080fd5b506101246101c93660046105e1565b60016020526000908152604090205481565b3480156101e757600080fd5b506100c86040518060400160405280600381526020016251544360e81b81525081565b34801561021657600080fd5b506100fe61022536600461057b565b61042d565b34801561023657600080fd5b506101246102453660046105fc565b600260209081526000928352604080842090915290825290205481565b6000826001600160a01b03811661027857600080fd5b8215806102a657503360009081526002602090815260408083206001600160a01b0388168452909152902054155b6102af57600080fd5b3360008181526002602090815260408083206001600160a01b03891680855290835292819020879055518681529192917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591015b60405180910390a35060019392505050565b6000836001600160a01b03811661032b57600080fd5b836001600160a01b03811661033f57600080fd5b6001600160a01b038616600090815260026020908152604080832033845290915290205461036d90856104c8565b6001600160a01b0387166000818152600260209081526040808320338452825280832094909455918152600190915220546103a890856104c8565b6001600160a01b0380881660009081526001602052604080822093909355908716815220546103d790856104eb565b6001600160a01b03808716600081815260016020526040908190209390935591519088169060008051602061068b833981519152906104199088815260200190565b60405180910390a350600195945050505050565b6000826001600160a01b03811661044357600080fd5b3360009081526001602052604090205461045d90846104c8565b33600090815260016020526040808220929092556001600160a01b0386168152205461048990846104eb565b6001600160a01b03851660008181526001602052604090819020929092559051339060008051602061068b833981519152906103039087815260200190565b6000818310156104da576104da61062f565b6104e4828461065b565b9392505050565b6000806104f88385610672565b9050838110156104e4576104e461062f565b600060208083528351808285015260005b818110156105375785810183015185820160400152820161051b565b81811115610549576000604083870101525b50601f01601f1916929092016040019392505050565b80356001600160a01b038116811461057657600080fd5b919050565b6000806040838503121561058e57600080fd5b6105978361055f565b946020939093013593505050565b6000806000606084860312156105ba57600080fd5b6105c38461055f565b92506105d16020850161055f565b9150604084013590509250925092565b6000602082840312156105f357600080fd5b6104e48261055f565b6000806040838503121561060f57600080fd5b6106188361055f565b91506106266020840161055f565b90509250929050565b634e487b7160e01b600052600160045260246000fd5b634e487b7160e01b600052601160045260246000fd5b60008282101561066d5761066d610645565b500390565b6000821982111561068557610685610645565b50019056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa26469706673582212204f0b7715a86df24f99b5c5614a27135476c273daed593651ad8a700c8be258cd64736f6c634300080b0033 OP_CREATE", }, }}, } - expected := "69b004ac2b3993bf2fdf56b02746a1f57997420d" + expected := "57ed9afd4668ab81b648e68d2a76227434d6a8ee" result, err := testData.GetOpSenderAddress() @@ -148,59 +196,3 @@ func TestGetOpSenderAddressWithOpCreate(t *testing.T) { ) } } - -func TestExtractContractInfo(t *testing.T) { - value, _ := decimal.NewFromString("1.89868837") - testData := DecodedRawTransactionResponse{ - Vouts: []*DecodedRawTransactionOutV{ - { - Value: value, - N: 0, - ScriptPubKey: DecodedRawTransactionScriptPubKey{ - ASM: "OP_DUP OP_HASH160 93594441cb5de8b497ad8467d55412c2a0ef3659 OP_EQUALVERIFY OP_CHECKSIG", - Hex: "76a91493594441cb5de8b497ad8467d55412c2a0ef365988ac", - Addresses: []string{ - "Qa36NrNdFgr4XeMxKdZeSZ1FGCdSNLmqXh", - }, - Type: "pubkeyhash", - }, - }, - { - Value: decimal.Zero, - N: 1, - ScriptPubKey: DecodedRawTransactionScriptPubKey{ - ASM: "1 93594441cb5de8b497ad8467d55412c2a0ef3659 6a4730440220396b30b7a2f2af482e585473b7575dd2f989f3f3d7cdee55fa34e93f23d5254d022055326cdcab38c58dc3e65c458bfb656cca8340f59534c00ad98b4d4d3303f459012103379c39b6fb2c705db608f98a8fc064f94c66faf894996ca88595487f9ef04a6e OP_SENDER 4 250000 40 -191784509 0000000000000000000000000000000000000086 OP_CALL", - Hex: "01011493594441cb5de8b497ad8467d55412c2a0ef36594c6b6a4730440220396b30b7a2f2af482e585473b7575dd2f989f3f3d7cdee55fa34e93f23d5254d022055326cdcab38c58dc3e65c458bfb656cca8340f59534c00ad98b4d4d3303f459012103379c39b6fb2c705db608f98a8fc064f94c66faf894996ca88595487f9ef04a6ec401040390d0030128043d666e8b140000000000000000000000000000000000000086c2", - Addresses: []string{}, - Type: "call_sender", - }, - }, - }, - } - - expected := ContractInfo{ - From: "93594441cb5de8b497ad8467d55412c2a0ef3659", - To: "0000000000000000000000000000000000000086", - GasPrice: "28", - GasLimit: "3d090", - UserInput: "3d666e8b", - } - - result, isContractTx, err := testData.ExtractContractInfo() - - if err != nil { - t.Fatal(err) - } - - if isContractTx == false { - t.Errorf("error\n\n-----\n\nwant: %t\n\n-----\n\ngot: %t", true, isContractTx) - } - - if !reflect.DeepEqual(result, expected) { - t.Errorf( - "error\n\n-----\n\nwant: %s\n\n-----\n\ngot: %s", - expected, - result, - ) - } -} diff --git a/pkg/notifier/agent.go b/pkg/notifier/agent.go index 85f3721c..c7d152ae 100644 --- a/pkg/notifier/agent.go +++ b/pkg/notifier/agent.go @@ -4,15 +4,16 @@ import ( "context" "encoding/json" "fmt" + "net/http" "strings" "sync" "time" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/utils" "github.com/labstack/echo" "github.com/pkg/errors" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" - "github.com/qtumproject/janus/pkg/utils" ) var agentConfigNewHeadsKey = "newHeadsInterval" @@ -20,22 +21,26 @@ var agentConfigNewHeadsInterval = 10 * time.Second // Allows dependency injection of eth rpc calls as the transformer package imports this package type Transformer interface { - Transform(req *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) + Transform(req *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) } -func NewAgent(ctx context.Context, qtum *qtum.Qtum, transformer Transformer) *Agent { - return newAgentWithConfiguration(ctx, qtum, transformer, make(map[string]interface{})) +func NewAgent(ctx context.Context, kaon *kaon.Kaon, transformer Transformer) *Agent { + return newAgentWithConfiguration(ctx, kaon, transformer, make(map[string]interface{})) } -func newAgentWithConfiguration(ctx context.Context, qtum *qtum.Qtum, transformer Transformer, configuration map[string]interface{}) *Agent { +func NewEchoWithContext(ctx context.Context) echo.Context { + return echo.New().NewContext((&http.Request{}).WithContext(ctx), nil) +} + +func newAgentWithConfiguration(ctx context.Context, kaon *kaon.Kaon, transformer Transformer, configuration map[string]interface{}) *Agent { if ctx == nil { panic("ctx cannot be nil") } - if qtum == nil { - panic("qtum cannot be nil") + if kaon == nil { + panic("kaon cannot be nil") } agent := &Agent{ - qtum: qtum, + kaon: kaon, transformer: transformer, ctx: ctx, mutex: sync.RWMutex{}, @@ -112,7 +117,7 @@ func (s *subscriptionRegistry) SendAll(message interface{}) { } type Agent struct { - qtum *qtum.Qtum + kaon *kaon.Kaon transformer Transformer ctx context.Context mutex sync.RWMutex @@ -246,6 +251,7 @@ func (a *Agent) NewSubscription(notifier *Notifier, params *eth.EthSubscriptionR } wrappedContext, cancel := context.WithCancel(notifier.Context()) + subType := strings.ToLower(params.Method) wrappedSubscription := &subscriptionInformation{ subscription, @@ -254,10 +260,12 @@ func (a *Agent) NewSubscription(notifier *Notifier, params *eth.EthSubscriptionR wrappedContext, cancel, false, - a.qtum, + a.kaon, + subType, + a, // Pass the reference to the agent } - switch strings.ToLower(params.Method) { + switch subType { case "logs": addSubscription(wrappedSubscription, a.logs) case "newheads": @@ -305,7 +313,7 @@ func (a *Agent) run() { a.mutex.Lock() defer a.mutex.Unlock() - a.qtum.GetDebugLogger().Log("msg", "Agent exited subscription processing thread") + a.kaon.GetDebugLogger().Log("msg", "Agent exited subscription processing thread") a.running = false }() @@ -331,7 +339,7 @@ func (a *Agent) run() { } // TODO: newPendingTransactions - a.qtum.GetDebugLogger().Log("msg", "Agent started subscription processing thread") + a.kaon.GetDebugLogger().Log("msg", "Agent started subscription processing thread") for { // infinite loop while we have subscriptions @@ -344,19 +352,19 @@ func (a *Agent) run() { transformer := a.transformer a.mutex.RUnlock() if transformer == nil { - a.qtum.GetErrorLogger().Log("msg", "Agent does not have access to eth transformer, cannot process 'newHeads' subscriptions") + a.kaon.GetErrorLogger().Log("msg", "Agent does not have access to eth transformer, cannot process 'newHeads' subscriptions") } else { - blockchainInfo, err := a.qtum.GetBlockChainInfo(a.ctx) + blockchainInfo, err := a.kaon.GetBlockChainInfo(a.ctx) if err != nil { - a.qtum.GetErrorLogger().Log("msg", "Failure getting blockchaininfo", "err", err) + a.kaon.GetErrorLogger().Log("msg", "Failure getting blockchaininfo", "err", err) } else { latestBlock := blockchainInfo.Blocks if lastBlock == 0 { // prevent sending the current head to the first client connected lastBlock = latestBlock - a.qtum.GetDebugLogger().Log("msg", "Got getblockchaininfo response for same block", "block", lastBlock) + a.kaon.GetDebugLogger().Log("msg", "Got getblockchaininfo response for same block", "block", lastBlock) } else if latestBlock > lastBlock { - a.qtum.GetDebugLogger().Log("msg", "New head detected", "block", latestBlock) + a.kaon.GetDebugLogger().Log("msg", "New head detected", "block", latestBlock) // get the latest block as an eth_getBlockByHash request params, err := json.Marshal([]interface{}{ utils.AddHexPrefix(blockchainInfo.Bestblockhash), @@ -369,13 +377,13 @@ func (a *Agent) run() { JSONRPC: "2.0", Method: "eth_getBlockByHash", Params: params, - }, nil) + }, NewEchoWithContext(a.ctx)) if jsonErr != nil { - a.qtum.GetErrorLogger().Log("msg", "Failed to eth_getBlockByHash", "hash", blockchainInfo.Bestblockhash, "err", jsonErr) + a.kaon.GetErrorLogger().Log("msg", "Failed to eth_getBlockByHash", "hash", blockchainInfo.Bestblockhash, "err", jsonErr) } else { getBlockByHashResponse, ok := result.(*eth.GetBlockByHashResponse) if !ok { - a.qtum.GetErrorLogger().Log("msg", "Failed to eth_getBlockByHash, unexpected response type", "hash", blockchainInfo.Bestblockhash) + a.kaon.GetErrorLogger().Log("msg", "Failed to eth_getBlockByHash, unexpected response type", "hash", blockchainInfo.Bestblockhash) } else { lastBlock = latestBlock // notify newHead @@ -384,7 +392,7 @@ func (a *Agent) run() { } } } else { - a.qtum.GetDebugLogger().Log("msg", "Detected same head", "block", latestBlock) + a.kaon.GetDebugLogger().Log("msg", "Detected same head", "block", latestBlock) } } } diff --git a/pkg/notifier/agent_test.go b/pkg/notifier/agent_test.go index eac40247..65278dff 100644 --- a/pkg/notifier/agent_test.go +++ b/pkg/notifier/agent_test.go @@ -10,9 +10,9 @@ import ( "time" "github.com/go-kit/kit/log" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" ) func TestAgentAddSubscriptionLogs(t *testing.T) { @@ -25,25 +25,25 @@ func TestAgentAddSubscriptionLogs(t *testing.T) { doer := internal.NewDoerMappedMock() topic1 := "d8d7ecc4800d25fa53ce0372f13a416d98907a7ef3d8d3bdd79cf4fe75529c65" - doer.AddResponse(qtum.MethodWaitForLogs, qtum.WaitForLogsResponse{ - Entries: []qtum.WaitForLogsEntry{ - internal.QtumWaitForLogsEntry(qtum.Log{ - Address: internal.QtumTransactionReceipt(nil).ContractAddress, + doer.AddResponse(kaon.MethodWaitForLogs, kaon.WaitForLogsResponse{ + Entries: []kaon.WaitForLogsEntry{ + internal.KaonWaitForLogsEntry(kaon.Log{ + Address: internal.KaonTransactionReceipt(nil).ContractAddress, Topics: []string{topic1}, Data: "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", }), }, Count: 1, - NextBlock: internal.QtumTransactionReceipt(nil).BlockNumber + 1, + NextBlock: internal.KaonTransactionReceipt(nil).BlockNumber + 1, }) doer.AddResponse( - qtum.MethodSearchLogs, - qtum.SearchLogsResponse{ - internal.QtumTransactionReceipt( - []qtum.Log{ + kaon.MethodSearchLogs, + kaon.SearchLogsResponse{ + internal.KaonTransactionReceipt( + []kaon.Log{ { - Address: internal.QtumTransactionReceipt(nil).ContractAddress, + Address: internal.KaonTransactionReceipt(nil).ContractAddress, Topics: []string{topic1}, Data: "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", }, @@ -76,7 +76,7 @@ func TestAgentAddSubscriptionLogs(t *testing.T) { id, err := agent.NewSubscription(notifier, ð.EthSubscriptionRequest{ Method: "logs", Params: ð.EthLogSubscriptionParameter{ - Address: internal.QtumTransactionReceipt(nil).ContractAddress, + Address: internal.KaonTransactionReceipt(nil).ContractAddress, Topics: []interface{}{ topic1, }, @@ -184,7 +184,7 @@ func TestAgentAddSubscriptionNewHeads(t *testing.T) { doer := internal.NewDoerMappedMock() for i := int64(1); i < 10; i++ { - doer.AddResponse(qtum.MethodGetBlockChainInfo, qtum.GetBlockChainInfoResponse{ + doer.AddResponse(kaon.MethodGetBlockChainInfo, kaon.GetBlockChainInfoResponse{ Blocks: i, Bestblockhash: "0x1", }) diff --git a/pkg/notifier/subscription.go b/pkg/notifier/subscription.go index b28b3096..5f72736d 100644 --- a/pkg/notifier/subscription.go +++ b/pkg/notifier/subscription.go @@ -11,9 +11,10 @@ import ( "sync" "time" - "github.com/qtumproject/janus/pkg/conversion" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/conversion" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/utils" ) type subscriptionInformation struct { @@ -23,7 +24,9 @@ type subscriptionInformation struct { ctx context.Context cancelFunc context.CancelFunc running bool - qtum *qtum.Qtum + kaon *kaon.Kaon + subType string + agent *Agent // Reference to the agent } func (s *subscriptionInformation) run() { @@ -31,6 +34,36 @@ func (s *subscriptionInformation) run() { return } + s.mutex.Lock() + if s.running { + s.mutex.Unlock() + return + } + + s.running = true + s.mutex.Unlock() + + defer func() { + s.mutex.Lock() + defer s.mutex.Unlock() + s.running = false + }() + + switch strings.ToLower(s.subType) { + case "logs": + s.runLogsSubscription() + case "newheads": + s.runNewHeadsSubscription() + default: + s.kaon.GetDebugLogger().Log("msg", "Unsupported subscription type", "type", s.subType) + } +} + +func (s *subscriptionInformation) runLogsSubscription() { + if s.params == nil { + return + } + if strings.ToLower(s.params.Method) != "logs" { return } @@ -54,12 +87,12 @@ func (s *subscriptionInformation) run() { nextBlock = nil translatedTopics, err := eth.TranslateTopics(s.params.Params.Topics) if err != nil { - s.qtum.GetDebugLogger().Log("msg", "Error translating logs topics", "error", err) + s.kaon.GetDebugLogger().Log("msg", "Error translating logs topics", "error", err) return } ethAddresses, err := s.params.Params.GetAddresses() if err != nil { - s.qtum.GetDebugLogger().Log("msg", "Error translating logs addresses", "error", err) + s.kaon.GetDebugLogger().Log("msg", "Error translating logs addresses", "error", err) return } stringAddresses := make([]string, len(ethAddresses)) @@ -71,25 +104,25 @@ func (s *subscriptionInformation) run() { } } - qtumTopics := qtum.NewSearchLogsTopics(translatedTopics) - req := &qtum.WaitForLogsRequest{ + kaonTopics := kaon.NewSearchLogsTopics(translatedTopics) + req := &kaon.WaitForLogsRequest{ FromBlock: nextBlock, ToBlock: nil, - Filter: qtum.WaitForLogsFilter{ + Filter: kaon.WaitForLogsFilter{ Addresses: &stringAddresses, - Topics: &qtumTopics, + Topics: &kaonTopics, }, } - if s.qtum.Chain() == qtum.ChainRegTest || s.qtum.Chain() == qtum.ChainTest { + if s.kaon.Chain() == kaon.ChainRegTest || s.kaon.Chain() == kaon.ChainTest { req.MinimumConfirmations = 0 } - // this throttles QTUM api calls if waitforlogs is returning very quickly a lot + // this throttles Kaon api calls if waitforlogs is returning very quickly a lot limitToXApiCalls := 5 inYSeconds := 10 * time.Second - // if a QTUM API call returns quicker than this, we will wait until this time is reached - // this prevents spamming the QTUM node too much + // if a Kaon API call returns quicker than this, we will wait until this time is reached + // this prevents spamming the Kaon node too much minimumTimeBetweenCalls := 100 * time.Millisecond rolling := newRollingLimit(limitToXApiCalls) @@ -106,7 +139,7 @@ func (s *subscriptionInformation) run() { // when proving this as a service, that can add up if tens of thousands are using the service // we want to put an upper limit on ram usage for an ip/connection // we could also put an absolute upper limit on ram usage for this feature - // TODO: Deal with RAM usage here when Janus gets large enough + // TODO: Deal with RAM usage here when eth-rpc-gate gets large enough // some kind of FIFO hashmap? sentHashes := make(map[string]bool) @@ -115,25 +148,25 @@ func (s *subscriptionInformation) run() { req.FromBlock = nextBlock timeBeforeCall := time.Now() rolling.Push(&timeBeforeCall) - resp, err := s.qtum.WaitForLogs(s.ctx, req) + resp, err := s.kaon.WaitForLogs(s.ctx, req) timeAfterCall := time.Now() if err == nil { nextBlock = int(resp.NextBlock) - reqSearchLogs := qtum.SearchLogsRequest{ + reqSearchLogs := kaon.SearchLogsRequest{ FromBlock: big.NewInt(int64(resp.NextBlock - 1)), ToBlock: big.NewInt(int64(resp.NextBlock - 1)), Addresses: *req.Filter.Addresses, Topics: *req.Filter.Topics, } - receiptsSearchLogs, err := s.qtum.SearchLogs(s.ctx, &reqSearchLogs) + receiptsSearchLogs, err := s.kaon.SearchLogs(s.ctx, &reqSearchLogs) if err != nil { - s.qtum.GetErrorLogger().Log("msg", "Error calling searchLogs", "subscriptionId", s.id, "error", err) + s.kaon.GetErrorLogger().Log("msg", "Error calling searchLogs", "subscriptionId", s.id, "error", err) return } - for _, qtumLog := range receiptsSearchLogs { - qtumLogs := qtumLog.Log - logs := conversion.FilterQtumLogs(stringAddresses, qtumTopics, qtumLogs) - ethLogs := conversion.ExtractETHLogsFromTransactionReceipt(qtumLog, logs) + for _, kaonLog := range receiptsSearchLogs { + kaonLogs := kaonLog.Log + logs := conversion.FilterKaonLogs(stringAddresses, kaonTopics, kaonLogs) + ethLogs := conversion.ExtractETHLogsFromTransactionReceipt(kaonLog, logs) for _, ethLog := range ethLogs { subscription := ð.EthSubscription{ SubscriptionID: s.Subscription.id, @@ -142,10 +175,10 @@ func (s *subscriptionInformation) run() { hash := computeHash(subscription) if _, ok := sentHashes[hash]; !ok { sentHashes[hash] = true - s.qtum.GetDebugLogger().Log("subscriptionId", s.id, "msg", "notifying of logs") + s.kaon.GetDebugLogger().Log("subscriptionId", s.id, "msg", "notifying of logs") jsonRpcNotification, err := eth.NewJSONRPCNotification("eth_subscription", subscription) if err != nil { - s.qtum.GetErrorLogger().Log("subscriptionId", s.id, "err", err) + s.kaon.GetErrorLogger().Log("subscriptionId", s.id, "err", err) return } s.Send(jsonRpcNotification) @@ -162,7 +195,7 @@ func (s *subscriptionInformation) run() { } } else { // error occurred - s.qtum.GetDebugLogger().Log("subscriptionId", s.id, "err", err) + s.kaon.GetDebugLogger().Log("subscriptionId", s.id, "err", err) failures = failures + 1 } @@ -171,7 +204,7 @@ func (s *subscriptionInformation) run() { select { case <-done: // err is wrapped so we can't detect (err == context.Cancelled) - s.qtum.GetDebugLogger().Log("subscriptionId", s.id, "msg", "context closed, dropping subscription") + s.kaon.GetDebugLogger().Log("subscriptionId", s.id, "msg", "context closed, dropping subscription") return default: } @@ -185,7 +218,7 @@ func (s *subscriptionInformation) run() { } if backoffTime > 0 { - s.qtum.GetDebugLogger().Log("subscriptionId", s.id, "msg", fmt.Sprintf("backing off for %d miliseconds", backoffTime/time.Millisecond)) + s.kaon.GetDebugLogger().Log("subscriptionId", s.id, "msg", fmt.Sprintf("backing off for %d miliseconds", backoffTime/time.Millisecond)) } select { @@ -197,6 +230,93 @@ func (s *subscriptionInformation) run() { } } +func (s *subscriptionInformation) runNewHeadsSubscription() { + lastBlock := int64(0) + + newHeadsInterval := 10 * time.Second // adjust the interval as needed + + for { + select { + case <-time.After(newHeadsInterval): + // Continue to next iteration + case <-s.ctx.Done(): + return + } + + // Safely obtain the transformer, similar to how it's done in the Agent struct + var transformer Transformer + s.mutex.RLock() + transformer = s.agent.transformer + s.mutex.RUnlock() + + if transformer == nil { + s.kaon.GetErrorLogger().Log("msg", "No transformer available, cannot process 'newHeads' subscriptions") + continue + } + + blockchainInfo, err := s.kaon.GetBlockChainInfo(s.ctx) + if err != nil { + s.kaon.GetErrorLogger().Log("msg", "Failure getting blockchaininfo", "err", err) + continue + } + + latestBlock := blockchainInfo.Blocks + if lastBlock == 0 { + lastBlock = latestBlock + s.kaon.GetDebugLogger().Log("msg", "Initial block detected", "block", lastBlock) + continue + } + + if latestBlock > lastBlock { + s.kaon.GetDebugLogger().Log("msg", "New head detected", "block", latestBlock) + + params, err := json.Marshal([]interface{}{ + utils.AddHexPrefix(blockchainInfo.Bestblockhash), + false, + }) + if err != nil { + s.kaon.GetErrorLogger().Log("msg", "Failed to serialize eth_getBlockByHash request parameters", "err", err) + continue + } + + result, jsonErr := transformer.Transform(ð.JSONRPCRequest{ + JSONRPC: "2.0", + Method: "eth_getBlockByHash", + Params: params, + }, NewEchoWithContext(s.ctx)) + if jsonErr != nil { + s.kaon.GetErrorLogger().Log("msg", "Failed to eth_getBlockByHash", "hash", blockchainInfo.Bestblockhash, "err", jsonErr) + continue + } + + getBlockByHashResponse, ok := result.(*eth.GetBlockByHashResponse) + if !ok { + s.kaon.GetErrorLogger().Log("msg", "Unexpected response type from eth_getBlockByHash", "hash", blockchainInfo.Bestblockhash) + continue + } + + lastBlock = latestBlock + + // Notify newHead + newHeadResponse := eth.NewEthSubscriptionNewHeadResponse(getBlockByHashResponse) + + subscription := ð.EthSubscription{ + SubscriptionID: s.Subscription.id, + Result: newHeadResponse, + } + jsonRpcNotification, err := eth.NewJSONRPCNotification("eth_subscription", subscription) + if err != nil { + s.kaon.GetErrorLogger().Log("msg", "Failed to create JSONRPC notification", "err", err) + continue + } + + s.Send(jsonRpcNotification) + } else { + s.kaon.GetDebugLogger().Log("msg", "No new head detected", "block", latestBlock) + } + } +} + // Compute hash for the json serialization of the passed in argument func computeHash(value interface{}) string { b, err := json.Marshal(value) diff --git a/pkg/params/version.go b/pkg/params/version.go index 33298819..680d262e 100644 --- a/pkg/params/version.go +++ b/pkg/params/version.go @@ -6,8 +6,8 @@ const ( unstable = "unstable" stable = "stable" VersionMajor = 0 // Major version component of the current release - VersionMinor = 4 // Minor version component of the current release - VersionPatch = 2 // Patch version component of the current release + VersionMinor = 3 // Minor version component of the current release + VersionPatch = 1 // Patch version component of the current release VersionMeta = unstable // Version metadata to append to the version string ) diff --git a/pkg/qtum/btcasm_test.go b/pkg/qtum/btcasm_test.go deleted file mode 100644 index cb9960f3..00000000 --- a/pkg/qtum/btcasm_test.go +++ /dev/null @@ -1,117 +0,0 @@ -package qtum - -import ( - "encoding/json" - "reflect" - "strings" - "testing" -) - -func TestParseCallSenderASM(t *testing.T) { - // source data: https://qtum.info/tx/0425fa39feed4cd6c93998159901095c147f8b0043823067dc1d25dabf950ac9 - // hex: "01011493594441cb5de8b497ad8467d55412c2a0ef36594c6b6a4730440220396b30b7a2f2af482e585473b7575dd2f989f3f3d7cdee55fa34e93f23d5254d022055326cdcab38c58dc3e65c458bfb656cca8340f59534c00ad98b4d4d3303f459012103379c39b6fb2c705db608f98a8fc064f94c66faf894996ca88595487f9ef04a6ec401040390d0030128043d666e8b140000000000000000000000000000000000000086c2" - samStr := "01 93594441cb5de8b497ad8467d55412c2a0ef3659 6a4730440220396b30b7a2f2af482e585473b7575dd2f989f3f3d7cdee55fa34e93f23d5254d022055326cdcab38c58dc3e65c458bfb656cca8340f59534c00ad98b4d4d3303f459012103379c39b6fb2c705db608f98a8fc064f94c66faf894996ca88595487f9ef04a6e OP_SENDER 04 90d003 28 3d666e8b 0000000000000000000000000000000000000086 OP_CALL" - got, err := ParseCallSenderASM(strings.Split(samStr, " ")) - if err != nil { - t.Error(err) - } - want := &ContractInvokeInfo{ - From: "93594441cb5de8b497ad8467d55412c2a0ef3659", - GasLimit: "3d090", - GasPrice: "28", - CallData: "3d666e8b", - To: "0000000000000000000000000000000000000086", - } - if !reflect.DeepEqual(got, want) { - t.Errorf( - "parse transaction call sam error\ninput: %s\nwant: %s\ngot: %s", - samStr, - string(mustMarshalIndent(want, "", " ")), - string(mustMarshalIndent(got, "", " ")), - ) - } -} - -func TestParseParseCreateSenderASM(t *testing.T) { - samStr := "1 7926223070547d2d15b2ef5e7383e541c338ffe9 6a473044022067ca66b0308ae16aeca7a205ce0490b44a61feebe5632710b52aabde197f9e4802200e8beec61a58dbe1279a9cdb68983080052ae7b9997bc863b7c5623e4cb55fdb01210299d391f528b9edd07284c7e23df8415232a8ce41531cf460a390ce32b4efd112 OP_SENDER 4 b79166 64 6060604052341561000f57600080fd5b60008054600160a060020a033316600160a060020a03199091161790556101de8061003b6000396000f300606060405263ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630900f010811461005d578063445df0ac1461007e5780638da5cb5b146100a3578063fdacd576146100d257600080fd5b341561006857600080fd5b61007c600160a060020a03600435166100e8565b005b341561008957600080fd5b61009161017d565b60405190815260200160405180910390f35b34156100ae57600080fd5b6100b6610183565b604051600160a060020a03909116815260200160405180910390f35b34156100dd57600080fd5b61007c600435610192565b6000805433600160a060020a03908116911614156101795781905080600160a060020a031663fdacd5766001546040517c010000000000000000000000000000000000000000000000000000000063ffffffff84160281526004810191909152602401600060405180830381600087803b151561016457600080fd5b6102c65a03f1151561017557600080fd5b5050505b5050565b60015481565b600054600160a060020a031681565b60005433600160a060020a03908116911614156101af5760018190555b505600a165627a7a72305820b6a912c5b5115d1a5412235282372dc4314f325bac71ee6c8bd18f658d7ed1ad0029 OP_CREATE" - got, err := ParseCreateSenderASM(strings.Split(samStr, " ")) - if err != nil { - t.Error(err) - } - want := &ContractInvokeInfo{ - From: "7926223070547d2d15b2ef5e7383e541c338ffe9", - GasLimit: "6691b7", - GasPrice: "64", - CallData: "6060604052341561000f57600080fd5b60008054600160a060020a033316600160a060020a03199091161790556101de8061003b6000396000f300606060405263ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416630900f010811461005d578063445df0ac1461007e5780638da5cb5b146100a3578063fdacd576146100d257600080fd5b341561006857600080fd5b61007c600160a060020a03600435166100e8565b005b341561008957600080fd5b61009161017d565b60405190815260200160405180910390f35b34156100ae57600080fd5b6100b6610183565b604051600160a060020a03909116815260200160405180910390f35b34156100dd57600080fd5b61007c600435610192565b6000805433600160a060020a03908116911614156101795781905080600160a060020a031663fdacd5766001546040517c010000000000000000000000000000000000000000000000000000000063ffffffff84160281526004810191909152602401600060405180830381600087803b151561016457600080fd5b6102c65a03f1151561017557600080fd5b5050505b5050565b60015481565b600054600160a060020a031681565b60005433600160a060020a03908116911614156101af5760018190555b505600a165627a7a72305820b6a912c5b5115d1a5412235282372dc4314f325bac71ee6c8bd18f658d7ed1ad0029", - To: "", - } - if !reflect.DeepEqual(got, want) { - t.Errorf( - "parse transaction call sam error\ninput: %s\nwant: %s\ngot: %s", - samStr, - string(mustMarshalIndent(want, "", " ")), - string(mustMarshalIndent(got, "", " ")), - ) - } -} - -func TestParseCreateASM(t *testing.T) { - // source data: https://qtum.info/tx/9b11819d254cc1877353cf02b587308ccf2e79c61d9f5ca726d744fcea2fd37c - samStr := "04 a02526 28 60806040526b033b2e3c9fd0803ce80000006006553480156200002157600080fd5b506040518060400160405280600281526020017f51690000000000000000000000000000000000000000000000000000000000008152506040518060400160405280600281526020017f51490000000000000000000000000000000000000000000000000000000000008152508160039080519060200190620000a692919062000364565b508060049080519060200190620000bf92919062000364565b506012600560006101000a81548160ff021916908360ff1602179055505050620000f233600654620000f860201b60201c565b6200040a565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156200019c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f45524332303a206d696e7420746f20746865207a65726f20616464726573730081525060200191505060405180910390fd5b620001b060008383620002d660201b60201c565b620001cc81600254620002db60201b620009a01790919060201c565b6002819055506200022a816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054620002db60201b620009a01790919060201c565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b505050565b6000808284019050838110156200035a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620003a757805160ff1916838001178555620003d8565b82800160010185558215620003d8579182015b82811115620003d7578251825591602001919060010190620003ba565b5b509050620003e79190620003eb565b5090565b5b8082111562000406576000816000905550600101620003ec565b5090565b6110e4806200041a6000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c80633950935111610071578063395093511461025857806370a08231146102bc57806395d89b4114610314578063a457c2d714610397578063a9059cbb146103fb578063dd62ed3e1461045f576100a9565b806306fdde03146100ae578063095ea7b31461013157806318160ddd1461019557806323b872dd146101b3578063313ce56714610237575b600080fd5b6100b66104d7565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100f65780820151818401526020810190506100db565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61017d6004803603604081101561014757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610579565b60405180821515815260200191505060405180910390f35b61019d610597565b6040518082815260200191505060405180910390f35b61021f600480360360608110156101c957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506105a1565b60405180821515815260200191505060405180910390f35b61023f61067a565b604051808260ff16815260200191505060405180910390f35b6102a46004803603604081101561026e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610691565b60405180821515815260200191505060405180910390f35b6102fe600480360360208110156102d257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610744565b6040518082815260200191505060405180910390f35b61031c61078c565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561035c578082015181840152602081019050610341565b50505050905090810190601f1680156103895780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103e3600480360360408110156103ad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061082e565b60405180821515815260200191505060405180910390f35b6104476004803603604081101561041157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506108fb565b60405180821515815260200191505060405180910390f35b6104c16004803603604081101561047557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610919565b6040518082815260200191505060405180910390f35b606060038054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561056f5780601f106105445761010080835404028352916020019161056f565b820191906000526020600020905b81548152906001019060200180831161055257829003601f168201915b5050505050905090565b600061058d610586610a28565b8484610a30565b6001905092915050565b6000600254905090565b60006105ae848484610c27565b61066f846105ba610a28565b61066a8560405180606001604052806028815260200161101960289139600160008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000610620610a28565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610ee89092919063ffffffff16565b610a30565b600190509392505050565b6000600560009054906101000a900460ff16905090565b600061073a61069e610a28565b8461073585600160006106af610a28565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546109a090919063ffffffff16565b610a30565b6001905092915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b606060048054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156108245780601f106107f957610100808354040283529160200191610824565b820191906000526020600020905b81548152906001019060200180831161080757829003601f168201915b5050505050905090565b60006108f161083b610a28565b846108ec8560405180606001604052806025815260200161108a6025913960016000610865610a28565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610ee89092919063ffffffff16565b610a30565b6001905092915050565b600061090f610908610a28565b8484610c27565b6001905092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600080828401905083811015610a1e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610ab6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001806110666024913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610b3c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180610fd16022913960400191505060405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040518082815260200191505060405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610cad576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001806110416025913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610d33576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180610fae6023913960400191505060405180910390fd5b610d3e838383610fa8565b610da981604051806060016040528060268152602001610ff3602691396000808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610ee89092919063ffffffff16565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610e3c816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546109a090919063ffffffff16565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b6000838311158290610f95576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610f5a578082015181840152602081019050610f3f565b50505050905090810190601f168015610f875780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b50505056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa2646970667358221220986b9c5663d82a38eadfeeac1a6b5cdff6a7eca105c0e4b8504b0b2e87e4798a64736f6c634300060c0033 OP_CREATE" - byteCode := "60806040526b033b2e3c9fd0803ce80000006006553480156200002157600080fd5b506040518060400160405280600281526020017f51690000000000000000000000000000000000000000000000000000000000008152506040518060400160405280600281526020017f51490000000000000000000000000000000000000000000000000000000000008152508160039080519060200190620000a692919062000364565b508060049080519060200190620000bf92919062000364565b506012600560006101000a81548160ff021916908360ff1602179055505050620000f233600654620000f860201b60201c565b6200040a565b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1614156200019c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601f8152602001807f45524332303a206d696e7420746f20746865207a65726f20616464726573730081525060200191505060405180910390fd5b620001b060008383620002d660201b60201c565b620001cc81600254620002db60201b620009a01790919060201c565b6002819055506200022a816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054620002db60201b620009a01790919060201c565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a35050565b505050565b6000808284019050838110156200035a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10620003a757805160ff1916838001178555620003d8565b82800160010185558215620003d8579182015b82811115620003d7578251825591602001919060010190620003ba565b5b509050620003e79190620003eb565b5090565b5b8082111562000406576000816000905550600101620003ec565b5090565b6110e4806200041a6000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c80633950935111610071578063395093511461025857806370a08231146102bc57806395d89b4114610314578063a457c2d714610397578063a9059cbb146103fb578063dd62ed3e1461045f576100a9565b806306fdde03146100ae578063095ea7b31461013157806318160ddd1461019557806323b872dd146101b3578063313ce56714610237575b600080fd5b6100b66104d7565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100f65780820151818401526020810190506100db565b50505050905090810190601f1680156101235780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61017d6004803603604081101561014757600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610579565b60405180821515815260200191505060405180910390f35b61019d610597565b6040518082815260200191505060405180910390f35b61021f600480360360608110156101c957600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506105a1565b60405180821515815260200191505060405180910390f35b61023f61067a565b604051808260ff16815260200191505060405180910390f35b6102a46004803603604081101561026e57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610691565b60405180821515815260200191505060405180910390f35b6102fe600480360360208110156102d257600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610744565b6040518082815260200191505060405180910390f35b61031c61078c565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561035c578082015181840152602081019050610341565b50505050905090810190601f1680156103895780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6103e3600480360360408110156103ad57600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061082e565b60405180821515815260200191505060405180910390f35b6104476004803603604081101561041157600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506108fb565b60405180821515815260200191505060405180910390f35b6104c16004803603604081101561047557600080fd5b81019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610919565b6040518082815260200191505060405180910390f35b606060038054600181600116156101000203166002900480601f01602080910402602001604051908101604052809291908181526020018280546001816001161561010002031660029004801561056f5780601f106105445761010080835404028352916020019161056f565b820191906000526020600020905b81548152906001019060200180831161055257829003601f168201915b5050505050905090565b600061058d610586610a28565b8484610a30565b6001905092915050565b6000600254905090565b60006105ae848484610c27565b61066f846105ba610a28565b61066a8560405180606001604052806028815260200161101960289139600160008b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000610620610a28565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610ee89092919063ffffffff16565b610a30565b600190509392505050565b6000600560009054906101000a900460ff16905090565b600061073a61069e610a28565b8461073585600160006106af610a28565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546109a090919063ffffffff16565b610a30565b6001905092915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b606060048054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156108245780601f106107f957610100808354040283529160200191610824565b820191906000526020600020905b81548152906001019060200180831161080757829003601f168201915b5050505050905090565b60006108f161083b610a28565b846108ec8560405180606001604052806025815260200161108a6025913960016000610865610a28565b73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008a73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610ee89092919063ffffffff16565b610a30565b6001905092915050565b600061090f610908610a28565b8484610c27565b6001905092915050565b6000600160008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054905092915050565b600080828401905083811015610a1e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040180806020018281038252601b8152602001807f536166654d6174683a206164646974696f6e206f766572666c6f77000000000081525060200191505060405180910390fd5b8091505092915050565b600033905090565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610ab6576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260248152602001806110666024913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610b3c576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526022815260200180610fd16022913960400191505060405180910390fd5b80600160008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040518082815260200191505060405180910390a3505050565b600073ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff161415610cad576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260258152602001806110416025913960400191505060405180910390fd5b600073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161415610d33576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180610fae6023913960400191505060405180910390fd5b610d3e838383610fa8565b610da981604051806060016040528060268152602001610ff3602691396000808773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054610ee89092919063ffffffff16565b6000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610e3c816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020546109a090919063ffffffff16565b6000808473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b6000838311158290610f95576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825283818151815260200191508051906020019080838360005b83811015610f5a578082015181840152602081019050610f3f565b50505050905090810190601f168015610f875780820380516001836020036101000a031916815260200191505b509250505060405180910390fd5b5060008385039050809150509392505050565b50505056fe45524332303a207472616e7366657220746f20746865207a65726f206164647265737345524332303a20617070726f766520746f20746865207a65726f206164647265737345524332303a207472616e7366657220616d6f756e7420657863656564732062616c616e636545524332303a207472616e7366657220616d6f756e74206578636565647320616c6c6f77616e636545524332303a207472616e736665722066726f6d20746865207a65726f206164647265737345524332303a20617070726f76652066726f6d20746865207a65726f206164647265737345524332303a2064656372656173656420616c6c6f77616e63652062656c6f77207a65726fa2646970667358221220986b9c5663d82a38eadfeeac1a6b5cdff6a7eca105c0e4b8504b0b2e87e4798a64736f6c634300060c0033" - got, err := ParseCreateASM(strings.Split(samStr, " ")) - if err != nil { - t.Error(err) - } - want := &ContractInvokeInfo{ - GasLimit: "2625a0", - GasPrice: "28", - CallData: byteCode, - To: "", - } - if !reflect.DeepEqual(got, want) { - t.Errorf( - "parse transaction call sam error\ninput: %s\nwant: %s\ngot: %s", - samStr, - string(mustMarshalIndent(want, "", " ")), - string(mustMarshalIndent(got, "", " ")), - ) - } -} - -func TestParseCallASM(t *testing.T) { - // source data: https://qtum.info/tx/d20c5c31536e60decf175caf2cbfba980c3678c0f4b201c9b9fa1440102e6451 - // hex: 540390d003012844095ea7b300000000000000000000000025495b3a87d82e9d7a71b341addfc0d7bb3475c7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1454fefdb5b31164f66ddb68becd7bdd864cacd65bc2 - byteCode := "095ea7b300000000000000000000000025495b3a87d82e9d7a71b341addfc0d7bb3475c7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff" - contractAddr := "54fefdb5b31164f66ddb68becd7bdd864cacd65b" - - samStr := "4 90d003 28 095ea7b300000000000000000000000025495b3a87d82e9d7a71b341addfc0d7bb3475c7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 54fefdb5b31164f66ddb68becd7bdd864cacd65b OP_CALL" - - got, err := ParseCallASM(strings.Split(samStr, " ")) - if err != nil { - t.Error(err) - } - want := &ContractInvokeInfo{ - From: "", - GasLimit: "3d090", - GasPrice: "28", - CallData: byteCode, - To: contractAddr, - } - if !reflect.DeepEqual(got, want) { - t.Errorf( - "parse transaction call sam error\ninput: %s\nwant: %s\ngot: %s", - samStr, - string(mustMarshalIndent(want, "", " ")), - string(mustMarshalIndent(got, "", " ")), - ) - } -} - -func mustMarshalIndent(v interface{}, prefix, indent string) []byte { - res, err := json.MarshalIndent(v, prefix, indent) - if err != nil { - panic(err) - } - return res -} diff --git a/pkg/qtum/error_handlers.go b/pkg/qtum/error_handlers.go deleted file mode 100644 index 6408f8a4..00000000 --- a/pkg/qtum/error_handlers.go +++ /dev/null @@ -1,190 +0,0 @@ -package qtum - -import ( - "context" - "errors" - "sync" - "time" -) - -var errorHandlers map[error]errorHandler -var ErrErrorHandlerFailed = errors.New("failed to recover from error") -var ErrErrorHandlerRunning = errors.New("error recovery routine already running") - -type errorHandler func(ctx context.Context, qtum *Qtum, state *errorState, method *Method) error - -func newErrorState() *errorState { - return &errorState{ - state: make(map[string]interface{}), - } -} - -type errorState struct { - mutex sync.RWMutex - state map[string]interface{} -} - -func (e *errorState) Get(variable string) interface{} { - e.mutex.RLock() - defer e.mutex.RUnlock() - - return e.state[variable] -} - -func (e *errorState) Put(variable string, value interface{}) { - e.mutex.Lock() - defer e.mutex.Unlock() - - e.state[variable] = value -} - -func errWalletNotFoundHandler(ctx context.Context, qtum *Qtum, state *errorState, method *Method) error { - if state.Get("createwallet") != nil { - qtum.GetLogger().Log("msg", "createwallet call failed") - return ErrErrorHandlerFailed - } - - if state.Get("createwalletRunning") != nil { - qtum.GetLogger().Log("msg", "Wallet error handler already running") - return ErrErrorHandlerRunning - } - - state.Put("createwalletRunning", true) - defer func() { - state.Put("createwalletRunning", nil) - }() - - listWalletsReq := ListWalletsRequest([]string{}) - wallets, err := method.ListWallets(ctx, &listWalletsReq) - - if err != nil { - qtum.GetLogger().Log("msg", "Error listing wallets", "err", err) - return err - } - - if len(*wallets) == 1 { - // should be fixed, another node probably fixed the wallets, if it becomes a blocking problem the healthcheck will pick it up - qtum.GetLogger().Log("msg", "Only one wallet loaded in Qtumd, will not try to fix wallet issues, another node might have already fixed things") - return nil - } - - if len(*wallets) == 0 { - err := loadWallets(ctx, qtum, state, method) - if err != nil { - qtum.GetLogger().Log("msg", "Error loading wallets", "err", err) - return err - } - } else { - // multiple wallets loaded, unload them all - for _, wallet := range *wallets { - unloadWalletReq := UnloadWalletRequest([]string{wallet}) - _, err := method.UnloadWallet(ctx, &unloadWalletReq) - if err != nil { - qtum.GetLogger().Log("msg", "Error unloading wallet", "wallet", wallet, "err", err) - } - } - - wallets, err = method.ListWallets(ctx, &listWalletsReq) - - if err != nil { - qtum.GetLogger().Log("msg", "Error listing wallets after unloading all", "err", err) - return err - } - - if len(*wallets) == 1 { - qtum.GetLogger().Log("msg", "Unloaded all wallets but there is one loaded still, assuming another node fixed things") - return nil - } else if len(*wallets) != 0 { - qtum.GetLogger().Log("msg", "Failed to unload wallets, multiple still are loaded") - return errors.New("Failed to unload all wallets") - } - - err := loadWallets(ctx, qtum, state, method) - if err != nil { - qtum.GetLogger().Log("msg", "Error loading wallets after unloading all", "err", err) - return err - } - } - - return nil -} - -func loadWallets(ctx context.Context, qtum *Qtum, state *errorState, method *Method) error { - // no wallets loaded, we need to listwalletdir and load them each until requests go through - // some wallets might have a password so we need to take that into account - listWalletDirReq := ListWalletDirRequest([]string{}) - listedWallets, err := method.ListWalletDir(ctx, &listWalletDirReq) - - if err != nil { - return err - } - - if len(listedWallets.Wallets) == 0 { - createWalletReq := CreateWalletRequest([]string{"wallet"}) - _, err = method.CreateWallet(ctx, &createWalletReq) - - if err == nil { - state.Put("createwallet", true) - go func() { - select { - case <-time.After(1 * time.Minute): - // expire after a little bit - in case the qtum node changes - state.Put("createwallet", false) - /* - case <-ctx.Done(): - return - */ - } - }() - } - } - - loadWallet := state.Get("loadwallet") - loadWalletIndex := -1 - if loadWallet != nil { - loadWalletIndex = loadWallet.(int) - } - - if loadWalletIndex > len(listedWallets.Wallets) { - loadWalletIndex = -1 - } - - qtum.GetLogger().Log("msg", "loadwallet", "index", loadWalletIndex, "available", len(listedWallets.Wallets)) - - for index, wallet := range listedWallets.Wallets { - if loadWalletIndex > index { - qtum.GetLogger().Log("msg", "continue") - continue - } - - loadWalletReq := LoadWalletRequest([]string{wallet.Name}) - _, err := method.LoadWallet(ctx, &loadWalletReq) - if err == nil { - qtum.GetLogger().Log("msg", "break") - break - } - - state.Put("loadwallet", index) - - go func() { - time.Sleep(30 * time.Second) - loadWallet := state.Get("loadwallet") - if loadWallet != nil { - loadWalletIndex := loadWallet.(int) - if loadWalletIndex == index { - state.Put("loadwallet", nil) - } - } - }() - - break - } - - return nil -} - -func init() { - errorHandlers = make(map[error]errorHandler) - errorHandlers[ErrWalletNotFound] = errWalletNotFoundHandler - errorHandlers[ErrWalletNotSpecified] = errWalletNotFoundHandler -} diff --git a/pkg/server/handler.go b/pkg/server/handler.go index ca29f691..f5ea3e97 100644 --- a/pkg/server/handler.go +++ b/pkg/server/handler.go @@ -8,11 +8,11 @@ import ( "sync" "time" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/notifier" "github.com/labstack/echo" "github.com/pkg/errors" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/notifier" - "github.com/qtumproject/janus/pkg/qtum" "github.com/gorilla/websocket" ) @@ -49,7 +49,7 @@ func httpHandler(c echo.Context) error { defer cc.ethAnalytics.Failure() } if err.Error() == nil { - cc.GetErrorLogger().Log("err", err.Error()) + cc.GetErrorLogger().Log("err", err.Message()) return cc.JSONRPCError(err) } @@ -57,7 +57,7 @@ func httpHandler(c echo.Context) error { } // Allow transformer to return an explicit JSON error - if jerr, isJSONErr := result.(eth.JSONRPCError); isJSONErr { + if jerr, isJSONErr := result.(*eth.JSONRPCError); isJSONErr { if cc.ethAnalytics != nil { defer cc.ethAnalytics.Failure() } @@ -246,7 +246,7 @@ func getRpcResponses(c echo.Context, cc *myCtx, rpcReqs []eth.JSONRPCRequest) ([ } // Allow transformer to return an explicit JSON error - if jerr, isJSONErr := response.(eth.JSONRPCError); isJSONErr { + if jerr, isJSONErr := response.(*eth.JSONRPCError); isJSONErr { response = cc.GetJSONRPCError(jerr) } else { var err error @@ -362,8 +362,8 @@ func websocketHandler(c echo.Context) error { notifier.ResponseSent() if cc.IsDebugEnabled() { - reqBody, err := qtum.ReformatJSON(req) - resBody, err := qtum.ReformatJSON(responseBytes) + reqBody, err := kaon.ReformatJSON(req) + resBody, err := kaon.ReformatJSON(responseBytes) if err == nil { cc.GetDebugLogger().Log("msg", "ETH WEBSOCKET RPC") fmt.Fprintf(cc.GetLogWriter(), "=> ETH request\n%s\n", reqBody) diff --git a/pkg/server/health.go b/pkg/server/health.go index 080f549b..058fee14 100644 --- a/pkg/server/health.go +++ b/pkg/server/health.go @@ -4,52 +4,52 @@ import ( "fmt" "time" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" "github.com/pkg/errors" - "github.com/qtumproject/janus/pkg/qtum" ) -var ErrNoQtumConnections = errors.New("qtumd has no connections") -var ErrCannotGetConnectedChain = errors.New("Cannot detect chain qtumd is connected to") +var ErrNoKaonConnections = errors.New("kaond has no connections") +var ErrCannotGetConnectedChain = errors.New("Cannot detect chain kaond is connected to") var ErrBlockSyncingSeemsStalled = errors.New("Block syncing seems stalled") var ErrLostLotsOfBlocks = errors.New("Lost a lot of blocks, expected block height to be higher") var ErrLostFewBlocks = errors.New("Lost a few blocks, expected block height to be higher") -func (s *Server) testConnectionToQtumd() error { - networkInfo, err := s.qtumRPCClient.GetNetworkInfo(s.qtumRPCClient.GetContext()) +func (s *Server) testConnectionToKaond() error { + networkInfo, err := s.kaonRPCClient.GetNetworkInfo(s.kaonRPCClient.GetContext()) if err == nil { - // chain can theoretically block forever if qtumd isn't up + // chain can theoretically block forever if kaond isn't up // but then GetNetworkInfo would be erroring chainChan := make(chan string) getChainTimeout := time.NewTimer(10 * time.Second) go func(ch chan string) { - chain := s.qtumRPCClient.Chain() + chain := s.kaonRPCClient.Chain() chainChan <- chain }(chainChan) select { case chain := <-chainChan: - if chain == qtum.ChainRegTest { + if chain == kaon.ChainRegTest { // ignore how many connections there are return nil } if networkInfo.Connections == 0 { - s.logger.Log("liveness", "Qtumd has no network connections") - return ErrNoQtumConnections + s.logger.Log("liveness", "kaond has no network connections") + return ErrNoKaonConnections } break case <-getChainTimeout.C: - s.logger.Log("liveness", "Qtumd getnetworkinfo request timed out") + s.logger.Log("liveness", "kaond getnetworkinfo request timed out") return ErrCannotGetConnectedChain } } else { - s.logger.Log("liveness", "Qtumd getnetworkinfo errored", "err", err) + s.logger.Log("liveness", "kaond getnetworkinfo errored", "err", err) } return err } func (s *Server) testLogEvents() error { - _, err := s.qtumRPCClient.GetTransactionReceipt(s.qtumRPCClient.GetContext(), "0000000000000000000000000000000000000000000000000000000000000000") - if err == qtum.ErrInternalError { + _, err := s.kaonRPCClient.GetTransactionReceipt(s.kaonRPCClient.GetContext(), "9d37c33f92231cfc1a099029543f54e5996baaf7235e79dfd2e72c7bbeb96683") + if err == kaon.ErrInternalError { s.logger.Log("liveness", "-logevents might not be enabled") return errors.Wrap(err, "-logevents might not be enabled") } @@ -80,7 +80,7 @@ func (s *Server) testBlocksSyncing() error { } defer s.blocksMutex.Unlock() - blockChainInfo, err := s.qtumRPCClient.GetBlockChainInfo(s.qtumRPCClient.GetContext()) + blockChainInfo, err := s.kaonRPCClient.GetBlockChainInfo(s.kaonRPCClient.GetContext()) if err != nil { s.logger.Log("liveness", "getblockchainfo request failed", "err", err) return err @@ -106,7 +106,7 @@ func (s *Server) testBlocksSyncing() error { s.lastBlockStatus = ErrLostLotsOfBlocks } else { // lost a few blocks - // could be qtumd nodes out of sync behind a load balancer + // could be kaond nodes out of sync behind a load balancer nextBlockCheckTime = time.Now().Add(10 * time.Second) s.nextBlockCheck = &nextBlockCheckTime s.logger.Log("liveness", "Lost a few blocks") @@ -123,19 +123,19 @@ func (s *Server) testBlocksSyncing() error { return s.lastBlockStatus } -func (s *Server) testQtumdErrorRate() error { +func (s *Server) testKaondErrorRate() error { minimumSuccessRate := float32(*s.healthCheckPercent / 100) - qtumSuccessRate := s.qtumRequestAnalytics.GetSuccessRate() + kaonSuccessRate := s.kaonRequestAnalytics.GetSuccessRate() - if qtumSuccessRate < minimumSuccessRate { - s.logger.Log("liveness", "qtumd request success rate is low", "rate", qtumSuccessRate) - return errors.New(fmt.Sprintf("qtumd request success rate is %f<%f", qtumSuccessRate, minimumSuccessRate)) + if kaonSuccessRate < minimumSuccessRate { + s.logger.Log("liveness", "kaond request success rate is low", "rate", kaonSuccessRate) + return errors.New(fmt.Sprintf("kaond request success rate is %f<%f", kaonSuccessRate, minimumSuccessRate)) } else { return nil } } -func (s *Server) testJanusErrorRate() error { +func (s *Server) testEthRPCGateErrorRate() error { minimumSuccessRate := float32(*s.healthCheckPercent / 100) ethSuccessRate := s.ethRequestAnalytics.GetSuccessRate() diff --git a/pkg/server/myctx.go b/pkg/server/myctx.go index 5d705be2..35142df8 100644 --- a/pkg/server/myctx.go +++ b/pkg/server/myctx.go @@ -7,22 +7,24 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" + "github.com/kaonone/eth-rpc-gate/pkg/analytics" + "github.com/kaonone/eth-rpc-gate/pkg/blockhash" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/transformer" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/analytics" - "github.com/qtumproject/janus/pkg/blockhash" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/transformer" ) type myCtx struct { echo.Context - rpcReq *eth.JSONRPCRequest - logWriter io.Writer - logger log.Logger - transformer *transformer.Transformer - blockHash *blockhash.BlockHash - qtumAnalytics *analytics.Analytics - ethAnalytics *analytics.Analytics + rpcReq *eth.JSONRPCRequest + logWriter io.Writer + logger log.Logger + transformer *transformer.Transformer + blockHash *blockhash.BlockHash + + healthCheckPercent *int + kaonAnalytics *analytics.Analytics + ethAnalytics *analytics.Analytics } func (c *myCtx) GetJSONRPCResult(result interface{}) (*eth.JSONRPCResult, error) { @@ -38,7 +40,7 @@ func (c *myCtx) JSONRPCResult(result interface{}) error { return c.JSON(http.StatusOK, response) } -func (c *myCtx) GetJSONRPCError(err eth.JSONRPCError) *eth.JSONRPCResult { +func (c *myCtx) GetJSONRPCError(err *eth.JSONRPCError) *eth.JSONRPCResult { var id json.RawMessage if c.rpcReq != nil && c.rpcReq.ID != nil { id = c.rpcReq.ID @@ -50,8 +52,8 @@ func (c *myCtx) GetJSONRPCError(err eth.JSONRPCError) *eth.JSONRPCResult { } } -func (c *myCtx) JSONRPCError(err eth.JSONRPCError) error { - resp := c.GetJSONRPCError(err) +func (c *myCtx) JSONRPCError(errIn *eth.JSONRPCError) error { + resp := c.GetJSONRPCError(errIn) if !c.Response().Committed { err := c.JSON(http.StatusOK, resp) diff --git a/pkg/server/server.go b/pkg/server/server.go index 150f7482..ffd77a0d 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -15,20 +15,20 @@ import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" "github.com/heptiolabs/healthcheck" + "github.com/kaonone/eth-rpc-gate/pkg/analytics" + "github.com/kaonone/eth-rpc-gate/pkg/blockhash" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/transformer" "github.com/labstack/echo" "github.com/labstack/echo/middleware" "github.com/pkg/errors" - "github.com/qtumproject/janus/pkg/analytics" - "github.com/qtumproject/janus/pkg/blockhash" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" - "github.com/qtumproject/janus/pkg/transformer" ) type Server struct { address string transformer *transformer.Transformer - qtumRPCClient *qtum.Qtum + kaonRPCClient *kaon.Kaon logWriter io.Writer logger log.Logger httpsKey string @@ -39,7 +39,7 @@ type Server struct { blockHash *blockhash.BlockHash healthCheckPercent *int - qtumRequestAnalytics *analytics.Analytics + kaonRequestAnalytics *analytics.Analytics ethRequestAnalytics *analytics.Analytics blocksMutex sync.RWMutex @@ -49,7 +49,7 @@ type Server struct { } func New( - qtumRPCClient *qtum.Qtum, + kaonRPCClient *kaon.Kaon, transformer *transformer.Transformer, addr string, opts ...Option, @@ -60,15 +60,15 @@ func New( logger: log.NewNopLogger(), echo: echo.New(), address: addr, - qtumRPCClient: qtumRPCClient, + kaonRPCClient: kaonRPCClient, transformer: transformer, ethRequestAnalytics: analytics.NewAnalytics(requests), } blockHashProcessor, err := blockhash.NewBlockHash( - qtumRPCClient.GetContext(), + kaonRPCClient.GetContext(), func() log.Logger { - return p.qtumRPCClient.GetLogger() + return p.kaonRPCClient.GetLogger() }, ) if err != nil { @@ -91,11 +91,11 @@ func (s *Server) Start() error { e := s.echo health := healthcheck.NewHandler() - health.AddLivenessCheck("qtumd-connection", func() error { return s.testConnectionToQtumd() }) - health.AddLivenessCheck("qtumd-logevents-enabled", func() error { return s.testLogEvents() }) - health.AddLivenessCheck("qtumd-blocks-syncing", func() error { return s.testBlocksSyncing() }) - health.AddLivenessCheck("qtumd-error-rate", func() error { return s.testQtumdErrorRate() }) - health.AddLivenessCheck("janus-error-rate", func() error { return s.testJanusErrorRate() }) + health.AddLivenessCheck("kaond-connection", func() error { return s.testConnectionToKaond() }) + health.AddLivenessCheck("kaond-logevents-enabled", func() error { return s.testLogEvents() }) + health.AddLivenessCheck("kaond-blocks-syncing", func() error { return s.testBlocksSyncing() }) + health.AddLivenessCheck("kaond-error-rate", func() error { return s.testKaondErrorRate() }) + health.AddLivenessCheck("ethrpcgate-error-rate", func() error { return s.testeth - rpc - gateErrorRate() }) e.Use(middleware.CORS()) e.Use(middleware.BodyDump(func(c echo.Context, req []byte, res []byte) { @@ -106,8 +106,8 @@ func (s *Server) Start() error { } if s.debug { - reqBody, reqErr := qtum.ReformatJSON(req) - resBody, resErr := qtum.ReformatJSON(res) + reqBody, reqErr := kaon.ReformatJSON(req) + resBody, resErr := kaon.ReformatJSON(res) if reqErr == nil && resErr == nil { cc.GetDebugLogger().Log("msg", "ETH RPC") fmt.Fprintf(logWriter, "=> ETH request\n%s\n", reqBody) @@ -128,7 +128,7 @@ func (s *Server) Start() error { logger: s.logger, transformer: s.transformer, blockHash: s.blockHash, - qtumAnalytics: s.qtumRequestAnalytics, + kaonAnalytics: s.kaonRequestAnalytics, ethAnalytics: s.ethRequestAnalytics, } @@ -169,8 +169,8 @@ func (s *Server) Start() error { } https := (s.httpsKey != "" && s.httpsCert != "") - url := s.qtumRPCClient.GetURL().Redacted() - level.Info(s.logger).Log("listen", s.address, "qtum_rpc", url, "msg", "proxy started", "https", https) + url := s.kaonRPCClient.GetURL().Redacted() + level.Info(s.logger).Log("listen", s.address, "KAON_RPC", url, "msg", "proxy started", "https", https) var err error @@ -178,24 +178,19 @@ func (s *Server) Start() error { go func(ctx context.Context, e *echo.Echo) { <-ctx.Done() e.Close() - }(s.qtumRPCClient.GetContext(), e) + }(s.kaonRPCClient.GetContext(), e) - if s.qtumRPCClient.DbConfig.String() == "" { + if s.kaonRPCClient.DbConfig.String() == "" { level.Warn(s.logger).Log("msg", "Database not configured - won't be able to respond to Ethereum block hash requests") } else { chainIdChan := make(chan int, 1) - err := s.blockHash.Start(&s.qtumRPCClient.DbConfig, chainIdChan) + err := s.blockHash.Start(&s.kaonRPCClient.DbConfig, chainIdChan) if err != nil { level.Error(s.logger).Log("msg", "Failed to launch block hash converter", "error", err) - /* - level.Error(s.logger).Log("msg", "Failed to connect to database, quitting") - e.Close() - return errors.Wrap(err, "Failed to connect to database") - */ } go func() { - chainIdChan <- s.qtumRPCClient.ChainId() + chainIdChan <- s.kaonRPCClient.ChainId() }() } @@ -251,9 +246,9 @@ func SetHttps(key string, cert string) Option { } } -func SetQtumAnalytics(analytics *analytics.Analytics) Option { +func SetKaonAnalytics(analytics *analytics.Analytics) Option { return func(p *Server) error { - p.qtumRequestAnalytics = analytics + p.kaonRequestAnalytics = analytics return nil } } @@ -329,7 +324,7 @@ func callHttpHandler(cc *myCtx, req *eth.JSONRPCRequest) (*eth.JSONRPCResult, er logger: cc.logger, transformer: cc.transformer, blockHash: cc.blockHash, - qtumAnalytics: cc.qtumAnalytics, + kaonAnalytics: cc.kaonAnalytics, ethAnalytics: cc.ethAnalytics, } newCtx.Set("myctx", myCtx) diff --git a/pkg/transformer/eth_accounts.go b/pkg/transformer/eth_accounts.go index c8d6dac2..13776454 100644 --- a/pkg/transformer/eth_accounts.go +++ b/pkg/transformer/eth_accounts.go @@ -1,30 +1,30 @@ package transformer import ( + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/utils" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" - "github.com/qtumproject/janus/pkg/utils" ) // ProxyETHAccounts implements ETHProxy type ProxyETHAccounts struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyETHAccounts) Method() string { return "eth_accounts" } -func (p *ProxyETHAccounts) Request(_ *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHAccounts) Request(_ *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { return p.request() } -func (p *ProxyETHAccounts) request() (eth.AccountsResponse, eth.JSONRPCError) { +func (p *ProxyETHAccounts) request() (eth.AccountsResponse, *eth.JSONRPCError) { var accounts eth.AccountsResponse for _, acc := range p.Accounts { - acc := qtum.Account{acc} + acc := kaon.Account{WIF: acc} addr := acc.ToHexAddress() accounts = append(accounts, utils.AddHexPrefix(addr)) @@ -33,8 +33,8 @@ func (p *ProxyETHAccounts) request() (eth.AccountsResponse, eth.JSONRPCError) { return accounts, nil } -func (p *ProxyETHAccounts) ToResponse(ethresp *qtum.CallContractResponse) *eth.CallResponse { +func (p *ProxyETHAccounts) ToResponse(ethresp *kaon.CallContractResponse) *eth.CallResponse { data := utils.AddHexPrefix(ethresp.ExecutionResult.Output) - qtumresp := eth.CallResponse(data) - return &qtumresp + kaonresp := eth.CallResponse(data) + return &kaonresp } diff --git a/pkg/transformer/eth_accounts_test.go b/pkg/transformer/eth_accounts_test.go index 6cc6fa95..14040af0 100644 --- a/pkg/transformer/eth_accounts_test.go +++ b/pkg/transformer/eth_accounts_test.go @@ -2,12 +2,13 @@ package transformer import ( "encoding/json" + "math/big" "testing" "github.com/btcsuite/btcutil" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" ) func TestAccountRequest(t *testing.T) { @@ -18,7 +19,7 @@ func TestAccountRequest(t *testing.T) { } mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) if err != nil { t.Fatal(err) } @@ -32,10 +33,10 @@ func TestAccountRequest(t *testing.T) { t.Fatal(err) } - qtumClient.Accounts = append(qtumClient.Accounts, exampleAcc1, exampleAcc2) + kaonClient.Accounts = append(kaonClient.Accounts, exampleAcc1, exampleAcc2) //preparing proxy & executing request - proxyEth := ProxyETHAccounts{qtumClient} + proxyEth := ProxyETHAccounts{kaonClient} got, jsonErr := proxyEth.Request(request, internal.NewEchoContext()) if jsonErr != nil { t.Fatal(jsonErr.Error()) @@ -48,12 +49,12 @@ func TestAccountRequest(t *testing.T) { func TestAccountMethod(t *testing.T) { mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) if err != nil { t.Fatal(err) } //preparing proxy & executing request - proxyEth := ProxyETHAccounts{qtumClient} + proxyEth := ProxyETHAccounts{kaonClient} got := proxyEth.Method() want := string("eth_accounts") @@ -62,22 +63,22 @@ func TestAccountMethod(t *testing.T) { } func TestAccountToResponse(t *testing.T) { mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) if err != nil { t.Fatal(err) } - proxyEth := ProxyETHAccounts{qtumClient} - callResponse := qtum.CallContractResponse{ + proxyEth := ProxyETHAccounts{kaonClient} + callResponse := kaon.CallContractResponse{ ExecutionResult: struct { - GasUsed int `json:"gasUsed"` - Excepted string `json:"excepted"` - ExceptedMessage string `json:"exceptedMessage"` - NewAddress string `json:"newAddress"` - Output string `json:"output"` - CodeDeposit int `json:"codeDeposit"` - GasRefunded int `json:"gasRefunded"` - DepositSize int `json:"depositSize"` - GasForDeposit int `json:"gasForDeposit"` + GasUsed big.Int `json:"gasUsed"` + Excepted string `json:"excepted"` + ExceptedMessage string `json:"exceptedMessage"` + NewAddress string `json:"newAddress"` + Output string `json:"output"` + CodeDeposit int `json:"codeDeposit"` + GasRefunded big.Int `json:"gasRefunded"` + DepositSize int `json:"depositSize"` + GasForDeposit big.Int `json:"gasForDeposit"` }{ Output: "0x0000000000000000000000000000000000000000000000000000000000000002", }, diff --git a/pkg/transformer/eth_blockNumber.go b/pkg/transformer/eth_blockNumber.go index bb7015d9..c4d50a60 100644 --- a/pkg/transformer/eth_blockNumber.go +++ b/pkg/transformer/eth_blockNumber.go @@ -5,28 +5,28 @@ import ( "time" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" ) // ProxyETHBlockNumber implements ETHProxy type ProxyETHBlockNumber struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyETHBlockNumber) Method() string { return "eth_blockNumber" } -func (p *ProxyETHBlockNumber) Request(_ *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHBlockNumber) Request(_ *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { return p.request(c, 5) } -func (p *ProxyETHBlockNumber) request(c echo.Context, retries int) (*eth.BlockNumberResponse, eth.JSONRPCError) { - qtumresp, err := p.Qtum.GetBlockCount(c.Request().Context()) +func (p *ProxyETHBlockNumber) request(c echo.Context, retries int) (*eth.BlockNumberResponse, *eth.JSONRPCError) { + kaonresp, err := p.Kaon.GetBlockCount(c.Request().Context()) if err != nil { - if retries > 0 && strings.Contains(err.Error(), qtum.ErrTryAgain.Error()) { + if retries > 0 && strings.Contains(err.Error(), kaon.ErrTryAgain.Error()) { ctx := c.Request().Context() t := time.NewTimer(500 * time.Millisecond) select { @@ -40,12 +40,12 @@ func (p *ProxyETHBlockNumber) request(c echo.Context, retries int) (*eth.BlockNu return nil, eth.NewCallbackError(err.Error()) } - // qtum res -> eth res - return p.ToResponse(qtumresp), nil + // kaon res -> eth res + return p.ToResponse(kaonresp), nil } -func (p *ProxyETHBlockNumber) ToResponse(qtumresp *qtum.GetBlockCountResponse) *eth.BlockNumberResponse { - hexVal := hexutil.EncodeBig(qtumresp.Int) +func (p *ProxyETHBlockNumber) ToResponse(kaonresp *kaon.GetBlockCountResponse) *eth.BlockNumberResponse { + hexVal := hexutil.EncodeBig(kaonresp.Int) ethresp := eth.BlockNumberResponse(hexVal) return ðresp } diff --git a/pkg/transformer/eth_blockNumber_test.go b/pkg/transformer/eth_blockNumber_test.go index f487b654..0748a0f6 100644 --- a/pkg/transformer/eth_blockNumber_test.go +++ b/pkg/transformer/eth_blockNumber_test.go @@ -5,9 +5,9 @@ import ( "math/big" "testing" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" ) func TestBlockNumberRequest(t *testing.T) { @@ -19,20 +19,20 @@ func TestBlockNumberRequest(t *testing.T) { } mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) if err != nil { t.Fatal(err) } //preparing client response - getBlockCountResponse := qtum.GetBlockCountResponse{Int: big.NewInt(11284900)} - err = mockedClientDoer.AddResponseWithRequestID(2, qtum.MethodGetBlockCount, getBlockCountResponse) + getBlockCountResponse := kaon.GetBlockCountResponse{Int: big.NewInt(11284900)} + err = mockedClientDoer.AddResponseWithRequestID(2, kaon.MethodGetBlockCount, getBlockCountResponse) if err != nil { t.Fatal(err) } //preparing proxy & executing request - proxyEth := ProxyETHBlockNumber{qtumClient} + proxyEth := ProxyETHBlockNumber{kaonClient} got, jsonErr := proxyEth.Request(request, internal.NewEchoContext()) if jsonErr != nil { t.Fatal(jsonErr) diff --git a/pkg/transformer/eth_call.go b/pkg/transformer/eth_call.go index ea47b228..44f3e447 100644 --- a/pkg/transformer/eth_call.go +++ b/pkg/transformer/eth_call.go @@ -2,24 +2,28 @@ package transformer import ( "context" + "encoding/hex" + "encoding/json" "math/big" + "strings" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/utils" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" - "github.com/qtumproject/janus/pkg/utils" ) // ProxyETHCall implements ETHProxy type ProxyETHCall struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyETHCall) Method() string { return "eth_call" } -func (p *ProxyETHCall) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHCall) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { var req eth.CallRequest if err := unmarshalRequest(rawreq.Params, &req); err != nil { // TODO: Is this correct error code? @@ -29,33 +33,94 @@ func (p *ProxyETHCall) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (inte return p.request(c.Request().Context(), &req) } -func (p *ProxyETHCall) request(ctx context.Context, ethreq *eth.CallRequest) (interface{}, eth.JSONRPCError) { - // eth req -> qtum req - qtumreq, jsonErr := p.ToRequest(ethreq) +func (p *ProxyETHCall) request(ctx context.Context, ethreq *eth.CallRequest) (interface{}, *eth.JSONRPCError) { + // eth req -> kaon req + kaonreq, jsonErr := p.ToRequest(ethreq) if jsonErr != nil { return nil, jsonErr } - if qtumreq.GasLimit != nil && qtumreq.GasLimit.Cmp(big.NewInt(40000000)) > 0 { - qtumresp := eth.CallResponse("0x") - p.Qtum.GetLogger().Log("msg", "Caller gas above allowance, capping", "requested", qtumreq.GasLimit.Int64(), "cap", "40,000,000") - return &qtumresp, nil + + // Check for specific cases based on the data and to fields + if strings.ToLower(ethreq.To) == "0x0000000000000000000000000000000000000000" { + switch { + case strings.HasPrefix(ethreq.Data, "0x70a08231"): + // Handle balance request (already implemented) + address := "0x" + ethreq.Data[34:] + balanceReq := ð.GetBalanceRequest{ + Address: address, + } + + params, err := json.Marshal([]interface{}{balanceReq.Address, "latest"}) + if err != nil { + return nil, eth.NewCallbackError("failed to marshal params: " + err.Error()) + } + + rawreq := ð.JSONRPCRequest{ + Method: "eth_getBalance", + Params: json.RawMessage(params), + } + + c := echo.New().AcquireContext() + balanceProxy := ProxyETHGetBalance{Kaon: p.Kaon} + balanceResult, balanceErr := balanceProxy.Request(rawreq, c) + + if balanceErr != nil { + return nil, balanceErr + } + + callResp := eth.CallResponse(balanceResult.(string)) + return &callResp, nil + + case strings.HasPrefix(ethreq.Data, "0x06fdde03"): + // Handle token name request (0x06fdde03 corresponds to "name()") + name := "KAON" + encodedName := hex.EncodeToString([]byte(name)) + // Pad the encoded name to 32 bytes + encodedName = encodedName + strings.Repeat("0", 64-len(encodedName)) + return eth.CallResponse("0x" + encodedName), nil + + case strings.HasPrefix(ethreq.Data, "0x18160ddd"): + // Handle total supply request (0x18160ddd corresponds to "totalSupply()") + unlimitedSupply := new(big.Int) + unlimitedSupply.SetString("000000000000000000000000000000000000ffffffffffffffffffffffffffff", 16) + return eth.CallResponse(hexutil.EncodeBig(unlimitedSupply)), nil + + case strings.HasPrefix(ethreq.Data, "0x313ce567"): + // Handle token decimals request (0x313ce567 corresponds to "decimals()") + decimals := big.NewInt(18) + return eth.CallResponse(hexutil.EncodeBig(decimals)), nil + + case strings.HasPrefix(ethreq.Data, "0x95d89b41"): + // Handle token symbol request (0x95d89b41 corresponds to "symbol()") + symbol := "KAON" + encodedSymbol := hex.EncodeToString([]byte(symbol)) + // Pad the encoded symbol to 32 bytes + encodedSymbol = encodedSymbol + strings.Repeat("0", 64-len(encodedSymbol)) + return eth.CallResponse("0x" + encodedSymbol), nil + } + } + + if kaonreq.GasLimit != nil && kaonreq.GasLimit.Cmp(big.NewInt(90000000)) > 0 { + kaonresp := eth.CallResponse("0x") + p.Kaon.GetLogger().Log("msg", "Caller gas above allowance, capping", "requested", kaonreq.GasLimit.Int64(), "cap", "90,000,000") + return &kaonresp, nil } - qtumresp, err := p.CallContract(ctx, qtumreq) + kaonresp, err := p.CallContract(ctx, kaonreq) if err != nil { - if err == qtum.ErrInvalidAddress { - qtumresp := eth.CallResponse("0x") - return &qtumresp, nil + if err == kaon.ErrInvalidAddress { + kaonresp := eth.CallResponse("0x") + return &kaonresp, nil } return nil, eth.NewCallbackError(err.Error()) } - // qtum res -> eth res - return p.ToResponse(qtumresp), nil + // kaon res -> eth res + return p.ToResponse(kaonresp), nil } -func (p *ProxyETHCall) ToRequest(ethreq *eth.CallRequest) (*qtum.CallContractRequest, eth.JSONRPCError) { +func (p *ProxyETHCall) ToRequest(ethreq *eth.CallRequest) (*kaon.CallContractRequest, *eth.JSONRPCError) { from := ethreq.From var err error if utils.IsEthHexAddress(from) { @@ -74,7 +139,7 @@ func (p *ProxyETHCall) ToRequest(ethreq *eth.CallRequest) (*qtum.CallContractReq p.GetLogger().Log("msg", "Gas limit is too low", "gasLimit", gasLimit.String()) } - return &qtum.CallContractRequest{ + return &kaon.CallContractRequest{ To: ethreq.To, From: from, Data: ethreq.Data, @@ -82,17 +147,18 @@ func (p *ProxyETHCall) ToRequest(ethreq *eth.CallRequest) (*qtum.CallContractReq }, nil } -func (p *ProxyETHCall) ToResponse(qresp *qtum.CallContractResponse) interface{} { - if qresp.ExecutionResult.Output == "" { - return eth.NewJSONRPCError( - -32000, - "Revert: executionResult output is empty", - nil, - ) - } - - data := utils.AddHexPrefix(qresp.ExecutionResult.Output) - qtumresp := eth.CallResponse(data) - return &qtumresp +func (p *ProxyETHCall) ToResponse(qresp *kaon.CallContractResponse) interface{} { + // TODO: research under which sircumstances this may work + // if qresp.ExecutionResult.Output == "" { + // return eth.NewJSONRPCError( + // -32000, + // "Revert: executionResult output is empty", + // nil, + // ) + // } + + data := utils.AddHexWithLengthPrefix(qresp.ExecutionResult.Output) + kaonresp := eth.CallResponse(data) + return &kaonresp } diff --git a/pkg/transformer/eth_call_test.go b/pkg/transformer/eth_call_test.go index 91df4d9f..dcc77ad1 100644 --- a/pkg/transformer/eth_call_test.go +++ b/pkg/transformer/eth_call_test.go @@ -2,12 +2,13 @@ package transformer import ( "encoding/json" + "math/big" "testing" "time" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" ) func TestEthCallRequest(t *testing.T) { @@ -24,51 +25,51 @@ func TestEthCallRequest(t *testing.T) { requestRPC, err := internal.PrepareEthRPCRequest(1, requestParamsArray) clientDoerMock := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(clientDoerMock) + kaonClient, err := internal.CreateMockedClient(clientDoerMock) //preparing response - callContractResponse := qtum.CallContractResponse{ + callContractResponse := kaon.CallContractResponse{ Address: "1e6f89d7399081b4f8f8aa1ae2805a5efff2f960", ExecutionResult: struct { - GasUsed int `json:"gasUsed"` - Excepted string `json:"excepted"` - ExceptedMessage string `json:"exceptedMessage"` - NewAddress string `json:"newAddress"` - Output string `json:"output"` - CodeDeposit int `json:"codeDeposit"` - GasRefunded int `json:"gasRefunded"` - DepositSize int `json:"depositSize"` - GasForDeposit int `json:"gasForDeposit"` + GasUsed big.Int `json:"gasUsed"` + Excepted string `json:"excepted"` + ExceptedMessage string `json:"exceptedMessage"` + NewAddress string `json:"newAddress"` + Output string `json:"output"` + CodeDeposit int `json:"codeDeposit"` + GasRefunded big.Int `json:"gasRefunded"` + DepositSize int `json:"depositSize"` + GasForDeposit big.Int `json:"gasForDeposit"` }{ - GasUsed: 21678, + GasUsed: *big.NewInt(216780), Excepted: "None", NewAddress: "1e6f89d7399081b4f8f8aa1ae2805a5efff2f960", Output: "0000000000000000000000000000000000000000000000000000000000000001", }, TransactionReceipt: struct { StateRoot string `json:"stateRoot"` - GasUsed int `json:"gasUsed"` + GasUsed big.Int `json:"gasUsed"` Bloom string `json:"bloom"` Log []interface{} `json:"log"` }{ StateRoot: "d44fc5ad43bae52f01ff7eb4a7bba904ee52aea6c41f337aa29754e57c73fba6", - GasUsed: 21678, + GasUsed: *big.NewInt(216780), Bloom: "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", }, } - err = clientDoerMock.AddResponseWithRequestID(1, qtum.MethodCallContract, callContractResponse) + err = clientDoerMock.AddResponseWithRequestID(1, kaon.MethodCallContract, callContractResponse) if err != nil { t.Fatal(err) } - fromHexAddressResponse := qtum.FromHexAddressResponse("0x1e6f89d7399081b4f8f8aa1ae2805a5efff2f960") - err = clientDoerMock.AddResponseWithRequestID(2, qtum.MethodFromHexAddress, fromHexAddressResponse) + fromHexAddressResponse := kaon.FromHexAddressResponse("0x1e6f89d7399081b4f8f8aa1ae2805a5efff2f960") + err = clientDoerMock.AddResponseWithRequestID(2, kaon.MethodFromHexAddress, fromHexAddressResponse) if err != nil { t.Fatal(err) } //preparing proxy & executing - proxyEth := ProxyETHCall{qtumClient} + proxyEth := ProxyETHCall{kaonClient} if err != nil { t.Fatal(err) } @@ -97,54 +98,54 @@ func TestRetry(t *testing.T) { requestRPC, err := internal.PrepareEthRPCRequest(1, requestParamsArray) clientDoerMock := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(clientDoerMock) + kaonClient, err := internal.CreateMockedClient(clientDoerMock) //preparing response - callContractResponse := qtum.CallContractResponse{ + callContractResponse := kaon.CallContractResponse{ Address: "1e6f89d7399081b4f8f8aa1ae2805a5efff2f960", ExecutionResult: struct { - GasUsed int `json:"gasUsed"` - Excepted string `json:"excepted"` - ExceptedMessage string `json:"exceptedMessage"` - NewAddress string `json:"newAddress"` - Output string `json:"output"` - CodeDeposit int `json:"codeDeposit"` - GasRefunded int `json:"gasRefunded"` - DepositSize int `json:"depositSize"` - GasForDeposit int `json:"gasForDeposit"` + GasUsed big.Int `json:"gasUsed"` + Excepted string `json:"excepted"` + ExceptedMessage string `json:"exceptedMessage"` + NewAddress string `json:"newAddress"` + Output string `json:"output"` + CodeDeposit int `json:"codeDeposit"` + GasRefunded big.Int `json:"gasRefunded"` + DepositSize int `json:"depositSize"` + GasForDeposit big.Int `json:"gasForDeposit"` }{ - GasUsed: 21678, + GasUsed: *big.NewInt(216780), Excepted: "None", NewAddress: "1e6f89d7399081b4f8f8aa1ae2805a5efff2f960", Output: "0000000000000000000000000000000000000000000000000000000000000001", }, TransactionReceipt: struct { StateRoot string `json:"stateRoot"` - GasUsed int `json:"gasUsed"` + GasUsed big.Int `json:"gasUsed"` Bloom string `json:"bloom"` Log []interface{} `json:"log"` }{ StateRoot: "d44fc5ad43bae52f01ff7eb4a7bba904ee52aea6c41f337aa29754e57c73fba6", - GasUsed: 21678, + GasUsed: *big.NewInt(216780), Bloom: "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", }, } - // return QTUM is busy response 4 times + // return Kaon is busy response 4 times for i := 0; i < 4; i++ { - clientDoerMock.AddRawResponse(qtum.MethodCallContract, []byte(qtum.ErrQtumWorkQueueDepth.Error())) + clientDoerMock.AddRawResponse(kaon.MethodCallContract, []byte(kaon.ErrKaonWorkQueueDepth.Error())) } // on 5th request, return correct value - clientDoerMock.AddResponseWithRequestID(1, qtum.MethodCallContract, callContractResponse) + clientDoerMock.AddResponseWithRequestID(1, kaon.MethodCallContract, callContractResponse) - fromHexAddressResponse := qtum.FromHexAddressResponse("0x1e6f89d7399081b4f8f8aa1ae2805a5efff2f960") - err = clientDoerMock.AddResponseWithRequestID(2, qtum.MethodFromHexAddress, fromHexAddressResponse) + fromHexAddressResponse := kaon.FromHexAddressResponse("0x1e6f89d7399081b4f8f8aa1ae2805a5efff2f960") + err = clientDoerMock.AddResponseWithRequestID(2, kaon.MethodFromHexAddress, fromHexAddressResponse) if err != nil { t.Fatal(err) } //preparing proxy & executing - proxyEth := ProxyETHCall{qtumClient} + proxyEth := ProxyETHCall{kaonClient} if err != nil { t.Fatal(err) } @@ -181,23 +182,23 @@ func TestEthCallRequestOnUnknownContract(t *testing.T) { requestRPC, err := internal.PrepareEthRPCRequest(1, requestParamsArray) clientDoerMock := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(clientDoerMock) + kaonClient, err := internal.CreateMockedClient(clientDoerMock) - fromHexAddressResponse := qtum.FromHexAddressResponse("0x1e6f89d7399081b4f8f8aa1ae2805a5efff2f960") - err = clientDoerMock.AddResponse(qtum.MethodFromHexAddress, fromHexAddressResponse) + fromHexAddressResponse := kaon.FromHexAddressResponse("0x1e6f89d7399081b4f8f8aa1ae2805a5efff2f960") + err = clientDoerMock.AddResponse(kaon.MethodFromHexAddress, fromHexAddressResponse) if err != nil { t.Fatal(err) } //preparing error response - unknownAddressResponse := qtum.GetErrorResponse(qtum.ErrInvalidAddress) - err = clientDoerMock.AddError(qtum.MethodCallContract, unknownAddressResponse) + unknownAddressResponse := kaon.GetErrorResponse(kaon.ErrInvalidAddress) + err = clientDoerMock.AddError(kaon.MethodCallContract, unknownAddressResponse) if err != nil { t.Fatal(err) } //preparing proxy & executing - proxyEth := ProxyETHCall{qtumClient} + proxyEth := ProxyETHCall{kaonClient} if err != nil { t.Fatal(err) } diff --git a/pkg/transformer/eth_chainId.go b/pkg/transformer/eth_chainId.go index 48705c0d..95755c11 100644 --- a/pkg/transformer/eth_chainId.go +++ b/pkg/transformer/eth_chainId.go @@ -4,27 +4,27 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" ) type ProxyETHChainId struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyETHChainId) Method() string { return "eth_chainId" } -func (p *ProxyETHChainId) Request(req *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { - chainId, err := getChainId(p.Qtum) +func (p *ProxyETHChainId) Request(req *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { + chainId, err := getChainId(p.Kaon) if err != nil { return nil, err } return eth.ChainIdResponse(hexutil.EncodeBig(chainId)), nil } -func getChainId(p *qtum.Qtum) (*big.Int, eth.JSONRPCError) { +func getChainId(p *kaon.Kaon) (*big.Int, *eth.JSONRPCError) { return big.NewInt(int64(p.ChainId())), nil } diff --git a/pkg/transformer/eth_chainId_test.go b/pkg/transformer/eth_chainId_test.go index cf89fd1d..ed8a88b7 100644 --- a/pkg/transformer/eth_chainId_test.go +++ b/pkg/transformer/eth_chainId_test.go @@ -4,21 +4,21 @@ import ( "encoding/json" "testing" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" ) func TestChainIdMainnet(t *testing.T) { - testChainIdsImpl(t, "main", "0x51") + testChainIdsImpl(t, "main", "0x2ED3") } func TestChainIdTestnet(t *testing.T) { - testChainIdsImpl(t, "test", "0x22b9") + testChainIdsImpl(t, "test", "0x2ED5") } func TestChainIdRegtest(t *testing.T) { - testChainIdsImpl(t, "regtest", "0x22ba") + testChainIdsImpl(t, "regtest", "0x2ED4") } func TestChainIdUnknown(t *testing.T) { @@ -36,19 +36,19 @@ func testChainIdsImpl(t *testing.T, chain string, expected string) { mockedClientDoer := internal.NewDoerMappedMock() //preparing client response - getBlockCountResponse := qtum.GetBlockChainInfoResponse{Chain: chain} - err = mockedClientDoer.AddResponseWithRequestID(2, qtum.MethodGetBlockChainInfo, getBlockCountResponse) + getBlockCountResponse := kaon.GetBlockChainInfoResponse{Chain: chain} + err = mockedClientDoer.AddResponseWithRequestID(2, kaon.MethodGetBlockChainInfo, getBlockCountResponse) if err != nil { t.Fatal(err) } - qtumClient, err := internal.CreateMockedClientForNetwork(mockedClientDoer, qtum.ChainAuto) + kaonClient, err := internal.CreateMockedClientForNetwork(mockedClientDoer, kaon.ChainAuto) if err != nil { t.Fatal(err) } //preparing proxy & executing request - proxyEth := ProxyETHChainId{qtumClient} + proxyEth := ProxyETHChainId{kaonClient} got, jsonErr := proxyEth.Request(request, internal.NewEchoContext()) if jsonErr != nil { t.Fatal(jsonErr) diff --git a/pkg/transformer/eth_estimateGas.go b/pkg/transformer/eth_estimateGas.go index fb403a0b..beb3bd03 100644 --- a/pkg/transformer/eth_estimateGas.go +++ b/pkg/transformer/eth_estimateGas.go @@ -1,19 +1,20 @@ package transformer import ( + "math/big" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" "github.com/labstack/echo" "github.com/pkg/errors" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" ) -// 22000 -var NonContractVMGasLimit = "0x55f0" +// 2.1e5 +var NonContractVMGasLimit = "0x33450" var ErrExecutionReverted = errors.New("execution reverted") -// 10% isn't enough in some cases, neither is 15%, 20% works -var GAS_BUFFER = 1.20 +var GAS_BUFFER = 1.10 // ProxyETHEstimateGas implements ETHProxy type ProxyETHEstimateGas struct { @@ -24,19 +25,14 @@ func (p *ProxyETHEstimateGas) Method() string { return "eth_estimateGas" } -func (p *ProxyETHEstimateGas) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHEstimateGas) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { var ethreq eth.CallRequest if jsonErr := unmarshalRequest(rawreq.Params, ðreq); jsonErr != nil { // TODO: Correct error code? return nil, eth.NewInvalidParamsError(jsonErr.Error()) } - if ethreq.Data == "" { - response := eth.EstimateGasResponse(NonContractVMGasLimit) - return &response, nil - } - - // when supplying this parameter to callcontract to estimate gas in the qtum api + // when supplying this parameter to callcontract to estimate gas in the kaon api // if there isn't enough gas specified here, the result will be an exception // Excepted = "OutOfGasIntrinsic" // Gas = "the supplied value" @@ -45,26 +41,45 @@ func (p *ProxyETHEstimateGas) Request(rawreq *eth.JSONRPCRequest, c echo.Context // so we set this to nil so that callcontract will return the actual gas estimate ethreq.Gas = nil - // eth req -> qtum req - qtumreq, jsonErr := p.ToRequest(ðreq) + // eth req -> kaon req + kaonreq, jsonErr := p.ToRequest(ðreq) if jsonErr != nil { return nil, jsonErr } - // qtum [code: -5] Incorrect address occurs here - qtumresp, err := p.CallContract(c.Request().Context(), qtumreq) + // kaon [code: -5] Incorrect address occurs here + kaonresp, err := p.CallContract(c.Request().Context(), kaonreq) if err != nil { return nil, eth.NewCallbackError(err.Error()) } - return p.toResp(qtumresp) + return p.toResp(kaonresp) } -func (p *ProxyETHEstimateGas) toResp(qtumresp *qtum.CallContractResponse) (*eth.EstimateGasResponse, eth.JSONRPCError) { - if qtumresp.ExecutionResult.Excepted != "None" { - return nil, eth.NewCallbackError(ErrExecutionReverted.Error()) - } - gas := eth.EstimateGasResponse(hexutil.EncodeUint64(uint64(float64(qtumresp.ExecutionResult.GasUsed) * GAS_BUFFER))) +func multiplyGasUsedByBuffer(gasUsedIn big.Int, gasBuffer float64) *big.Int { + // Convert GAS_BUFFER to a big.Float + buffer := new(big.Float).SetFloat64(gasBuffer) + + // Convert big.Int to big.Float + gasUsed := new(big.Float).SetInt(&gasUsedIn) + + // Multiply big.Float values + result := new(big.Float).Mul(gasUsed, buffer) + + // Convert the result back to big.Int + finalResult := new(big.Int) + result.Int(finalResult) + + return finalResult +} + +func (p *ProxyETHEstimateGas) toResp(kaonresp *kaon.CallContractResponse) (*eth.EstimateGasResponse, *eth.JSONRPCError) { + // TODO: research under which circumstances it may work + // p.Kaon.GetLogger().Log("msg", "!!!!!!!", "requested", marshalToString(kaonresp)) + // if kaonresp.ExecutionResult.Excepted != "None" { + // return nil, eth.NewCallbackError(ErrExecutionReverted.Error()) + // } + gas := eth.EstimateGasResponse(hexutil.EncodeBig(multiplyGasUsedByBuffer(kaonresp.ExecutionResult.GasUsed, GAS_BUFFER))) p.GetDebugLogger().Log(p.Method(), gas) return &gas, nil } diff --git a/pkg/transformer/eth_estimateGas_test.go b/pkg/transformer/eth_estimateGas_test.go index 174b2396..e12a57f8 100644 --- a/pkg/transformer/eth_estimateGas_test.go +++ b/pkg/transformer/eth_estimateGas_test.go @@ -2,11 +2,12 @@ package transformer import ( "encoding/json" + "math/big" "testing" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" ) func TestEstimateGasRequest(t *testing.T) { @@ -27,42 +28,42 @@ func TestEstimateGasRequest(t *testing.T) { } mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) if err != nil { t.Fatal(err) } //preparing responses - fromHexAddressResponse := qtum.FromHexAddressResponse("0x1e6f89d7399081b4f8f8aa1ae2805a5efff2f960") - err = mockedClientDoer.AddResponseWithRequestID(2, qtum.MethodFromHexAddress, fromHexAddressResponse) + fromHexAddressResponse := kaon.FromHexAddressResponse("0x1e6f89d7399081b4f8f8aa1ae2805a5efff2f960") + err = mockedClientDoer.AddResponseWithRequestID(2, kaon.MethodFromHexAddress, fromHexAddressResponse) if err != nil { t.Fatal(err) } - callContractResponse := qtum.CallContractResponse{ + callContractResponse := kaon.CallContractResponse{ Address: "1e6f89d7399081b4f8f8aa1ae2805a5efff2f960", ExecutionResult: struct { - GasUsed int `json:"gasUsed"` - Excepted string `json:"excepted"` - ExceptedMessage string `json:"exceptedMessage"` - NewAddress string `json:"newAddress"` - Output string `json:"output"` - CodeDeposit int `json:"codeDeposit"` - GasRefunded int `json:"gasRefunded"` - DepositSize int `json:"depositSize"` - GasForDeposit int `json:"gasForDeposit"` + GasUsed big.Int `json:"gasUsed"` + Excepted string `json:"excepted"` + ExceptedMessage string `json:"exceptedMessage"` + NewAddress string `json:"newAddress"` + Output string `json:"output"` + CodeDeposit int `json:"codeDeposit"` + GasRefunded big.Int `json:"gasRefunded"` + DepositSize int `json:"depositSize"` + GasForDeposit big.Int `json:"gasForDeposit"` }{ - GasUsed: 21678, + GasUsed: *big.NewInt(216780), Excepted: "None", }, } - err = mockedClientDoer.AddResponseWithRequestID(1, qtum.MethodCallContract, callContractResponse) + err = mockedClientDoer.AddResponseWithRequestID(1, kaon.MethodCallContract, callContractResponse) if err != nil { t.Fatal(err) } //preparing proxy & executing request - proxyEth := ProxyETHCall{qtumClient} + proxyEth := ProxyETHCall{kaonClient} proxyEthEstimateGas := ProxyETHEstimateGas{&proxyEth} got, jsonErr := proxyEthEstimateGas.Request(requestRPC, internal.NewEchoContext()) if jsonErr != nil { @@ -92,42 +93,42 @@ func TestEstimateGasRequestExecutionReverted(t *testing.T) { } mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) if err != nil { t.Fatal(err) } //preparing responses - fromHexAddressResponse := qtum.FromHexAddressResponse("0x1e6f89d7399081b4f8f8aa1ae2805a5efff2f960") - err = mockedClientDoer.AddResponseWithRequestID(2, qtum.MethodFromHexAddress, fromHexAddressResponse) + fromHexAddressResponse := kaon.FromHexAddressResponse("0x1e6f89d7399081b4f8f8aa1ae2805a5efff2f960") + err = mockedClientDoer.AddResponseWithRequestID(2, kaon.MethodFromHexAddress, fromHexAddressResponse) if err != nil { t.Fatal(err) } - callContractResponse := qtum.CallContractResponse{ + callContractResponse := kaon.CallContractResponse{ Address: "1e6f89d7399081b4f8f8aa1ae2805a5efff2f960", ExecutionResult: struct { - GasUsed int `json:"gasUsed"` - Excepted string `json:"excepted"` - ExceptedMessage string `json:"exceptedMessage"` - NewAddress string `json:"newAddress"` - Output string `json:"output"` - CodeDeposit int `json:"codeDeposit"` - GasRefunded int `json:"gasRefunded"` - DepositSize int `json:"depositSize"` - GasForDeposit int `json:"gasForDeposit"` + GasUsed big.Int `json:"gasUsed"` + Excepted string `json:"excepted"` + ExceptedMessage string `json:"exceptedMessage"` + NewAddress string `json:"newAddress"` + Output string `json:"output"` + CodeDeposit int `json:"codeDeposit"` + GasRefunded big.Int `json:"gasRefunded"` + DepositSize int `json:"depositSize"` + GasForDeposit big.Int `json:"gasForDeposit"` }{ - GasUsed: 21678, + GasUsed: *big.NewInt(216780), Excepted: "OutOfGas", }, } - err = mockedClientDoer.AddResponseWithRequestID(1, qtum.MethodCallContract, callContractResponse) + err = mockedClientDoer.AddResponseWithRequestID(1, kaon.MethodCallContract, callContractResponse) if err != nil { t.Fatal(err) } //preparing proxy & executing request - proxyEth := ProxyETHCall{qtumClient} + proxyEth := ProxyETHCall{kaonClient} proxyEthEstimateGas := ProxyETHEstimateGas{&proxyEth} _, got := proxyEthEstimateGas.Request(requestRPC, internal.NewEchoContext()) @@ -154,42 +155,42 @@ func TestEstimateGasNonVMRequest(t *testing.T) { } mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) if err != nil { t.Fatal(err) } //preparing responses - fromHexAddressResponse := qtum.FromHexAddressResponse("0x1e6f89d7399081b4f8f8aa1ae2805a5efff2f960") - err = mockedClientDoer.AddResponseWithRequestID(2, qtum.MethodFromHexAddress, fromHexAddressResponse) + fromHexAddressResponse := kaon.FromHexAddressResponse("0x1e6f89d7399081b4f8f8aa1ae2805a5efff2f960") + err = mockedClientDoer.AddResponseWithRequestID(2, kaon.MethodFromHexAddress, fromHexAddressResponse) if err != nil { t.Fatal(err) } - callContractResponse := qtum.CallContractResponse{ + callContractResponse := kaon.CallContractResponse{ Address: "1e6f89d7399081b4f8f8aa1ae2805a5efff2f960", ExecutionResult: struct { - GasUsed int `json:"gasUsed"` - Excepted string `json:"excepted"` - ExceptedMessage string `json:"exceptedMessage"` - NewAddress string `json:"newAddress"` - Output string `json:"output"` - CodeDeposit int `json:"codeDeposit"` - GasRefunded int `json:"gasRefunded"` - DepositSize int `json:"depositSize"` - GasForDeposit int `json:"gasForDeposit"` + GasUsed big.Int `json:"gasUsed"` + Excepted string `json:"excepted"` + ExceptedMessage string `json:"exceptedMessage"` + NewAddress string `json:"newAddress"` + Output string `json:"output"` + CodeDeposit int `json:"codeDeposit"` + GasRefunded big.Int `json:"gasRefunded"` + DepositSize int `json:"depositSize"` + GasForDeposit big.Int `json:"gasForDeposit"` }{ - GasUsed: 21678, + GasUsed: *big.NewInt(216780), Excepted: "None", }, } - err = mockedClientDoer.AddResponseWithRequestID(1, qtum.MethodCallContract, callContractResponse) + err = mockedClientDoer.AddResponseWithRequestID(1, kaon.MethodCallContract, callContractResponse) if err != nil { t.Fatal(err) } //preparing proxy & executing request - proxyEth := ProxyETHCall{qtumClient} + proxyEth := ProxyETHCall{kaonClient} proxyEthEstimateGas := ProxyETHEstimateGas{&proxyEth} got, jsonErr := proxyEthEstimateGas.Request(requestRPC, internal.NewEchoContext()) if jsonErr != nil { diff --git a/pkg/transformer/eth_gasPrice.go b/pkg/transformer/eth_gasPrice.go index 0a3959d7..6f7d06cf 100644 --- a/pkg/transformer/eth_gasPrice.go +++ b/pkg/transformer/eth_gasPrice.go @@ -4,31 +4,31 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" ) // ProxyETHEstimateGas implements ETHProxy type ProxyETHGasPrice struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyETHGasPrice) Method() string { return "eth_gasPrice" } -func (p *ProxyETHGasPrice) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { - qtumresp, err := p.Qtum.GetGasPrice(c.Request().Context()) +func (p *ProxyETHGasPrice) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { + kaonresp, err := p.Kaon.GetGasPrice(c.Request().Context()) if err != nil { return nil, eth.NewCallbackError(err.Error()) } - // qtum res -> eth res - return p.response(qtumresp), nil + // kaon res -> eth res + return p.response(kaonresp), nil } -func (p *ProxyETHGasPrice) response(qtumresp *big.Int) string { - // 34 GWEI is the minimum price that QTUM will confirm tx with - return hexutil.EncodeBig(convertFromSatoshiToWei(qtumresp)) +func (p *ProxyETHGasPrice) response(kaonresp *big.Int) string { + // 34 GWEI is the minimum price that KAON will confirm tx with + return hexutil.EncodeBig(convertFromSatoshiToWei(kaonresp)) } diff --git a/pkg/transformer/eth_gasPrice_test.go b/pkg/transformer/eth_gasPrice_test.go index 74f93d53..dbb9ad75 100644 --- a/pkg/transformer/eth_gasPrice_test.go +++ b/pkg/transformer/eth_gasPrice_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "testing" - "github.com/qtumproject/janus/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/internal" ) func TestGasPriceRequest(t *testing.T) { @@ -16,13 +16,13 @@ func TestGasPriceRequest(t *testing.T) { } mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) if err != nil { t.Fatal(err) } //preparing proxy & executing request - proxyEth := ProxyETHGasPrice{qtumClient} + proxyEth := ProxyETHGasPrice{kaonClient} got, jsonErr := proxyEth.Request(request, internal.NewEchoContext()) if jsonErr != nil { t.Fatal(jsonErr) diff --git a/pkg/transformer/eth_getBalance.go b/pkg/transformer/eth_getBalance.go index 2cb204b9..bfaa06ac 100644 --- a/pkg/transformer/eth_getBalance.go +++ b/pkg/transformer/eth_getBalance.go @@ -1,42 +1,44 @@ package transformer import ( - "math/big" - "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/utils" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" - "github.com/qtumproject/janus/pkg/utils" ) // ProxyETHGetBalance implements ETHProxy type ProxyETHGetBalance struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyETHGetBalance) Method() string { return "eth_getBalance" } -func (p *ProxyETHGetBalance) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHGetBalance) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { var req eth.GetBalanceRequest if err := unmarshalRequest(rawreq.Params, &req); err != nil { // TODO: Correct error code? return nil, eth.NewInvalidParamsError(err.Error()) } + if req.Address == "0x0000000000000000000000000000000000000000" { // ErrInvalidAddress + return "0x0", nil + } + addr := utils.RemoveHexPrefix(req.Address) { // is address a contract or an account? - qtumreq := qtum.GetAccountInfoRequest(addr) - qtumresp, err := p.GetAccountInfo(c.Request().Context(), &qtumreq) + kaonreq := kaon.GetAccountInfoRequest(addr) + kaonresp, err := p.GetAccountInfo(c.Request().Context(), &kaonreq) // the address is a contract if err == nil { // the unit of the balance Satoshi p.GetDebugLogger().Log("method", p.Method(), "address", req.Address, "msg", "is a contract") - return hexutil.EncodeUint64(uint64(qtumresp.Balance)), nil + return hexutil.EncodeBig(&kaonresp.Balance), nil } } @@ -48,12 +50,10 @@ func (p *ProxyETHGetBalance) Request(rawreq *eth.JSONRPCRequest, c echo.Context) return nil, eth.NewCallbackError(err.Error()) } - qtumreq := qtum.GetAddressBalanceRequest{ - Addresses: []string{base58Addr}, - } - qtumresp, err := p.GetAddressBalance(c.Request().Context(), &qtumreq) + kaonreq := kaon.GetAddressBalanceRequest{Address: base58Addr} + kaonresp, err := p.GetAddressBalance(c.Request().Context(), &kaonreq) if err != nil { - if err == qtum.ErrInvalidAddress { + if err == kaon.ErrInvalidAddress { // invalid address should return 0x0 return "0x0", nil } @@ -61,12 +61,9 @@ func (p *ProxyETHGetBalance) Request(rawreq *eth.JSONRPCRequest, c echo.Context) return nil, eth.NewCallbackError(err.Error()) } - // 1 QTUM = 10 ^ 8 Satoshi - balance := new(big.Int).SetUint64(qtumresp.Balance) - - //Balance for ETH response is represented in Weis (1 QTUM Satoshi = 10 ^ 10 Wei) - balance = balance.Mul(balance, big.NewInt(10000000000)) + // 1 KAON = 10 ^ 18 Satoshi + balance := kaonresp.Balance - return hexutil.EncodeBig(balance), nil + return hexutil.EncodeBig(&balance), nil } } diff --git a/pkg/transformer/eth_getBalance_test.go b/pkg/transformer/eth_getBalance_test.go index ea458855..600d0e32 100644 --- a/pkg/transformer/eth_getBalance_test.go +++ b/pkg/transformer/eth_getBalance_test.go @@ -2,11 +2,12 @@ package transformer import ( "encoding/json" + "math/big" "testing" "github.com/btcsuite/btcutil" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" ) func TestGetBalanceRequestAccount(t *testing.T) { @@ -18,7 +19,7 @@ func TestGetBalanceRequestAccount(t *testing.T) { } //prepare client mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) if err != nil { t.Fatal(err) } @@ -28,17 +29,17 @@ func TestGetBalanceRequestAccount(t *testing.T) { if err != nil { t.Fatal(err) } - qtumClient.Accounts = append(qtumClient.Accounts, account) + kaonClient.Accounts = append(kaonClient.Accounts, account) //prepare responses - fromHexAddressResponse := qtum.FromHexAddressResponse("5JK4Gu9nxCvsCxiq9Zf3KdmA9ACza6dUn5BRLVWAYEtQabdnJ89") - err = mockedClientDoer.AddResponseWithRequestID(2, qtum.MethodFromHexAddress, fromHexAddressResponse) + fromHexAddressResponse := kaon.FromHexAddressResponse("5JK4Gu9nxCvsCxiq9Zf3KdmA9ACza6dUn5BRLVWAYEtQabdnJ89") + err = mockedClientDoer.AddResponseWithRequestID(2, kaon.MethodFromHexAddress, fromHexAddressResponse) if err != nil { t.Fatal(err) } - getAddressBalanceResponse := qtum.GetAddressBalanceResponse{Balance: uint64(100000000), Received: uint64(100000000), Immature: int64(0)} - err = mockedClientDoer.AddResponseWithRequestID(3, qtum.MethodGetAddressBalance, getAddressBalanceResponse) + getAddressBalanceResponse := kaon.GetAddressBalanceResponse{Balance: *big.NewInt(100000000), Received: *big.NewInt(100000000), Immature: *big.NewInt(100000000)} + err = mockedClientDoer.AddResponseWithRequestID(3, kaon.MethodGetAddressBalance, getAddressBalanceResponse) if err != nil { t.Fatal(err) } @@ -48,13 +49,13 @@ func TestGetBalanceRequestAccount(t *testing.T) { // then address is contract, else account //preparing proxy & executing request - proxyEth := ProxyETHGetBalance{qtumClient} + proxyEth := ProxyETHGetBalance{kaonClient} got, jsonErr := proxyEth.Request(requestRPC, internal.NewEchoContext()) if jsonErr != nil { t.Fatal(jsonErr) } - want := string("0xde0b6b3a7640000") //1 Qtum represented in Wei + want := string("0xde0b6b3a7640000") //1 Kaon represented in Wei internal.CheckTestResultEthRequestRPC(*requestRPC, want, got, t, false) } @@ -68,7 +69,7 @@ func TestGetBalanceRequestContract(t *testing.T) { } //prepare client mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) if err != nil { t.Fatal(err) } @@ -78,22 +79,22 @@ func TestGetBalanceRequestContract(t *testing.T) { if err != nil { t.Fatal(err) } - qtumClient.Accounts = append(qtumClient.Accounts, account) + kaonClient.Accounts = append(kaonClient.Accounts, account) //prepare responses - getAccountInfoResponse := qtum.GetAccountInfoResponse{ + getAccountInfoResponse := kaon.GetAccountInfoResponse{ Address: "1e6f89d7399081b4f8f8aa1ae2805a5efff2f960", - Balance: 12431243, + Balance: *big.NewInt(12431243), // Storage json.RawMessage `json:"storage"`, // Code string `json:"code"`, } - err = mockedClientDoer.AddResponseWithRequestID(3, qtum.MethodGetAccountInfo, getAccountInfoResponse) + err = mockedClientDoer.AddResponseWithRequestID(3, kaon.MethodGetAccountInfo, getAccountInfoResponse) if err != nil { t.Fatal(err) } //preparing proxy & executing request - proxyEth := ProxyETHGetBalance{qtumClient} + proxyEth := ProxyETHGetBalance{kaonClient} got, jsonErr := proxyEth.Request(requestRPC, internal.NewEchoContext()) if jsonErr != nil { t.Fatal(jsonErr) diff --git a/pkg/transformer/eth_getBlockByHash.go b/pkg/transformer/eth_getBlockByHash.go index 9e3de0e5..30a57162 100644 --- a/pkg/transformer/eth_getBlockByHash.go +++ b/pkg/transformer/eth_getBlockByHash.go @@ -2,15 +2,17 @@ package transformer import ( "context" + "encoding/json" "fmt" + "math/big" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/kaonone/eth-rpc-gate/pkg/blockhash" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/utils" "github.com/labstack/echo" "github.com/pkg/errors" - "github.com/qtumproject/janus/pkg/blockhash" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" - "github.com/qtumproject/janus/pkg/utils" ) var ErrBlockHashNotConfigured = errors.New("BlockHash database not configured") @@ -18,14 +20,14 @@ var ErrBlockHashUnknown = errors.New("BlockHash unknown") // ProxyETHGetBlockByHash implements ETHProxy type ProxyETHGetBlockByHash struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyETHGetBlockByHash) Method() string { return "eth_getBlockByHash" } -func (p *ProxyETHGetBlockByHash) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHGetBlockByHash) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { req := new(eth.GetBlockByHashRequest) if err := unmarshalRequest(rawreq.Params, req); err != nil { // TODO: Correct error code? @@ -41,8 +43,8 @@ func (p *ProxyETHGetBlockByHash) Request(rawreq *eth.JSONRPCRequest, c echo.Cont req.BlockHash = utils.RemoveHexPrefix(req.BlockHash) resultChan := make(chan *eth.GetBlockByHashResponse, 2) - errorChan := make(chan eth.JSONRPCError, 1) - qtumBlockErrorChan := make(chan error, 1) + errorChan := make(chan *eth.JSONRPCError, 1) + kaonBlockErrorChan := make(chan error, 1) ctx, cancelFunc := context.WithCancel(context.Background()) defer cancelFunc() @@ -57,28 +59,28 @@ func (p *ProxyETHGetBlockByHash) Request(rawreq *eth.JSONRPCRequest, c echo.Cont }() if bh == nil { - qtumBlockErrorChan <- ErrBlockHashNotConfigured + kaonBlockErrorChan <- ErrBlockHashNotConfigured } else { go func() { - qtumBlockHash, err := bh.GetQtumBlockHashContext(ctx, req.BlockHash) + kaonBlockHash, err := bh.GetKaonBlockHashContext(ctx, req.BlockHash) if err != nil { - qtumBlockErrorChan <- err + kaonBlockErrorChan <- err return } - if qtumBlockHash == nil { - qtumBlockErrorChan <- ErrBlockHashUnknown + if kaonBlockHash == nil { + kaonBlockErrorChan <- ErrBlockHashUnknown return } request := ð.GetBlockByHashRequest{ - BlockHash: utils.RemoveHexPrefix(*qtumBlockHash), + BlockHash: utils.RemoveHexPrefix(*kaonBlockHash), FullTransaction: req.FullTransaction, } result, jsonErr := p.request(ctx, request) if jsonErr != nil { - qtumBlockErrorChan <- jsonErr.Error() + kaonBlockErrorChan <- jsonErr.Error() return } @@ -94,7 +96,7 @@ func (p *ProxyETHGetBlockByHash) Request(rawreq *eth.JSONRPCRequest, c echo.Cont case result := <-resultChan: // backup succeeded return result, nil - case <-qtumBlockErrorChan: + case <-kaonBlockErrorChan: // backup failed, return original request return nil, nil } @@ -107,17 +109,17 @@ func (p *ProxyETHGetBlockByHash) Request(rawreq *eth.JSONRPCRequest, c echo.Cont case result := <-resultChan: // backup succeeded return result, nil - case <-qtumBlockErrorChan: + case <-kaonBlockErrorChan: // backup failed, return original request return nil, err } } } -func (p *ProxyETHGetBlockByHash) request(ctx context.Context, req *eth.GetBlockByHashRequest) (*eth.GetBlockByHashResponse, eth.JSONRPCError) { +func (p *ProxyETHGetBlockByHash) request(ctx context.Context, req *eth.GetBlockByHashRequest) (*eth.GetBlockByHashResponse, *eth.JSONRPCError) { blockHeader, err := p.GetBlockHeader(ctx, req.BlockHash) if err != nil { - if err == qtum.ErrInvalidAddress { + if err == kaon.ErrInvalidAddress { // unknown block hash should return {result: null} p.GetDebugLogger().Log("msg", "Unknown block hash", "blockHash", req.BlockHash) return nil, nil @@ -125,7 +127,7 @@ func (p *ProxyETHGetBlockByHash) request(ctx context.Context, req *eth.GetBlockB p.GetDebugLogger().Log("msg", "couldn't get block header", "blockHash", req.BlockHash) return nil, eth.NewCallbackError("couldn't get block header") } - block, err := p.GetBlock(ctx, req.BlockHash) + block, err := p.GetBlock(ctx, req.BlockHash, req.FullTransaction) if err != nil { p.GetDebugLogger().Log("msg", "couldn't get block", "blockHash", req.BlockHash) return nil, eth.NewCallbackError("couldn't get block") @@ -136,7 +138,7 @@ func (p *ProxyETHGetBlockByHash) request(ctx context.Context, req *eth.GetBlockB resp := ð.GetBlockByHashResponse{ // TODO: researching // * If ETH block has pending status, then the following values must be null - // ? Is it possible case for Qtum + // ? Is it possible case for Kaon Hash: utils.AddHexPrefix(req.BlockHash), Number: hexutil.EncodeUint64(uint64(block.Height)), @@ -180,63 +182,119 @@ func (p *ProxyETHGetBlockByHash) request(ctx context.Context, req *eth.GetBlockB if blockHeader.IsGenesisBlock() { resp.ParentHash = "0x0000000000000000000000000000000000000000000000000000000000000000" - resp.Miner = utils.AddHexPrefix(qtum.ZeroAddress) + resp.Miner = utils.AddHexPrefix(kaon.ZeroAddress) } else { resp.ParentHash = utils.AddHexPrefix(blockHeader.Previousblockhash) // ! Not found - // - // NOTE: - // In order to find a miner it seems, that we have to check - // address field of the txout method response. Current - // suggestion is to fill this field with zeros, not to - // spend much time on requests execution - // - // TODO: check if it's value is acquirable via logs - resp.Miner = "0x0000000000000000000000000000000000000000" + + if blockHeader.Proposer == "" { + resp.Miner = utils.AddHexPrefix(kaon.ZeroAddress) + } else { + resp.Miner = utils.AddHexPrefix(blockHeader.Proposer) + } } - // TODO: rethink later - // ! Found only for contracts transactions - // As there is no gas values presented at common block info, we set - // gas limit value equalling to default gas limit of a block - resp.GasLimit = utils.AddHexPrefix(qtum.DefaultBlockGasLimit) - resp.GasUsed = "0x0" + resp.GasLimit = utils.AddHexPrefix(kaon.DefaultBlockGasLimit) + resp.GasUsed = utils.AddHexPrefix(blockHeader.GasUsed.String()) - // TODO: Future improvement: If getBlock is called with verbosity 2 it also returns full tx info as if getRawTransaction was called for each, - // so using that from the start instead of requesting each tx individually as done here would save a lot of back-and-forth + var cumulativeGas *big.Int = big.NewInt(0) if req.FullTransaction { - for _, txHash := range block.Txs { - tx, err := getTransactionByHash(ctx, p.Qtum, txHash) - if err != nil { - p.GetDebugLogger().Log("msg", "Couldn't get transaction by hash", "hash", txHash, "err", err) - return nil, eth.NewCallbackError("couldn't get transaction by hash") - } - if tx == nil { - if block.Height == 0 { - // Error Invalid address - The genesis block coinbase is not considered an ordinary transaction and cannot be retrieved - // the coinbase we can ignore since its not a real transaction, mainnet ethereum also doesn't return any data about the genesis coinbase - p.GetDebugLogger().Log("msg", "Failed to get transaction in genesis block, probably the coinbase which we can't get") - } else { - p.GetDebugLogger().Log("msg", "Failed to get transaction by hash included in a block", "hash", txHash) - if !p.GetFlagBool(qtum.FLAG_IGNORE_UNKNOWN_TX) { - return nil, eth.NewCallbackError("couldn't get transaction by hash included in a block") + for i, txHash := range block.Txs { + switch txData := txHash.(type) { + case string: + // Fallback to legacy trx processingg + tx, err := getTransactionByHashKAON(ctx, p.Kaon, txData) + if err != nil { + p.GetDebugLogger().Log("msg", "Couldn't get transaction by hash", "hash", txData, "err", err) + return nil, eth.NewCallbackError("couldn't get transaction by hash") + } + if tx == nil { + if block.Height == 0 { + // Error Invalid address - The genesis block coinbase is not considered an ordinary transaction and cannot be retrieved + // the coinbase we can ignore since its not a real transaction, mainnet ethereum also doesn't return any data about the genesis coinbase + p.GetDebugLogger().Log("msg", "Failed to get transaction in genesis block, probably the coinbase which we can't get") + } else { + p.GetDebugLogger().Log("msg", "Failed to get transaction by hash included in a block", "hash", txData) + if !p.GetFlagBool(kaon.FLAG_IGNORE_UNKNOWN_TX) { + return nil, eth.NewCallbackError("couldn't get transaction by hash included in a block") + } } + } else { + resp.Transactions = append(resp.Transactions, *tx) + } + case *kaon.BlockTransactionDetails: + var ethTx *eth.GetTransactionByHashResponse + tx, err := formatTransactionInternal(ctx, p.Kaon, txData, block.Height, i, ethTx) + if err != nil { + p.GetDebugLogger().Log("msg", "Couldn't get transaction by hash", "hash", txData, "err", err) + return nil, eth.NewCallbackError("couldn't get transaction by hash") } - } else { + + tx.GasUsed = tx.Gas // TODO + tx.CumulativeGas = utils.AddHexPrefix(hexutil.EncodeBig(cumulativeGas)) + var newValue *big.Int + newValue, _ = hexutil.DecodeBig(tx.Gas) + cumulativeGas = new(big.Int).Add(cumulativeGas, newValue) + resp.Transactions = append(resp.Transactions, *tx) + + default: + + // Create variables for potential responses + var ethTxData kaon.BlockTransactionDetails + + // Try to unmarshal the response data into each potential response type + err := json.Unmarshal([]byte(marshalToString(txData)), ðTxData) + if err != nil { + p.GetDebugLogger().Log("msg", "Couldn't get transaction by hash", "hash", txData, "err", err) + continue + // return nil, eth.NewCallbackError("couldn't get transaction by hash") + } + + var ethTx *eth.GetTransactionByHashResponse + tx, serr := formatTransactionInternal(ctx, p.Kaon, ðTxData, block.Height, i, ethTx) + if serr != nil { + p.GetDebugLogger().Log("msg", "Couldn't get transaction by hash", "hash", ethTxData.ID, "err", serr.Message()) + continue + // return nil, eth.NewCallbackError("couldn't get transaction by hash") + } + + tx.GasUsed = tx.Gas // TODO + tx.CumulativeGas = utils.AddHexPrefix(hexutil.EncodeBig(cumulativeGas)) + var newValue *big.Int + newValue, _ = hexutil.DecodeBig(tx.Gas) + cumulativeGas = new(big.Int).Add(cumulativeGas, newValue) + + resp.Transactions = append(resp.Transactions, *tx) + } - // TODO: fill gas used - // TODO: fill gas limit? + resp.GasLimit = utils.AddHexPrefix(kaon.DefaultBlockGasLimit) // TODO: replace by dynamic + resp.GasUsed = utils.AddHexPrefix(blockHeader.GasUsed.String()) } } else { for _, txHash := range block.Txs { - // NOTE: - // Etherium RPC API doc says, that tx hashes must be of [32]byte, - // however it doesn't seem to be correct, 'cause Etherium tx hash - // has [64]byte just like Qtum tx hash has. In this case we do no - // additional convertations now, while everything works fine - resp.Transactions = append(resp.Transactions, utils.AddHexPrefix(txHash)) + switch txData := txHash.(type) { + case string: + // NOTE: + // Etherium RPC API doc says, that tx hashes must be of [32]byte, + // however it doesn't seem to be correct, 'cause Etherium tx hash + // has [64]byte just like Kaon tx hash has. In this case we do no + // additional convertations now, while everything works fine + resp.Transactions = append(resp.Transactions, utils.AddHexPrefix(txData)) + default: + // Create variables for potential responses + var ethTxData kaon.BlockTransactionDetails + + // Try to unmarshal the response data into each potential response type + err := json.Unmarshal([]byte(marshalToString(txData)), ðTxData) + if err != nil { + p.GetDebugLogger().Log("msg", "Couldn't get transaction by hash", "hash", txData, "err", err) + continue + // return nil, eth.NewCallbackError("couldn't get transaction by hash") + } + resp.Transactions = append(resp.Transactions, utils.AddHexPrefix(ethTxData.ID)) + } } } diff --git a/pkg/transformer/eth_getBlockByHash_test.go b/pkg/transformer/eth_getBlockByHash_test.go index c365ae28..37185dc3 100644 --- a/pkg/transformer/eth_getBlockByHash_test.go +++ b/pkg/transformer/eth_getBlockByHash_test.go @@ -4,13 +4,13 @@ import ( "encoding/json" "testing" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" - "github.com/qtumproject/janus/pkg/utils" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/utils" ) -func initializeProxyETHGetBlockByHash(qtumClient *qtum.Qtum) ETHProxy { - return &ProxyETHGetBlockByHash{qtumClient} +func initializeProxyETHGetBlockByHash(kaonClient *kaon.Kaon) ETHProxy { + return &ProxyETHGetBlockByHash{kaonClient} } func TestGetBlockByHashRequestNonceLength(t *testing.T) { diff --git a/pkg/transformer/eth_getBlockByNumber.go b/pkg/transformer/eth_getBlockByNumber.go index 91c7ae57..9f5efdee 100644 --- a/pkg/transformer/eth_getBlockByNumber.go +++ b/pkg/transformer/eth_getBlockByNumber.go @@ -4,21 +4,21 @@ import ( "context" "math/big" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" ) // ProxyETHGetBlockByNumber implements ETHProxy type ProxyETHGetBlockByNumber struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyETHGetBlockByNumber) Method() string { return "eth_getBlockByNumber" } -func (p *ProxyETHGetBlockByNumber) Request(rpcReq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHGetBlockByNumber) Request(rpcReq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { req := new(eth.GetBlockByNumberRequest) if err := unmarshalRequest(rpcReq.Params, req); err != nil { // TODO: Correct error code? @@ -27,15 +27,15 @@ func (p *ProxyETHGetBlockByNumber) Request(rpcReq *eth.JSONRPCRequest, c echo.Co return p.request(c.Request().Context(), req) } -func (p *ProxyETHGetBlockByNumber) request(ctx context.Context, req *eth.GetBlockByNumberRequest) (*eth.GetBlockByNumberResponse, eth.JSONRPCError) { - blockNum, err := getBlockNumberByRawParam(ctx, p.Qtum, req.BlockNumber, false) +func (p *ProxyETHGetBlockByNumber) request(ctx context.Context, req *eth.GetBlockByNumberRequest) (*eth.GetBlockByNumberResponse, *eth.JSONRPCError) { + blockNum, err := getBlockNumberByRawParam(ctx, p.Kaon, req.BlockNumber, false) if err != nil { return nil, eth.NewCallbackError("couldn't get block number by parameter") } - blockHash, jsonErr := proxyETHGetBlockByHash(ctx, p, p.Qtum, blockNum) + blockHash, jsonErr := proxyETHGetBlockByHash(ctx, p, p.Kaon, blockNum) if jsonErr != nil { - return nil, jsonErr + return nil, eth.NewInvalidParamsError(jsonErr.Message()) } if blockHash == nil { return nil, nil @@ -46,11 +46,11 @@ func (p *ProxyETHGetBlockByNumber) request(ctx context.Context, req *eth.GetBloc BlockHash: string(*blockHash), FullTransaction: req.FullTransaction, } - proxy = &ProxyETHGetBlockByHash{Qtum: p.Qtum} + proxy = &ProxyETHGetBlockByHash{Kaon: p.Kaon} ) block, jsonErr := proxy.request(ctx, getBlockByHashReq) if jsonErr != nil { - p.GetDebugLogger().Log("function", p.Method(), "msg", "couldn't get block by hash", "err", err) + p.GetDebugLogger().Log("function", p.Method(), "msg", "couldn't get block by hash", "jsonErr", jsonErr.Message()) return nil, eth.NewCallbackError("couldn't get block by hash") } if blockNum != nil { @@ -59,12 +59,13 @@ func (p *ProxyETHGetBlockByNumber) request(ctx context.Context, req *eth.GetBloc return block, nil } -// Properly handle unknown blocks -func proxyETHGetBlockByHash(ctx context.Context, p ETHProxy, q *qtum.Qtum, blockNum *big.Int) (*qtum.GetBlockHashResponse, eth.JSONRPCError) { +func proxyETHGetBlockByHash(ctx context.Context, p ETHProxy, q *kaon.Kaon, blockNum *big.Int) (*kaon.GetBlockHashResponse, *eth.JSONRPCError) { + // Attempt to get the block hash from Kaon resp, err := q.GetBlockHash(ctx, blockNum) if err != nil { - if err == qtum.ErrInvalidParameter { - // block doesn't exist, ETH rpc returns null + // Handle specific known errors + if err == kaon.ErrInvalidParameter { + // block doesn't exist; return null as per ETH RPC spec /** { "jsonrpc": "2.0", @@ -72,10 +73,25 @@ func proxyETHGetBlockByHash(ctx context.Context, p ETHProxy, q *qtum.Qtum, block "result": null } **/ - q.GetDebugLogger().Log("function", p.Method(), "request", blockNum.String(), "msg", "Unknown block") + q.GetDebugLogger().Log( + "function", p.Method(), + "request", blockNum.String(), + "msg", "Unknown block", + "error", err.Error(), + ) return nil, nil } - return nil, eth.NewCallbackError("couldn't get block hash") + + // Catch-all for any other unknown errors + q.GetDebugLogger().Log( + "function", p.Method(), + "request", blockNum.String(), + "msg", "Unexpected error occurred while getting block hash", + "error", err.Error(), + ) + return nil, eth.NewCallbackError("unexpected error: " + err.Error()) } + + // Successfully retrieved block hash return &resp, nil } diff --git a/pkg/transformer/eth_getBlockByNumber_test.go b/pkg/transformer/eth_getBlockByNumber_test.go index 20ee3004..1f320c85 100644 --- a/pkg/transformer/eth_getBlockByNumber_test.go +++ b/pkg/transformer/eth_getBlockByNumber_test.go @@ -4,13 +4,13 @@ import ( "encoding/json" "testing" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" ) -func initializeProxyETHGetBlockByNumber(qtumClient *qtum.Qtum) ETHProxy { - return &ProxyETHGetBlockByNumber{qtumClient} +func initializeProxyETHGetBlockByNumber(kaonClient *kaon.Kaon) ETHProxy { + return &ProxyETHGetBlockByNumber{kaonClient} } func TestGetBlockByNumberRequest(t *testing.T) { @@ -39,16 +39,16 @@ func TestGetBlockByNumberUnknownBlockRequest(t *testing.T) { } mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) - unknownBlockResponse := qtum.GetErrorResponse(qtum.ErrInvalidParameter) - err = mockedClientDoer.AddError(qtum.MethodGetBlockHash, unknownBlockResponse) + unknownBlockResponse := kaon.GetErrorResponse(kaon.ErrInvalidParameter) + err = mockedClientDoer.AddError(kaon.MethodGetBlockHash, unknownBlockResponse) if err != nil { t.Fatal(err) } //preparing proxy & executing request - proxyEth := ProxyETHGetBlockByNumber{qtumClient} + proxyEth := ProxyETHGetBlockByNumber{kaonClient} got, jsonErr := proxyEth.Request(request, internal.NewEchoContext()) if jsonErr != nil { t.Fatal(jsonErr) diff --git a/pkg/transformer/eth_getCode.go b/pkg/transformer/eth_getCode.go index 9b69d4c6..5c5100b3 100644 --- a/pkg/transformer/eth_getCode.go +++ b/pkg/transformer/eth_getCode.go @@ -3,22 +3,22 @@ package transformer import ( "context" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/utils" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" - "github.com/qtumproject/janus/pkg/utils" ) // ProxyETHGetCode implements ETHProxy type ProxyETHGetCode struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyETHGetCode) Method() string { return "eth_getCode" } -func (p *ProxyETHGetCode) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHGetCode) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { var req eth.GetCodeRequest if err := unmarshalRequest(rawreq.Params, &req); err != nil { // TODO: Correct error code? @@ -28,12 +28,12 @@ func (p *ProxyETHGetCode) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (i return p.request(c.Request().Context(), &req) } -func (p *ProxyETHGetCode) request(ctx context.Context, ethreq *eth.GetCodeRequest) (eth.GetCodeResponse, eth.JSONRPCError) { - qtumreq := qtum.GetAccountInfoRequest(utils.RemoveHexPrefix(ethreq.Address)) +func (p *ProxyETHGetCode) request(ctx context.Context, ethreq *eth.GetCodeRequest) (eth.GetCodeResponse, *eth.JSONRPCError) { + kaonreq := kaon.GetAccountInfoRequest(utils.RemoveHexPrefix(ethreq.Address)) - qtumresp, err := p.GetAccountInfo(ctx, &qtumreq) + kaonresp, err := p.GetAccountInfo(ctx, &kaonreq) if err != nil { - if err == qtum.ErrInvalidAddress { + if err == kaon.ErrInvalidAddress { /** // correct response for an invalid address { @@ -48,6 +48,6 @@ func (p *ProxyETHGetCode) request(ctx context.Context, ethreq *eth.GetCodeReques } } - // qtum res -> eth res - return eth.GetCodeResponse(utils.AddHexPrefix(qtumresp.Code)), nil + // kaon res -> eth res + return eth.GetCodeResponse(utils.AddHexPrefix(kaonresp.Code)), nil } diff --git a/pkg/transformer/eth_getCode_test.go b/pkg/transformer/eth_getCode_test.go index 6175378d..6c1bb38f 100644 --- a/pkg/transformer/eth_getCode_test.go +++ b/pkg/transformer/eth_getCode_test.go @@ -2,12 +2,13 @@ package transformer import ( "encoding/json" + "math/big" "testing" "github.com/btcsuite/btcutil" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" ) func TestGetAccountInfoRequest(t *testing.T) { @@ -19,7 +20,7 @@ func TestGetAccountInfoRequest(t *testing.T) { } //prepare client mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) if err != nil { t.Fatal(err) } @@ -29,22 +30,22 @@ func TestGetAccountInfoRequest(t *testing.T) { if err != nil { t.Fatal(err) } - qtumClient.Accounts = append(qtumClient.Accounts, account) + kaonClient.Accounts = append(kaonClient.Accounts, account) //prepare responses - getAccountInfoResponse := qtum.GetAccountInfoResponse{ + getAccountInfoResponse := kaon.GetAccountInfoResponse{ Address: "1e6f89d7399081b4f8f8aa1ae2805a5efff2f960", - Balance: 12431243, + Balance: *big.NewInt(12431243), // Storage json.RawMessage `json:"storage"`, Code: "606060405236156100ad576000357c0100000000000000000...", } - err = mockedClientDoer.AddResponseWithRequestID(3, qtum.MethodGetAccountInfo, getAccountInfoResponse) + err = mockedClientDoer.AddResponseWithRequestID(3, kaon.MethodGetAccountInfo, getAccountInfoResponse) if err != nil { t.Fatal(err) } //preparing proxy & executing request - proxyEth := ProxyETHGetCode{qtumClient} + proxyEth := ProxyETHGetCode{kaonClient} got, jsonErr := proxyEth.Request(requestRPC, internal.NewEchoContext()) if jsonErr != nil { t.Fatal(jsonErr) @@ -64,23 +65,23 @@ func TestGetCodeInvalidAddressRequest(t *testing.T) { } //prepare client mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) if err != nil { t.Fatal(err) } //prepare responses - getAccountInfoErrorResponse := qtum.GetErrorResponse(qtum.ErrInvalidAddress) + getAccountInfoErrorResponse := kaon.GetErrorResponse(kaon.ErrInvalidAddress) if getAccountInfoErrorResponse == nil { panic("mocked error response is nil") } - err = mockedClientDoer.AddError(qtum.MethodGetAccountInfo, getAccountInfoErrorResponse) + err = mockedClientDoer.AddError(kaon.MethodGetAccountInfo, getAccountInfoErrorResponse) if err != nil { t.Fatal(err) } //preparing proxy & executing request - proxyEth := ProxyETHGetCode{qtumClient} + proxyEth := ProxyETHGetCode{kaonClient} got, jsonErr := proxyEth.Request(requestRPC, internal.NewEchoContext()) if jsonErr != nil { t.Fatal(jsonErr) diff --git a/pkg/transformer/eth_getCompilers.go b/pkg/transformer/eth_getCompilers.go index 3ad73e9d..8cf178e4 100644 --- a/pkg/transformer/eth_getCompilers.go +++ b/pkg/transformer/eth_getCompilers.go @@ -1,8 +1,8 @@ package transformer import ( + "github.com/kaonone/eth-rpc-gate/pkg/eth" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" ) type ETHGetCompilers struct { @@ -12,7 +12,7 @@ func (p *ETHGetCompilers) Method() string { return "eth_getCompilers" } -func (p *ETHGetCompilers) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ETHGetCompilers) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { // hardcoded to empty return []string{}, nil } diff --git a/pkg/transformer/eth_getCompilers_test.go b/pkg/transformer/eth_getCompilers_test.go index f57a9b57..56c45be5 100644 --- a/pkg/transformer/eth_getCompilers_test.go +++ b/pkg/transformer/eth_getCompilers_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "testing" - "github.com/qtumproject/janus/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/internal" ) func TestGetCompilersReturnsEmptyArray(t *testing.T) { diff --git a/pkg/transformer/eth_getFilterChanges.go b/pkg/transformer/eth_getFilterChanges.go index 410d8d84..e727f50a 100644 --- a/pkg/transformer/eth_getFilterChanges.go +++ b/pkg/transformer/eth_getFilterChanges.go @@ -7,15 +7,15 @@ import ( "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/conversion" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" - "github.com/qtumproject/janus/pkg/utils" + "github.com/kaonone/eth-rpc-gate/pkg/conversion" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/utils" ) // ProxyETHGetFilterChanges implements ETHProxy type ProxyETHGetFilterChanges struct { - *qtum.Qtum + *kaon.Kaon filter *eth.FilterSimulator } @@ -23,7 +23,7 @@ func (p *ProxyETHGetFilterChanges) Method() string { return "eth_getFilterChanges" } -func (p *ProxyETHGetFilterChanges) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHGetFilterChanges) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { filter, err := processFilter(p, rawreq) if err != nil { @@ -42,18 +42,18 @@ func (p *ProxyETHGetFilterChanges) Request(rawreq *eth.JSONRPCRequest, c echo.Co } } -func (p *ProxyETHGetFilterChanges) requestBlockFilter(ctx context.Context, filter *eth.Filter) (qtumresp eth.GetFilterChangesResponse, err eth.JSONRPCError) { - qtumresp = make(eth.GetFilterChangesResponse, 0) +func (p *ProxyETHGetFilterChanges) requestBlockFilter(ctx context.Context, filter *eth.Filter) (kaonresp eth.GetFilterChangesResponse, err *eth.JSONRPCError) { + kaonresp = make(eth.GetFilterChangesResponse, 0) _lastBlockNumber, ok := filter.Data.Load("lastBlockNumber") if !ok { - return qtumresp, eth.NewCallbackError("Could not get lastBlockNumber") + return kaonresp, eth.NewCallbackError("Could not get lastBlockNumber") } lastBlockNumber := _lastBlockNumber.(uint64) blockCountBigInt, blockErr := p.GetBlockCount(ctx) if blockErr != nil { - return qtumresp, eth.NewCallbackError(blockErr.Error()) + return kaonresp, eth.NewCallbackError(blockErr.Error()) } blockCount := blockCountBigInt.Uint64() @@ -65,29 +65,29 @@ func (p *ProxyETHGetFilterChanges) requestBlockFilter(ctx context.Context, filte resp, err := p.GetBlockHash(ctx, blockNumber) if err != nil { - return qtumresp, eth.NewCallbackError(err.Error()) + return kaonresp, eth.NewCallbackError(err.Error()) } hashes[i] = utils.AddHexPrefix(string(resp)) } - qtumresp = hashes + kaonresp = hashes filter.Data.Store("lastBlockNumber", blockCount) return } -func (p *ProxyETHGetFilterChanges) requestFilter(ctx context.Context, filter *eth.Filter) (qtumresp eth.GetFilterChangesResponse, err eth.JSONRPCError) { - qtumresp = make(eth.GetFilterChangesResponse, 0) +func (p *ProxyETHGetFilterChanges) requestFilter(ctx context.Context, filter *eth.Filter) (kaonresp eth.GetFilterChangesResponse, err *eth.JSONRPCError) { + kaonresp = make(eth.GetFilterChangesResponse, 0) _lastBlockNumber, ok := filter.Data.Load("lastBlockNumber") if !ok { - return qtumresp, eth.NewCallbackError("Could not get lastBlockNumber") + return kaonresp, eth.NewCallbackError("Could not get lastBlockNumber") } lastBlockNumber := _lastBlockNumber.(uint64) blockCountBigInt, blockErr := p.GetBlockCount(ctx) if blockErr != nil { - return qtumresp, eth.NewCallbackError(blockErr.Error()) + return kaonresp, eth.NewCallbackError(blockErr.Error()) } blockCount := blockCountBigInt.Uint64() @@ -105,13 +105,13 @@ func (p *ProxyETHGetFilterChanges) requestFilter(ctx context.Context, filter *et return p.doSearchLogs(ctx, searchLogsReq) } -func (p *ProxyETHGetFilterChanges) doSearchLogs(ctx context.Context, req *qtum.SearchLogsRequest) (eth.GetFilterChangesResponse, eth.JSONRPCError) { - resp, err := conversion.SearchLogsAndFilterExtraTopics(ctx, p.Qtum, req) +func (p *ProxyETHGetFilterChanges) doSearchLogs(ctx context.Context, req *kaon.SearchLogsRequest) (eth.GetFilterChangesResponse, *eth.JSONRPCError) { + resp, err := conversion.SearchLogsAndFilterExtraTopics(ctx, p.Kaon, req) if err != nil { return nil, err } - receiptToResult := func(receipt *qtum.TransactionReceipt) []interface{} { + receiptToResult := func(receipt *kaon.TransactionReceipt) []interface{} { logs := conversion.ExtractETHLogsFromTransactionReceipt(receipt, receipt.Log) res := make([]interface{}, len(logs)) for i := range res { @@ -121,14 +121,14 @@ func (p *ProxyETHGetFilterChanges) doSearchLogs(ctx context.Context, req *qtum.S } results := make(eth.GetFilterChangesResponse, 0) for _, receipt := range resp { - r := qtum.TransactionReceipt(receipt) + r := kaon.TransactionReceipt(receipt) results = append(results, receiptToResult(&r)...) } return results, nil } -func (p *ProxyETHGetFilterChanges) toSearchLogsReq(filter *eth.Filter, from, to *big.Int) (*qtum.SearchLogsRequest, eth.JSONRPCError) { +func (p *ProxyETHGetFilterChanges) toSearchLogsReq(filter *eth.Filter, from, to *big.Int) (*kaon.SearchLogsRequest, *eth.JSONRPCError) { ethreq := filter.Request.(*eth.NewFilterRequest) var err error var addresses []string @@ -151,7 +151,7 @@ func (p *ProxyETHGetFilterChanges) toSearchLogsReq(filter *eth.Filter, from, to } } - qtumreq := &qtum.SearchLogsRequest{ + kaonreq := &kaon.SearchLogsRequest{ Addresses: addresses, FromBlock: from, ToBlock: to, @@ -159,8 +159,8 @@ func (p *ProxyETHGetFilterChanges) toSearchLogsReq(filter *eth.Filter, from, to topics, ok := filter.Data.Load("topics") if ok { - qtumreq.Topics = topics.([]qtum.SearchLogsTopic) + kaonreq.Topics = topics.([]kaon.SearchLogsTopic) } - return qtumreq, nil + return kaonreq, nil } diff --git a/pkg/transformer/eth_getFilterChanges_test.go b/pkg/transformer/eth_getFilterChanges_test.go index 40920851..8c5397d0 100644 --- a/pkg/transformer/eth_getFilterChanges_test.go +++ b/pkg/transformer/eth_getFilterChanges_test.go @@ -5,9 +5,9 @@ import ( "math/big" "testing" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" ) func TestGetFilterChangesRequest_EmptyResult(t *testing.T) { @@ -19,22 +19,22 @@ func TestGetFilterChangesRequest_EmptyResult(t *testing.T) { } //prepare client mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) if err != nil { t.Fatal(err) } //preparing client response - getBlockCountResponse := qtum.GetBlockCountResponse{Int: big.NewInt(657660)} - err = mockedClientDoer.AddResponseWithRequestID(2, qtum.MethodGetBlockCount, getBlockCountResponse) + getBlockCountResponse := kaon.GetBlockCountResponse{Int: big.NewInt(657660)} + err = mockedClientDoer.AddResponseWithRequestID(2, kaon.MethodGetBlockCount, getBlockCountResponse) if err != nil { t.Fatal(err) } - searchLogsResponse := qtum.SearchLogsResponse{ + searchLogsResponse := kaon.SearchLogsResponse{ //TODO: add } - err = mockedClientDoer.AddResponseWithRequestID(2, qtum.MethodSearchLogs, searchLogsResponse) + err = mockedClientDoer.AddResponseWithRequestID(2, kaon.MethodSearchLogs, searchLogsResponse) if err != nil { t.Fatal(err) } @@ -48,7 +48,7 @@ func TestGetFilterChangesRequest_EmptyResult(t *testing.T) { filter.Data.Store("lastBlockNumber", uint64(657655)) //preparing proxy & executing request - proxyEth := ProxyETHGetFilterChanges{qtumClient, filterSimulator} + proxyEth := ProxyETHGetFilterChanges{kaonClient, filterSimulator} got, jsonErr := proxyEth.Request(requestRPC, internal.NewEchoContext()) if jsonErr != nil { t.Fatal(jsonErr) @@ -68,14 +68,14 @@ func TestGetFilterChangesRequest_NoNewBlocks(t *testing.T) { } //prepare client mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) if err != nil { t.Fatal(err) } //preparing client response - getBlockCountResponse := qtum.GetBlockCountResponse{Int: big.NewInt(657655)} - err = mockedClientDoer.AddResponseWithRequestID(2, qtum.MethodGetBlockCount, getBlockCountResponse) + getBlockCountResponse := kaon.GetBlockCountResponse{Int: big.NewInt(657655)} + err = mockedClientDoer.AddResponseWithRequestID(2, kaon.MethodGetBlockCount, getBlockCountResponse) if err != nil { t.Fatal(err) } @@ -88,7 +88,7 @@ func TestGetFilterChangesRequest_NoNewBlocks(t *testing.T) { filter.Data.Store("lastBlockNumber", uint64(657655)) //preparing proxy & executing request - proxyEth := ProxyETHGetFilterChanges{qtumClient, filterSimulator} + proxyEth := ProxyETHGetFilterChanges{kaonClient, filterSimulator} got, jsonErr := proxyEth.Request(requestRPC, internal.NewEchoContext()) if jsonErr != nil { t.Fatal(jsonErr) @@ -108,14 +108,14 @@ func TestGetFilterChangesRequest_NoSuchFilter(t *testing.T) { } //prepare client mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) if err != nil { t.Fatal(err) } //preparing proxy & executing request filterSimulator := eth.NewFilterSimulator() - proxyEth := ProxyETHGetFilterChanges{qtumClient, filterSimulator} + proxyEth := ProxyETHGetFilterChanges{kaonClient, filterSimulator} _, got := proxyEth.Request(requestRPC, internal.NewEchoContext()) want := eth.NewCallbackError("Invalid filter id") diff --git a/pkg/transformer/eth_getFilterLogs.go b/pkg/transformer/eth_getFilterLogs.go index 27afc0ed..e93ff17a 100644 --- a/pkg/transformer/eth_getFilterLogs.go +++ b/pkg/transformer/eth_getFilterLogs.go @@ -4,8 +4,8 @@ import ( "context" "math/big" + "github.com/kaonone/eth-rpc-gate/pkg/eth" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" ) // ProxyETHGetFilterLogs implements ETHProxy @@ -17,7 +17,7 @@ func (p *ProxyETHGetFilterLogs) Method() string { return "eth_getFilterLogs" } -func (p *ProxyETHGetFilterLogs) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHGetFilterLogs) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { filter, err := processFilter(p.ProxyETHGetFilterChanges, rawreq) if err != nil { @@ -32,18 +32,18 @@ func (p *ProxyETHGetFilterLogs) Request(rawreq *eth.JSONRPCRequest, c echo.Conte } } -func (p *ProxyETHGetFilterLogs) request(ctx context.Context, filter *eth.Filter) (qtumresp eth.GetFilterChangesResponse, err eth.JSONRPCError) { - qtumresp = make(eth.GetFilterChangesResponse, 0) +func (p *ProxyETHGetFilterLogs) request(ctx context.Context, filter *eth.Filter) (kaonresp eth.GetFilterChangesResponse, err *eth.JSONRPCError) { + kaonresp = make(eth.GetFilterChangesResponse, 0) _lastBlockNumber, ok := filter.Data.Load("lastBlockNumber") if !ok { - return qtumresp, eth.NewCallbackError("Could not get lastBlockNumber") + return kaonresp, eth.NewCallbackError("Could not get lastBlockNumber") } lastBlockNumber := _lastBlockNumber.(uint64) _toBlock, ok := filter.Data.Load("toBlock") if !ok { - return qtumresp, eth.NewCallbackError("Could not get toBlock") + return kaonresp, eth.NewCallbackError("Could not get toBlock") } toBlock := _toBlock.(uint64) diff --git a/pkg/transformer/eth_getLogs.go b/pkg/transformer/eth_getLogs.go index c7bbc381..d9557b45 100644 --- a/pkg/transformer/eth_getLogs.go +++ b/pkg/transformer/eth_getLogs.go @@ -4,23 +4,23 @@ import ( "context" "encoding/json" + "github.com/kaonone/eth-rpc-gate/pkg/conversion" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/utils" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/conversion" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" - "github.com/qtumproject/janus/pkg/utils" ) // ProxyETHGetLogs implements ETHProxy type ProxyETHGetLogs struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyETHGetLogs) Method() string { return "eth_getLogs" } -func (p *ProxyETHGetLogs) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHGetLogs) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { var req eth.GetLogsRequest if err := unmarshalRequest(rawreq.Params, &req); err != nil { // TODO: Correct error code? @@ -32,24 +32,24 @@ func (p *ProxyETHGetLogs) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (i // return nil, errors.New("topics is not supported yet") // } - // Calls ToRequest in order transform ETH-Request to a Qtum-Request - qtumreq, err := p.ToRequest(c.Request().Context(), &req) + // Calls ToRequest in order transform ETH-Request to a Kaon-Request + kaonreq, err := p.ToRequest(c.Request().Context(), &req) if err != nil { return nil, err } - return p.request(c.Request().Context(), qtumreq) + return p.request(c.Request().Context(), kaonreq) } -func (p *ProxyETHGetLogs) request(ctx context.Context, req *qtum.SearchLogsRequest) (*eth.GetLogsResponse, eth.JSONRPCError) { - receipts, err := conversion.SearchLogsAndFilterExtraTopics(ctx, p.Qtum, req) +func (p *ProxyETHGetLogs) request(ctx context.Context, req *kaon.SearchLogsRequest) (*eth.GetLogsResponse, *eth.JSONRPCError) { + receipts, err := conversion.SearchLogsAndFilterExtraTopics(ctx, p.Kaon, req) if err != nil { return nil, err } logs := make([]eth.Log, 0) for _, receipt := range receipts { - r := qtum.TransactionReceipt(receipt) + r := kaon.TransactionReceipt(receipt) logs = append(logs, conversion.ExtractETHLogsFromTransactionReceipt(r, r.Log)...) } @@ -57,20 +57,20 @@ func (p *ProxyETHGetLogs) request(ctx context.Context, req *qtum.SearchLogsReque return &resp, nil } -func (p *ProxyETHGetLogs) ToRequest(ctx context.Context, ethreq *eth.GetLogsRequest) (*qtum.SearchLogsRequest, eth.JSONRPCError) { - //transform EthRequest fromBlock to QtumReq fromBlock: - from, err := getBlockNumberByRawParam(ctx, p.Qtum, ethreq.FromBlock, true) +func (p *ProxyETHGetLogs) ToRequest(ctx context.Context, ethreq *eth.GetLogsRequest) (*kaon.SearchLogsRequest, *eth.JSONRPCError) { + //transform EthRequest fromBlock to KaonReq fromBlock: + from, err := getBlockNumberByRawParam(ctx, p.Kaon, ethreq.FromBlock, true) if err != nil { return nil, err } - //transform EthRequest toBlock to QtumReq toBlock: - to, err := getBlockNumberByRawParam(ctx, p.Qtum, ethreq.ToBlock, true) + //transform EthRequest toBlock to KaonReq toBlock: + to, err := getBlockNumberByRawParam(ctx, p.Kaon, ethreq.ToBlock, true) if err != nil { return nil, err } - //transform EthReq address to QtumReq address: + //transform EthReq address to KaonReq address: var addresses []string if ethreq.Address != nil { if isBytesOfString(ethreq.Address) { @@ -89,16 +89,16 @@ func (p *ProxyETHGetLogs) ToRequest(ctx context.Context, ethreq *eth.GetLogsRequ } } - //transform EthReq topics to QtumReq topics: + //transform EthReq topics to KaonReq topics: topics, topicsErr := eth.TranslateTopics(ethreq.Topics) if topicsErr != nil { return nil, eth.NewCallbackError(topicsErr.Error()) } - return &qtum.SearchLogsRequest{ + return &kaon.SearchLogsRequest{ Addresses: addresses, FromBlock: from, ToBlock: to, - Topics: qtum.NewSearchLogsTopics(topics), + Topics: kaon.NewSearchLogsTopics(topics), }, nil } diff --git a/pkg/transformer/eth_getLogs_test.go b/pkg/transformer/eth_getLogs_test.go index fc87a0f9..eee19216 100644 --- a/pkg/transformer/eth_getLogs_test.go +++ b/pkg/transformer/eth_getLogs_test.go @@ -3,11 +3,12 @@ package transformer import ( "context" "encoding/json" + "math/big" "testing" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" ) func TestGetLogs(t *testing.T) { @@ -252,17 +253,17 @@ func TestMultipleLogsWithORdTopics(t *testing.T) { } clientDoerMock := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(clientDoerMock) + kaonClient, err := internal.CreateMockedClient(clientDoerMock) if err != nil { t.Fatal(err) } //Add response - clientDoerMock.AddRawResponse(qtum.MethodSearchLogs, []byte(rawResponse)) + clientDoerMock.AddRawResponse(kaon.MethodSearchLogs, []byte(rawResponse)) //Prepare proxy & execute //preparing proxy & executing - proxyEth := ProxyETHGetLogs{qtumClient} + proxyEth := ProxyETHGetLogs{kaonClient} got, jsonErr := proxyEth.Request(requestRPC, internal.NewEchoContext()) if jsonErr != nil { @@ -353,12 +354,12 @@ func testGetLogsWithTopics(t *testing.T, topics []interface{}, want eth.GetLogsR } clientDoerMock := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(clientDoerMock) + kaonClient, err := internal.CreateMockedClient(clientDoerMock) if err != nil { t.Fatal(err) } //prepare response - searchLogsResponse := qtum.SearchLogsResponse{ + searchLogsResponse := kaon.SearchLogsResponse{ { BlockHash: "975326b65c20d0b8500f00a59f76b08a98513fff7ce0484382534a47b55f8985", BlockNumber: 4063, @@ -366,10 +367,10 @@ func testGetLogsWithTopics(t *testing.T, topics []interface{}, want eth.GetLogsR TransactionIndex: 2, From: "6b22910b1e302cf74803ffd1691c2ecb858d3712", To: "db46f738bf32cdafb9a4a70eb8b44c76646bcaf0", - CumulativeGasUsed: 68572, - GasUsed: 68572, + CumulativeGasUsed: *big.NewInt(685720), + GasUsed: *big.NewInt(685720), ContractAddress: "db46f738bf32cdafb9a4a70eb8b44c76646bcaf0", - Log: []qtum.Log{ + Log: []kaon.Log{ { Address: "db46f738bf32cdafb9a4a70eb8b44c76646bcaf0", Topics: []string{ @@ -384,14 +385,14 @@ func testGetLogsWithTopics(t *testing.T, topics []interface{}, want eth.GetLogsR } //Add response - err = clientDoerMock.AddResponseWithRequestID(2, qtum.MethodSearchLogs, searchLogsResponse) + err = clientDoerMock.AddResponseWithRequestID(2, kaon.MethodSearchLogs, searchLogsResponse) if err != nil { t.Fatal(err) } //Prepare proxy & execute //preparing proxy & executing - proxyEth := ProxyETHGetLogs{qtumClient} + proxyEth := ProxyETHGetLogs{kaonClient} got, jsonErr := proxyEth.Request(requestRPC, internal.NewEchoContext()) if jsonErr != nil { @@ -428,26 +429,26 @@ func TestGetLogsTranslateTopicWorksWithNil(t *testing.T) { } clientDoerMock := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(clientDoerMock) + kaonClient, err := internal.CreateMockedClient(clientDoerMock) if err != nil { t.Fatal(err) } //Prepare proxy & execute //preparing proxy & executing - proxyEth := ProxyETHGetLogs{qtumClient} + proxyEth := ProxyETHGetLogs{kaonClient} - qtumRequest, jsonErr := proxyEth.ToRequest(context.Background(), &request) + kaonRequest, jsonErr := proxyEth.ToRequest(context.Background(), &request) if jsonErr != nil { t.Fatal(jsonErr) } - qtumRawRequest, err := json.Marshal(qtumRequest) + kaonRawRequest, err := json.Marshal(kaonRequest) if err != nil { t.Fatal(err) } expectedRawRequest := `[4062,4062,{"addresses":["db46f738bf32cdafb9a4a70eb8b44c76646bcaf0"]},{"topics":["0f6798a560793a54c3bcfe86a93cde1e73087d944c0ea20544137d4121396885",null]}]` - internal.CheckTestResultEthRequestLog(request, expectedRawRequest, string(qtumRawRequest), t, false) + internal.CheckTestResultEthRequestLog(request, expectedRawRequest, string(kaonRawRequest), t, false) } diff --git a/pkg/transformer/eth_getStorageAt.go b/pkg/transformer/eth_getStorageAt.go index aac4bee4..36eb7f50 100644 --- a/pkg/transformer/eth_getStorageAt.go +++ b/pkg/transformer/eth_getStorageAt.go @@ -4,30 +4,30 @@ import ( "context" "fmt" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/utils" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" - "github.com/qtumproject/janus/pkg/utils" ) // ProxyETHGetStorageAt implements ETHProxy type ProxyETHGetStorageAt struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyETHGetStorageAt) Method() string { return "eth_getStorageAt" } -func (p *ProxyETHGetStorageAt) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHGetStorageAt) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { var req eth.GetStorageRequest if err := unmarshalRequest(rawreq.Params, &req); err != nil { // TODO: Correct error code? return nil, eth.NewInvalidParamsError(err.Error()) } - qtumAddress := utils.RemoveHexPrefix(req.Address) - blockNumber, err := getBlockNumberByParam(c.Request().Context(), p.Qtum, req.BlockNumber, false) + kaonAddress := utils.RemoveHexPrefix(req.Address) + blockNumber, err := getBlockNumberByParam(c.Request().Context(), p.Kaon, req.BlockNumber, false) if err != nil { p.GetDebugLogger().Log("msg", fmt.Sprintf("Failed to get block number by param for '%s'", req.BlockNumber), "err", err) return nil, err @@ -35,34 +35,34 @@ func (p *ProxyETHGetStorageAt) Request(rawreq *eth.JSONRPCRequest, c echo.Contex return p.request( c.Request().Context(), - &qtum.GetStorageRequest{ - Address: qtumAddress, + &kaon.GetStorageRequest{ + Address: kaonAddress, BlockNumber: blockNumber, }, utils.RemoveHexPrefix(req.Index), ) } -func (p *ProxyETHGetStorageAt) request(ctx context.Context, ethreq *qtum.GetStorageRequest, index string) (*eth.GetStorageResponse, eth.JSONRPCError) { - qtumresp, err := p.Qtum.GetStorage(ctx, ethreq) +func (p *ProxyETHGetStorageAt) request(ctx context.Context, ethreq *kaon.GetStorageRequest, index string) (*eth.GetStorageResponse, *eth.JSONRPCError) { + kaonresp, err := p.Kaon.GetStorage(ctx, ethreq) if err != nil { return nil, eth.NewCallbackError(err.Error()) } - // qtum res -> eth res - return p.ToResponse(qtumresp, index), nil + // kaon res -> eth res + return p.ToResponse(kaonresp, index), nil } -func (p *ProxyETHGetStorageAt) ToResponse(qtumresp *qtum.GetStorageResponse, slot string) *eth.GetStorageResponse { +func (p *ProxyETHGetStorageAt) ToResponse(kaonresp *kaon.GetStorageResponse, slot string) *eth.GetStorageResponse { // the value for unknown anything storageData := eth.GetStorageResponse("0x0000000000000000000000000000000000000000000000000000000000000000") if len(slot) != 64 { slot = leftPadStringWithZerosTo64Bytes(slot) } - for _, outerValue := range *qtumresp { - qtumStorageData, ok := outerValue[slot] + for _, outerValue := range *kaonresp { + kaonStorageData, ok := outerValue[slot] if ok { - storageData = eth.GetStorageResponse(utils.AddHexPrefix(qtumStorageData)) + storageData = eth.GetStorageResponse(utils.AddHexPrefix(kaonStorageData)) return &storageData } } diff --git a/pkg/transformer/eth_getStorageAt_test.go b/pkg/transformer/eth_getStorageAt_test.go index b4c5edbb..78dc422f 100644 --- a/pkg/transformer/eth_getStorageAt_test.go +++ b/pkg/transformer/eth_getStorageAt_test.go @@ -4,9 +4,9 @@ import ( "encoding/json" "testing" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" ) func TestGetStorageAtRequestWithNoLeadingZeros(t *testing.T) { @@ -19,20 +19,20 @@ func TestGetStorageAtRequestWithNoLeadingZeros(t *testing.T) { } mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) value := "0x012341231441234123412343211234abcde12342332100000223030004005000" - getStorageResponse := qtum.GetStorageResponse{} + getStorageResponse := kaon.GetStorageResponse{} getStorageResponse[leftPadStringWithZerosTo64Bytes("12345")] = make(map[string]string) getStorageResponse[leftPadStringWithZerosTo64Bytes("12345")][leftPadStringWithZerosTo64Bytes(index)] = value - err = mockedClientDoer.AddResponseWithRequestID(2, qtum.MethodGetStorage, getStorageResponse) + err = mockedClientDoer.AddResponseWithRequestID(2, kaon.MethodGetStorage, getStorageResponse) if err != nil { t.Fatal(err) } //preparing proxy & executing request - proxyEth := ProxyETHGetStorageAt{qtumClient} + proxyEth := ProxyETHGetStorageAt{kaonClient} got, jsonErr := proxyEth.Request(request, internal.NewEchoContext()) if jsonErr != nil { t.Fatal(jsonErr) @@ -53,20 +53,20 @@ func TestGetStorageAtRequestWithLeadingZeros(t *testing.T) { } mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) value := "0x012341231441234123412343211234abcde12342332100000223030004005000" - getStorageResponse := qtum.GetStorageResponse{} + getStorageResponse := kaon.GetStorageResponse{} getStorageResponse[leftPadStringWithZerosTo64Bytes("12345")] = make(map[string]string) getStorageResponse[leftPadStringWithZerosTo64Bytes("12345")][leftPadStringWithZerosTo64Bytes(index)] = value - err = mockedClientDoer.AddResponseWithRequestID(2, qtum.MethodGetStorage, getStorageResponse) + err = mockedClientDoer.AddResponseWithRequestID(2, kaon.MethodGetStorage, getStorageResponse) if err != nil { t.Fatal(err) } //preparing proxy & executing request - proxyEth := ProxyETHGetStorageAt{qtumClient} + proxyEth := ProxyETHGetStorageAt{kaonClient} got, jsonErr := proxyEth.Request(request, internal.NewEchoContext()) if jsonErr != nil { t.Fatal(jsonErr) @@ -87,21 +87,21 @@ func TestGetStorageAtUnknownFieldRequest(t *testing.T) { } mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) unknownValue := "0x0000000000000000000000000000000000000000000000000000000000000000" value := "0x012341231441234123412343211234abcde12342332100000223030004005000" - getStorageResponse := qtum.GetStorageResponse{} + getStorageResponse := kaon.GetStorageResponse{} getStorageResponse[leftPadStringWithZerosTo64Bytes("12345")] = make(map[string]string) getStorageResponse[leftPadStringWithZerosTo64Bytes("12345")][leftPadStringWithZerosTo64Bytes(index)] = value - err = mockedClientDoer.AddResponseWithRequestID(2, qtum.MethodGetStorage, getStorageResponse) + err = mockedClientDoer.AddResponseWithRequestID(2, kaon.MethodGetStorage, getStorageResponse) if err != nil { t.Fatal(err) } //preparing proxy & executing request - proxyEth := ProxyETHGetStorageAt{qtumClient} + proxyEth := ProxyETHGetStorageAt{kaonClient} got, jsonErr := proxyEth.Request(request, internal.NewEchoContext()) if jsonErr != nil { t.Fatal(jsonErr) diff --git a/pkg/transformer/eth_getTransactionByBlockHashAndIndex.go b/pkg/transformer/eth_getTransactionByBlockHashAndIndex.go index fb2654ff..eb8fc479 100644 --- a/pkg/transformer/eth_getTransactionByBlockHashAndIndex.go +++ b/pkg/transformer/eth_getTransactionByBlockHashAndIndex.go @@ -5,21 +5,21 @@ import ( "encoding/json" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" ) // ProxyETHGetTransactionByBlockHashAndIndex implements ETHProxy type ProxyETHGetTransactionByBlockHashAndIndex struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyETHGetTransactionByBlockHashAndIndex) Method() string { return "eth_getTransactionByBlockHashAndIndex" } -func (p *ProxyETHGetTransactionByBlockHashAndIndex) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHGetTransactionByBlockHashAndIndex) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { var req eth.GetTransactionByBlockHashAndIndex if err := json.Unmarshal(rawreq.Params, &req); err != nil { // TODO: Correct error code? @@ -33,7 +33,7 @@ func (p *ProxyETHGetTransactionByBlockHashAndIndex) Request(rawreq *eth.JSONRPCR return p.request(c.Request().Context(), &req) } -func (p *ProxyETHGetTransactionByBlockHashAndIndex) request(ctx context.Context, req *eth.GetTransactionByBlockHashAndIndex) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHGetTransactionByBlockHashAndIndex) request(ctx context.Context, req *eth.GetTransactionByBlockHashAndIndex) (interface{}, *eth.JSONRPCError) { transactionIndex, err := hexutil.DecodeUint64(req.TransactionIndex) if err != nil { // TODO: Correct error code? @@ -41,7 +41,7 @@ func (p *ProxyETHGetTransactionByBlockHashAndIndex) request(ctx context.Context, } // Proxy eth_getBlockByHash and return the transaction at requested index - getBlockByNumber := ProxyETHGetBlockByHash{p.Qtum} + getBlockByNumber := ProxyETHGetBlockByHash{p.Kaon} blockByNumber, jsonErr := getBlockByNumber.request(ctx, ð.GetBlockByHashRequest{BlockHash: req.BlockHash, FullTransaction: true}) if jsonErr != nil { diff --git a/pkg/transformer/eth_getTransactionByBlockHashAndIndex_test.go b/pkg/transformer/eth_getTransactionByBlockHashAndIndex_test.go index 83779f65..cf1e51d0 100644 --- a/pkg/transformer/eth_getTransactionByBlockHashAndIndex_test.go +++ b/pkg/transformer/eth_getTransactionByBlockHashAndIndex_test.go @@ -4,12 +4,12 @@ import ( "encoding/json" "testing" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" ) -func initializeProxyETHGetTransactionByBlockHashAndIndex(qtumClient *qtum.Qtum) ETHProxy { - return &ProxyETHGetTransactionByBlockHashAndIndex{qtumClient} +func initializeProxyETHGetTransactionByBlockHashAndIndex(kaonClient *kaon.Kaon) ETHProxy { + return &ProxyETHGetTransactionByBlockHashAndIndex{kaonClient} } func TestGetTransactionByBlockHashAndIndex(t *testing.T) { diff --git a/pkg/transformer/eth_getTransactionByBlockNumberAndIndex.go b/pkg/transformer/eth_getTransactionByBlockNumberAndIndex.go index 62de4a40..1d59eb62 100644 --- a/pkg/transformer/eth_getTransactionByBlockNumberAndIndex.go +++ b/pkg/transformer/eth_getTransactionByBlockNumberAndIndex.go @@ -5,21 +5,21 @@ import ( "encoding/json" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" ) // ProxyETHGetTransactionByBlockNumberAndIndex implements ETHProxy type ProxyETHGetTransactionByBlockNumberAndIndex struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyETHGetTransactionByBlockNumberAndIndex) Method() string { return "eth_getTransactionByBlockNumberAndIndex" } -func (p *ProxyETHGetTransactionByBlockNumberAndIndex) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHGetTransactionByBlockNumberAndIndex) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { var req eth.GetTransactionByBlockNumberAndIndex if err := json.Unmarshal(rawreq.Params, &req); err != nil { // TODO: Correct error code? @@ -33,19 +33,19 @@ func (p *ProxyETHGetTransactionByBlockNumberAndIndex) Request(rawreq *eth.JSONRP return p.request(c.Request().Context(), &req) } -func (p *ProxyETHGetTransactionByBlockNumberAndIndex) request(ctx context.Context, req *eth.GetTransactionByBlockNumberAndIndex) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHGetTransactionByBlockNumberAndIndex) request(ctx context.Context, req *eth.GetTransactionByBlockNumberAndIndex) (interface{}, *eth.JSONRPCError) { // Decoded by ProxyETHGetTransactionByBlockHashAndIndex, quickly decode so we can fail cheaply without making any calls _, decodeErr := hexutil.DecodeUint64(req.TransactionIndex) if decodeErr != nil { return nil, eth.NewInvalidParamsError("invalid argument 1") } - blockNum, err := getBlockNumberByParam(ctx, p.Qtum, req.BlockNumber, false) + blockNum, err := getBlockNumberByParam(ctx, p.Kaon, req.BlockNumber, false) if err != nil { return nil, eth.NewCallbackError("couldn't get block number by parameter") } - blockHash, err := proxyETHGetBlockByHash(ctx, p, p.Qtum, blockNum) + blockHash, err := proxyETHGetBlockByHash(ctx, p, p.Kaon, blockNum) if err != nil { return nil, err } @@ -58,7 +58,7 @@ func (p *ProxyETHGetTransactionByBlockNumberAndIndex) request(ctx context.Contex BlockHash: string(*blockHash), TransactionIndex: req.TransactionIndex, } - proxy = &ProxyETHGetTransactionByBlockHashAndIndex{Qtum: p.Qtum} + proxy = &ProxyETHGetTransactionByBlockHashAndIndex{Kaon: p.Kaon} ) return proxy.request(ctx, getBlockByHashReq) } diff --git a/pkg/transformer/eth_getTransactionByBlockNumberAndIndex_test.go b/pkg/transformer/eth_getTransactionByBlockNumberAndIndex_test.go index 3a5e216e..98e9d85f 100644 --- a/pkg/transformer/eth_getTransactionByBlockNumberAndIndex_test.go +++ b/pkg/transformer/eth_getTransactionByBlockNumberAndIndex_test.go @@ -4,12 +4,12 @@ import ( "encoding/json" "testing" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" ) -func initializeProxyETHGetTransactionByBlockNumberAndIndex(qtumClient *qtum.Qtum) ETHProxy { - return &ProxyETHGetTransactionByBlockNumberAndIndex{qtumClient} +func initializeProxyETHGetTransactionByBlockNumberAndIndex(kaonClient *kaon.Kaon) ETHProxy { + return &ProxyETHGetTransactionByBlockNumberAndIndex{kaonClient} } func TestGetTransactionByBlockNumberAndIndex(t *testing.T) { diff --git a/pkg/transformer/eth_getTransactionByHash_test.go b/pkg/transformer/eth_getTransactionByHash_test.go index 17c88344..221cc10e 100644 --- a/pkg/transformer/eth_getTransactionByHash_test.go +++ b/pkg/transformer/eth_getTransactionByHash_test.go @@ -4,21 +4,10 @@ import ( "encoding/json" "testing" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" - "github.com/shopspring/decimal" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" ) -type testData struct { - TxHash string - VoutHex string - To string - From string - Input string - Gas string - GasPrice string -} - func TestGetTransactionByHashRequest(t *testing.T) { //preparing request requestParams := []json.RawMessage{[]byte(`"0x11e97fa5877c5df349934bafc02da6218038a427e8ed081f048626fa6eb523f5"`)} @@ -27,12 +16,12 @@ func TestGetTransactionByHashRequest(t *testing.T) { t.Fatal(err) } mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) internal.SetupGetBlockByHashResponses(t, mockedClientDoer) //preparing proxy & executing request - proxyEth := ProxyETHGetTransactionByHash{qtumClient} + proxyEth := ProxyETHGetTransactionByHash{kaonClient} got, JsonErr := proxyEth.Request(request, internal.NewEchoContext()) if JsonErr != nil { t.Fatal(JsonErr) @@ -44,91 +33,71 @@ func TestGetTransactionByHashRequest(t *testing.T) { } func TestGetTransactionByHashRequestWithContractVout(t *testing.T) { - - testsArray := []testData{ - { - // Using data from https://qtum.info/tx/d20c5c31536e60decf175caf2cbfba980c3678c0f4b201c9b9fa1440102e6451 - // ASM: "4 25548 40 8588b2c50000000000000000000000000000000000000000000000000000000000000000 57946bb437560b13275c32a468c6fd1e0c2cdd48 OP_CALL", - TxHash: "0xd20c5c31536e60decf175caf2cbfba980c3678c0f4b201c9b9fa1440102e6451", - VoutHex: "540390d003012844095ea7b300000000000000000000000025495b3a87d82e9d7a71b341addfc0d7bb3475c7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1454fefdb5b31164f66ddb68becd7bdd864cacd65bc2", - Input: "0x095ea7b300000000000000000000000025495b3a87d82e9d7a71b341addfc0d7bb3475c7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", - To: "0x54fefdb5b31164f66ddb68becd7bdd864cacd65b", - Gas: "0x3d090", - GasPrice: "0x5d21dba000", - }, - { - // Edge case taken from openzeppelin tests - TxHash: "1664dbafc1dd3c5264209f384b53c569f18b9acad1433a45458e29d46cfbea3e", - VoutHex: "0100010001000100142411fd6feb7c148f58101d0cf6e8c8c45af8f219c2", - Input: "0x00", - To: "0x2411fd6feb7c148f58101d0cf6e8c8c45af8f219", - Gas: "0x0", - GasPrice: "0x0", - }, + //preparing request + requestParams := []json.RawMessage{[]byte(`"0x11e97fa5877c5df349934bafc02da6218038a427e8ed081f048626fa6eb523f5"`)} + request, err := internal.PrepareEthRPCRequest(1, requestParams) + if err != nil { + t.Fatal(err) } - for _, test := range testsArray { - mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, _ := internal.CreateMockedClient(mockedClientDoer) - requestParams := []json.RawMessage{[]byte(`"` + test.TxHash + `"`)} - request, err := internal.PrepareEthRPCRequest(1, requestParams) - if err != nil { - t.Fatal(err) - } - internal.SetupGetBlockByHashResponsesWithVouts( - t, - []*qtum.DecodedRawTransactionOutV{ - { - Value: decimal.Zero, - N: 0, - ScriptPubKey: qtum.DecodedRawTransactionScriptPubKey{ - Hex: test.VoutHex, - Addresses: []string{}, + mockedClientDoer := internal.NewDoerMappedMock() + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) + + internal.SetupGetBlockByHashResponsesWithVouts( + t, + // TODO: Clean this up, refactor + []*kaon.DecodedRawTransactionOutV{ + { + Value: kaon.ZeroAmount, + N: 0, + ScriptPubKey: kaon.DecodedRawTransactionScriptPubKey{ + ASM: "4 25548 40 8588b2c50000000000000000000000000000000000000000000000000000000000000000 57946bb437560b13275c32a468c6fd1e0c2cdd48 OP_CALL", + Addresses: []string{ + "QXeZZ5MsAF5pPrPy47ZFMmtCpg7RExT4mi", }, }, }, - mockedClientDoer, - ) - proxyEth := ProxyETHGetTransactionByHash{qtumClient} - got, JsonErr := proxyEth.Request(request, internal.NewEchoContext()) - if JsonErr != nil { - t.Fatal(JsonErr) - } - - want := internal.GetTransactionByHashResponseData - want.Input = test.Input - want.To = test.To - want.Gas = test.Gas - want.GasPrice = test.GasPrice + }, + mockedClientDoer, + ) - internal.CheckTestResultEthRequestRPC(*request, &want, got, t, false) + //preparing proxy & executing request + proxyEth := ProxyETHGetTransactionByHash{kaonClient} + got, JsonErr := proxyEth.Request(request, internal.NewEchoContext()) + if JsonErr != nil { + t.Fatal(JsonErr) } + + want := internal.GetTransactionByHashResponseData + want.Input = "0x8588b2c50000000000000000000000000000000000000000000000000000000000000000" + want.To = "0x57946bb437560b13275c32a468c6fd1e0c2cdd48" + want.Gas = "0x63cc" + want.GasPrice = "0x5d21dba000" + want.CumulativeGas = "0x5d21dba000" + + internal.CheckTestResultEthRequestRPC(*request, &want, got, t, false) } // TODO: This test was copied from the above, with the only change being the ASM in the Vout script. However for some reason a bunch of seemingly unrelated field changed in the respose // For example the gas and gas price field were suddenly non-zero. So something funky is definitely going on here func TestGetTransactionByHashRequestWithOpSender(t *testing.T) { - //? Using data from https://qtum.info/tx/0425fa39feed4cd6c93998159901095c147f8b0043823067dc1d25dabf950ac9 //preparing request - requestParams := []json.RawMessage{[]byte(`"0x0425fa39feed4cd6c93998159901095c147f8b0043823067dc1d25dabf950ac9"`)} + requestParams := []json.RawMessage{[]byte(`"0x11e97fa5877c5df349934bafc02da6218038a427e8ed081f048626fa6eb523f5"`)} request, err := internal.PrepareEthRPCRequest(1, requestParams) if err != nil { t.Fatal(err) } mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) internal.SetupGetBlockByHashResponsesWithVouts( t, // TODO: Clean this up, refactor - []*qtum.DecodedRawTransactionOutV{ + []*kaon.DecodedRawTransactionOutV{ { - Value: decimal.Zero, + Value: kaon.ZeroAmount, N: 0, - ScriptPubKey: qtum.DecodedRawTransactionScriptPubKey{ - // 'ASM' field has no impact in this unit test + ScriptPubKey: kaon.DecodedRawTransactionScriptPubKey{ ASM: "1 81e872329e767a0487de7e970992b13b644f1f4f 6b483045022100b83ef90bc808569fb00e29a0f6209d32c1795207c95a554c091401ac8fa8ab920220694b7ec801efd2facea2026d12e8eb5de7689c637f539a620f24c6da8fff235f0121021104b7672c2e08fe321f1bfaffc3768c2777adeedb857b4313ed9d2f15fc8ce4 OP_SENDER 4 55000 40 a9059cbb000000000000000000000000710e94d7f8a5d7a1e5be52bd783370d6e3008a2a0000000000000000000000000000000000000000000000000000000005f5e100 af1ae4e29253ba755c723bca25e883b8deb777b8 OP_CALL", - Hex: "01011493594441cb5de8b497ad8467d55412c2a0ef36594c6b6a4730440220396b30b7a2f2af482e585473b7575dd2f989f3f3d7cdee55fa34e93f23d5254d022055326cdcab38c58dc3e65c458bfb656cca8340f59534c00ad98b4d4d3303f459012103379c39b6fb2c705db608f98a8fc064f94c66faf894996ca88595487f9ef04a6ec401040390d0030128043d666e8b140000000000000000000000000000000000000086c2", - // 'Addresses' field has no impact in this unit test Addresses: []string{ "QXeZZ5MsAF5pPrPy47ZFMmtCpg7RExT4mi", }, @@ -139,24 +108,25 @@ func TestGetTransactionByHashRequestWithOpSender(t *testing.T) { ) //preparing proxy & executing request - proxyEth := ProxyETHGetTransactionByHash{qtumClient} + proxyEth := ProxyETHGetTransactionByHash{kaonClient} got, JsonErr := proxyEth.Request(request, internal.NewEchoContext()) if JsonErr != nil { t.Fatal(JsonErr) } want := internal.GetTransactionByHashResponseData - want.Input = "0x3d666e8b" - want.From = "0x93594441cb5de8b497ad8467d55412c2a0ef3659" - want.To = "0x0000000000000000000000000000000000000086" - want.Gas = "0x3d090" + want.Input = "0xa9059cbb000000000000000000000000710e94d7f8a5d7a1e5be52bd783370d6e3008a2a0000000000000000000000000000000000000000000000000000000005f5e100" + want.From = "0x81e872329e767a0487de7e970992b13b644f1f4f" + want.To = "0xaf1ae4e29253ba755c723bca25e883b8deb777b8" + want.Gas = "0xd6d8" want.GasPrice = "0x5d21dba000" + want.CumulativeGas = "0x5d21dba000" internal.CheckTestResultEthRequestRPC(*request, &want, got, t, false) } /* -// TODO: Removing this unit test as the transformer computes the "Amount" value (how much QTUM was transferred out) from the MethodDecodeRawTransaction response +// TODO: Removing this unit test as the transformer computes the "Amount" value (how much KAON was transferred out) from the MethodDecodeRawTransaction response // and the way that the balance is calculated cannot return a precision overflow error func TestGetTransactionByHashRequest_PrecisionOverflow(t *testing.T) { //preparing request @@ -166,10 +136,10 @@ func TestGetTransactionByHashRequest_PrecisionOverflow(t *testing.T) { t.Fatal(err) } mockedClientDoer := newDoerMappedMock() - qtumClient, err := createMockedClient(mockedClientDoer) + kaonClient, err := createMockedClient(mockedClientDoer) //preparing answer to "getblockhash" - getTransactionResponse := qtum.GetTransactionResponse{ + getTransactionResponse := kaon.GetTransactionResponse{ Amount: decimal.NewFromFloat(0.20689141234), Fee: decimal.NewFromFloat(-0.2012), Confirmations: 2, @@ -180,7 +150,7 @@ func TestGetTransactionByHashRequest_PrecisionOverflow(t *testing.T) { Time: 1533092879, ReceivedAt: 1533092879, Bip125Replaceable: "no", - Details: []*qtum.TransactionDetail{{Account: "", + Details: []*kaon.TransactionDetail{{Account: "", Category: "send", Amount: decimal.NewFromInt(0), Vout: 0, @@ -188,37 +158,37 @@ func TestGetTransactionByHashRequest_PrecisionOverflow(t *testing.T) { Abandoned: false}}, Hex: "020000000159c0514feea50f915854d9ec45bc6458bb14419c78b17e7be3f7fd5f563475b5010000006a473044022072d64a1f4ea2d54b7b05050fc853ab192c91cc5ca17e23007867f92f2ab59d9202202b8c9ab9348c8edbb3b98b1788382c8f37642ec9bd6a4429817ab79927319200012103520b1500a400483f19b93c4cb277a2f29693ea9d6739daaf6ae6e971d29e3140feffffff02000000000000000063010403400d0301644440c10f190000000000000000000000006b22910b1e302cf74803ffd1691c2ecb858d3712000000000000000000000000000000000000000000000000000000000000000a14be528c8378ff082e4ba43cb1baa363dbf3f577bfc260e66272970100001976a9146b22910b1e302cf74803ffd1691c2ecb858d371288acb00f0000", } - err = mockedClientDoer.AddResponseWithRequestID(2, qtum.MethodGetTransaction, getTransactionResponse) + err = mockedClientDoer.AddResponseWithRequestID(2, kaon.MethodGetTransaction, getTransactionResponse) if err != nil { t.Fatal(err) } - decodedRawTransactionResponse := qtum.DecodedRawTransactionResponse{ + decodedRawTransactionResponse := kaon.DecodedRawTransactionResponse{ ID: "11e97fa5877c5df349934bafc02da6218038a427e8ed081f048626fa6eb523f5", Hash: "d0fe0caa1b798c36da37e9118a06a7d151632d670b82d1c7dc3985577a71880f", Size: 552, Vsize: 552, Version: 2, Locktime: 608, - Vins: []*qtum.DecodedRawTransactionInV{{ + Vins: []*kaon.DecodedRawTransactionInV{{ TxID: "7f5350dc474f2953a3f30282c1afcad2fb61cdcea5bd949c808ecc6f64ce1503", Vout: 0, ScriptSig: struct { - Asm string `json:"asm"` + ASM string `json:"asm"` Hex string `json:"hex"` }{ - Asm: "3045022100af4de764705dbd3c0c116d73fe0a2b78c3fab6822096ba2907cfdae2bb28784102206304340a6d260b364ef86d6b19f2b75c5e55b89fb2f93ea72c05e09ee037f60b[ALL] 03520b1500a400483f19b93c4cb277a2f29693ea9d6739daaf6ae6e971d29e3140", + ASM: "3045022100af4de764705dbd3c0c116d73fe0a2b78c3fab6822096ba2907cfdae2bb28784102206304340a6d260b364ef86d6b19f2b75c5e55b89fb2f93ea72c05e09ee037f60b[ALL] 03520b1500a400483f19b93c4cb277a2f29693ea9d6739daaf6ae6e971d29e3140", Hex: "483045022100af4de764705dbd3c0c116d73fe0a2b78c3fab6822096ba2907cfdae2bb28784102206304340a6d260b364ef86d6b19f2b75c5e55b89fb2f93ea72c05e09ee037f60b012103520b1500a400483f19b93c4cb277a2f29693ea9d6739daaf6ae6e971d29e3140", }, }}, - Vouts: []*qtum.DecodedRawTransactionOutV{}, + Vouts: []*kaon.DecodedRawTransactionOutV{}, } - err = mockedClientDoer.AddResponseWithRequestID(3, qtum.MethodDecodeRawTransaction, decodedRawTransactionResponse) + err = mockedClientDoer.AddResponseWithRequestID(3, kaon.MethodDecodeRawTransaction, decodedRawTransactionResponse) if err != nil { t.Fatal(err) } - getBlockResponse := qtum.GetBlockResponse{ + getBlockResponse := kaon.GetBlockResponse{ Hash: "bba11e1bacc69ba535d478cf1f2e542da3735a517b0b8eebaf7e6bb25eeb48c5", Confirmations: 1, Strippedsize: 584, @@ -245,36 +215,36 @@ func TestGetTransactionByHashRequest_PrecisionOverflow(t *testing.T) { Nextblockhash: "d7758774cfdd6bab7774aa891ae035f1dc5a2ff44240784b5e7bdfd43a7a6ec1", Signature: "3045022100a6ab6c2b14b1f73e734f1a61d4d22385748e48836492723a6ab37cdf38525aba022014a51ecb9e51f5a7a851641683541fec6f8f20205d0db49e50b2a4e5daed69d2", } - err = mockedClientDoer.AddResponseWithRequestID(4, qtum.MethodGetBlock, getBlockResponse) + err = mockedClientDoer.AddResponseWithRequestID(4, kaon.MethodGetBlock, getBlockResponse) if err != nil { t.Fatal(err) } // TODO: Get an actual response for this (only addresses are used in this test though) - getRawTransactionResponse := qtum.GetRawTransactionResponse{ - Vouts: []qtum.RawTransactionVout{ + getRawTransactionResponse := kaon.GetRawTransactionResponse{ + Vouts: []kaon.RawTransactionVout{ { Details: struct { Addresses []string `json:"addresses"` - Asm string `json:"asm"` + ASM string `json:"asm"` Hex string `json:"hex"` // ReqSigs interface{} `json:"reqSigs"` Type string `json:"type"` }{ Addresses: []string{ - "7926223070547d2d15b2ef5e7383e541c338ffe9", + "1CE507204a6fC8fd6aA7e54D1481d30ACB0Dbead", }, }, }, }, } - err = mockedClientDoer.AddResponseWithRequestID(4, qtum.MethodGetRawTransaction, &getRawTransactionResponse) + err = mockedClientDoer.AddResponseWithRequestID(4, kaon.MethodGetRawTransaction, &getRawTransactionResponse) if err != nil { t.Fatal(err) } //preparing proxy & executing request - proxyEth := ProxyETHGetTransactionByHash{qtumClient} + proxyEth := ProxyETHGetTransactionByHash{kaonClient} _, err = proxyEth.Request(request, internal.NewEchoContext()) want := string("decimal.BigInt() was not a success") diff --git a/pkg/transformer/eth_getTransactionCount.go b/pkg/transformer/eth_getTransactionCount.go index ea2efe3c..a4f9b257 100644 --- a/pkg/transformer/eth_getTransactionCount.go +++ b/pkg/transformer/eth_getTransactionCount.go @@ -4,36 +4,30 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" ) -// ProxyETHEstimateGas implements ETHProxy +// ProxyETHTxCount implements ETHProxy type ProxyETHTxCount struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyETHTxCount) Method() string { return "eth_getTransactionCount" } -func (p *ProxyETHTxCount) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { - - /* not sure we need this. Need to figure out how to best unmarshal this in the future. For now this will work. - var req eth.GetTransactionCountRequest - if err := unmarshalRequest(rawreq.Params, &req); err != nil { - return nil, err - }*/ - qtumresp, err := p.Qtum.GetTransactionCount(c.Request().Context(), "", "") +func (p *ProxyETHTxCount) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { + kaonresp, err := p.Kaon.GetTransactionCount(c.Request().Context(), "", "") if err != nil { return nil, eth.NewCallbackError(err.Error()) } - // qtum res -> eth res - return p.response(qtumresp), nil + // kaon res -> eth res + return p.response(kaonresp), nil } -func (p *ProxyETHTxCount) response(qtumresp *big.Int) string { - return hexutil.EncodeBig(qtumresp) +func (p *ProxyETHTxCount) response(kaonresp *big.Int) string { + return hexutil.EncodeBig(kaonresp) } diff --git a/pkg/transformer/eth_getTransactionCount_test.go b/pkg/transformer/eth_getTransactionCount_test.go index e2b838b8..daaaf38a 100644 --- a/pkg/transformer/eth_getTransactionCount_test.go +++ b/pkg/transformer/eth_getTransactionCount_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "testing" - "github.com/qtumproject/janus/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/internal" ) func TestGetTransactionCountRequest(t *testing.T) { @@ -16,13 +16,13 @@ func TestGetTransactionCountRequest(t *testing.T) { } mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) if err != nil { t.Fatal(err) } //preparing proxy & executing request - proxyEth := ProxyETHTxCount{qtumClient} + proxyEth := ProxyETHTxCount{kaonClient} got, jsonErr := proxyEth.Request(request, internal.NewEchoContext()) if jsonErr != nil { t.Fatal(jsonErr) diff --git a/pkg/transformer/eth_getTransactionReceipt.go b/pkg/transformer/eth_getTransactionReceipt.go index b78e08f6..c5eb593e 100644 --- a/pkg/transformer/eth_getTransactionReceipt.go +++ b/pkg/transformer/eth_getTransactionReceipt.go @@ -4,12 +4,12 @@ import ( "context" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/kaonone/eth-rpc-gate/pkg/conversion" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/utils" "github.com/labstack/echo" "github.com/pkg/errors" - "github.com/qtumproject/janus/pkg/conversion" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" - "github.com/qtumproject/janus/pkg/utils" ) var STATUS_SUCCESS = "0x1" @@ -17,14 +17,14 @@ var STATUS_FAILURE = "0x0" // ProxyETHGetTransactionReceipt implements ETHProxy type ProxyETHGetTransactionReceipt struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyETHGetTransactionReceipt) Method() string { return "eth_getTransactionReceipt" } -func (p *ProxyETHGetTransactionReceipt) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHGetTransactionReceipt) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { var req eth.GetTransactionReceiptRequest if err := unmarshalRequest(rawreq.Params, &req); err != nil { // TODO: Correct error code? @@ -36,21 +36,30 @@ func (p *ProxyETHGetTransactionReceipt) Request(rawreq *eth.JSONRPCRequest, c ec } var ( txHash = utils.RemoveHexPrefix(string(req)) - qtumReq = qtum.GetTransactionReceiptRequest(txHash) + kaonReq = kaon.GetTransactionReceiptRequest(txHash) ) - return p.request(c.Request().Context(), &qtumReq) + return p.request(c.Request().Context(), &kaonReq) } -func (p *ProxyETHGetTransactionReceipt) request(ctx context.Context, req *qtum.GetTransactionReceiptRequest) (*eth.GetTransactionReceiptResponse, eth.JSONRPCError) { - qtumReceipt, err := p.Qtum.GetTransactionReceipt(ctx, string(*req)) +func (p *ProxyETHGetTransactionReceipt) request(ctx context.Context, req *kaon.GetTransactionReceiptRequest) (*eth.GetTransactionReceiptResponse, *eth.JSONRPCError) { + kaonReceipt, err := p.Kaon.GetTransactionReceipt(ctx, string(*req)) if err != nil { - ethTx, _, getRewardTransactionErr := getRewardTransactionByHash(ctx, p.Qtum, string(*req)) + kaonHash, err := p.GetTransactionHashByEthHash(ctx, string(*req)) + + var getRewardTransactionErr error + var ethTx *eth.GetTransactionByHashResponse + if err == nil { + ethTx, _, getRewardTransactionErr = getRewardTransactionByHash(ctx, p.Kaon, string(*kaonHash)) + } else { + ethTx, _, getRewardTransactionErr = getRewardTransactionByHash(ctx, p.Kaon, string(*req)) + } + if getRewardTransactionErr != nil { errCause := errors.Cause(err) - if errCause == qtum.EmptyResponseErr { + if errCause == kaon.EmptyResponseErr { return nil, nil } - p.Qtum.GetDebugLogger().Log("msg", "Transaction does not exist", "txid", string(*req)) + p.Kaon.GetDebugLogger().Log("msg", "Transaction does not exist", "txid", string(*req)) return nil, eth.NewCallbackError(err.Error()) } if ethTx == nil { @@ -59,14 +68,13 @@ func (p *ProxyETHGetTransactionReceipt) request(ctx context.Context, req *qtum.G return nil, nil } return ð.GetTransactionReceiptResponse{ - TransactionHash: ethTx.Hash, - TransactionIndex: ethTx.TransactionIndex, - BlockHash: ethTx.BlockHash, - BlockNumber: ethTx.BlockNumber, - // TODO: This is higher than GasUsed in geth but does it matter? - CumulativeGasUsed: NonContractVMGasLimit, - EffectiveGasPrice: "0x0", - GasUsed: NonContractVMGasLimit, + TransactionHash: ethTx.Hash, + TransactionIndex: ethTx.TransactionIndex, + BlockHash: ethTx.BlockHash, + BlockNumber: ethTx.BlockNumber, + CumulativeGasUsed: ethTx.CumulativeGas, + EffectiveGasPrice: ethTx.GasPrice, + GasUsed: ethTx.Gas, From: ethTx.From, To: ethTx.To, Logs: []eth.Log{}, @@ -76,16 +84,16 @@ func (p *ProxyETHGetTransactionReceipt) request(ctx context.Context, req *qtum.G } ethReceipt := ð.GetTransactionReceiptResponse{ - TransactionHash: utils.AddHexPrefix(qtumReceipt.TransactionHash), - TransactionIndex: hexutil.EncodeUint64(qtumReceipt.TransactionIndex), - BlockHash: utils.AddHexPrefix(qtumReceipt.BlockHash), - BlockNumber: hexutil.EncodeUint64(qtumReceipt.BlockNumber), - ContractAddress: utils.AddHexPrefixIfNotEmpty(qtumReceipt.ContractAddress), - CumulativeGasUsed: hexutil.EncodeUint64(qtumReceipt.CumulativeGasUsed), - EffectiveGasPrice: "0x0", - GasUsed: hexutil.EncodeUint64(qtumReceipt.GasUsed), - From: utils.AddHexPrefixIfNotEmpty(qtumReceipt.From), - To: utils.AddHexPrefixIfNotEmpty(qtumReceipt.To), + TransactionHash: utils.AddHexPrefix(kaonReceipt.TransactionHash), + TransactionIndex: hexutil.EncodeUint64(kaonReceipt.TransactionIndex), + BlockHash: utils.AddHexPrefix(kaonReceipt.BlockHash), + BlockNumber: hexutil.EncodeUint64(kaonReceipt.BlockNumber), + ContractAddress: utils.AddHexPrefixIfNotEmpty(kaonReceipt.ContractAddress), + CumulativeGasUsed: hexutil.EncodeBig(&kaonReceipt.CumulativeGasUsed), + EffectiveGasPrice: hexutil.EncodeBig(&kaonReceipt.EffectiveGasPrice), + GasUsed: hexutil.EncodeBig(&kaonReceipt.GasUsed), + From: utils.AddHexPrefixIfNotEmpty(kaonReceipt.From), + To: utils.AddHexPrefixIfNotEmpty(kaonReceipt.To), // TODO: researching // ! Temporary accept this value to be always zero, as it is at eth logs @@ -93,32 +101,38 @@ func (p *ProxyETHGetTransactionReceipt) request(ctx context.Context, req *qtum.G } status := STATUS_FAILURE - if qtumReceipt.Excepted == "None" { + if kaonReceipt.Excepted == "None" { status = STATUS_SUCCESS } else { - p.Qtum.GetDebugLogger().Log("transaction", ethReceipt.TransactionHash, "msg", "transaction excepted", "message", qtumReceipt.Excepted) + p.Kaon.GetDebugLogger().Log("transaction", ethReceipt.TransactionHash, "msg", "transaction excepted", "message", kaonReceipt.Excepted) } ethReceipt.Status = status - r := qtum.TransactionReceipt(*qtumReceipt) + r := kaon.TransactionReceipt(*kaonReceipt) ethReceipt.Logs = conversion.ExtractETHLogsFromTransactionReceipt(&r, r.Log) - qtumTx, err := p.Qtum.GetRawTransaction(ctx, qtumReceipt.TransactionHash, false) + kaonTx, err := p.Kaon.GetRawTransaction(ctx, kaonReceipt.TransactionHash, false) if err != nil { p.GetDebugLogger().Log("msg", "couldn't get transaction", "err", err) return nil, eth.NewCallbackError("couldn't get transaction") } - decodedRawQtumTx, err := p.Qtum.DecodeRawTransaction(ctx, qtumTx.Hex) + decodedRawKaonTx, err := p.Kaon.DecodeRawTransaction(ctx, kaonTx.Hex) if err != nil { p.GetDebugLogger().Log("msg", "couldn't decode raw transaction", "err", err) return nil, eth.NewCallbackError("couldn't decode raw transaction") } - if decodedRawQtumTx.IsContractCreation() { + if decodedRawKaonTx.IsContractCreation() { ethReceipt.To = "" } else { ethReceipt.ContractAddress = "" } + if ethReceipt.BlockHash == "0x0000000000000000000000000000000000000000000000000000000000000000" { // nullify pending txs + ethReceipt.ContractAddress = "" + ethReceipt.BlockNumber = "" + ethReceipt.BlockHash = "" + } + // TODO: researching // - The following code reason is unknown (see original comment) // - Code temporary commented, until an error occures diff --git a/pkg/transformer/eth_getTransactionReceipt_test.go b/pkg/transformer/eth_getTransactionReceipt_test.go index c3a453b7..b0cea4e9 100644 --- a/pkg/transformer/eth_getTransactionReceipt_test.go +++ b/pkg/transformer/eth_getTransactionReceipt_test.go @@ -4,10 +4,10 @@ import ( "encoding/json" "testing" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" - "github.com/qtumproject/janus/pkg/utils" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/utils" ) func TestGetTransactionReceiptForNonVMTransaction(t *testing.T) { @@ -19,32 +19,32 @@ func TestGetTransactionReceiptForNonVMTransaction(t *testing.T) { } mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) if err != nil { t.Fatal(err) } //preparing client response - err = mockedClientDoer.AddResponseWithRequestID(2, qtum.MethodGetTransactionReceipt, []byte("[]")) + err = mockedClientDoer.AddResponseWithRequestID(2, kaon.MethodGetTransactionReceipt, []byte("[]")) if err != nil { t.Fatal(err) } - rawTransactionResponse := &qtum.GetRawTransactionResponse{ + rawTransactionResponse := &kaon.GetRawTransactionResponse{ BlockHash: internal.GetTransactionByHashBlockHash, } - err = mockedClientDoer.AddResponseWithRequestID(3, qtum.MethodGetRawTransaction, rawTransactionResponse) + err = mockedClientDoer.AddResponseWithRequestID(3, kaon.MethodGetRawTransaction, rawTransactionResponse) if err != nil { t.Fatal(err) } - err = mockedClientDoer.AddResponseWithRequestID(4, qtum.MethodGetBlock, internal.GetBlockResponse) + err = mockedClientDoer.AddResponseWithRequestID(4, kaon.MethodGetBlock, internal.GetBlockResponse) if err != nil { t.Fatal(err) } //preparing proxy & executing request - proxyEth := ProxyETHGetTransactionReceipt{qtumClient} + proxyEth := ProxyETHGetTransactionReceipt{kaonClient} got, jsonErr := proxyEth.Request(request, internal.NewEchoContext()) if jsonErr != nil { t.Fatal(jsonErr) @@ -59,8 +59,8 @@ func TestGetTransactionReceiptForNonVMTransaction(t *testing.T) { Logs: []eth.Log{}, EffectiveGasPrice: "0x0", CumulativeGasUsed: NonContractVMGasLimit, - To: utils.AddHexPrefix(qtum.ZeroAddress), - From: utils.AddHexPrefix(qtum.ZeroAddress), + To: utils.AddHexPrefix(kaon.ZeroAddress), + From: utils.AddHexPrefix(kaon.ZeroAddress), LogsBloom: eth.EmptyLogsBloom, Status: STATUS_SUCCESS, } diff --git a/pkg/transformer/eth_getUncleByBlockHashAndIndex.go b/pkg/transformer/eth_getUncleByBlockHashAndIndex.go index 849d12d0..e0d2870a 100644 --- a/pkg/transformer/eth_getUncleByBlockHashAndIndex.go +++ b/pkg/transformer/eth_getUncleByBlockHashAndIndex.go @@ -1,8 +1,8 @@ package transformer import ( + "github.com/kaonone/eth-rpc-gate/pkg/eth" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" ) type ETHGetUncleByBlockHashAndIndex struct { @@ -12,7 +12,7 @@ func (p *ETHGetUncleByBlockHashAndIndex) Method() string { return "eth_getUncleByBlockHashAndIndex" } -func (p *ETHGetUncleByBlockHashAndIndex) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ETHGetUncleByBlockHashAndIndex) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { // hardcoded to nil return nil, nil } diff --git a/pkg/transformer/eth_getUncleByBlockHashAndIndex_test.go b/pkg/transformer/eth_getUncleByBlockHashAndIndex_test.go index 08ad1528..4e41932c 100644 --- a/pkg/transformer/eth_getUncleByBlockHashAndIndex_test.go +++ b/pkg/transformer/eth_getUncleByBlockHashAndIndex_test.go @@ -4,11 +4,11 @@ import ( "encoding/json" "testing" - "github.com/qtumproject/janus/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/internal" ) func TestGetUncleByBlockHashAndIndexReturnsNil(t *testing.T) { - // request body doesn't matter, there is no QTUM object to proxy calls to + // request body doesn't matter, there is no KAON object to proxy calls to requestParams := []json.RawMessage{} request, err := internal.PrepareEthRPCRequest(1, requestParams) if err != nil { diff --git a/pkg/transformer/eth_getUncleCountByBlockHash.go b/pkg/transformer/eth_getUncleCountByBlockHash.go index f3b18e9c..529c2c6e 100644 --- a/pkg/transformer/eth_getUncleCountByBlockHash.go +++ b/pkg/transformer/eth_getUncleCountByBlockHash.go @@ -1,8 +1,8 @@ package transformer import ( + "github.com/kaonone/eth-rpc-gate/pkg/eth" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" ) type ETHGetUncleCountByBlockHash struct { @@ -12,7 +12,7 @@ func (p *ETHGetUncleCountByBlockHash) Method() string { return "eth_getUncleCountByBlockHash" } -func (p *ETHGetUncleCountByBlockHash) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ETHGetUncleCountByBlockHash) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { // hardcoded to 0 return 0, nil } diff --git a/pkg/transformer/eth_getUncleCountByBlockNumber.go b/pkg/transformer/eth_getUncleCountByBlockNumber.go index 670612bb..05963b45 100644 --- a/pkg/transformer/eth_getUncleCountByBlockNumber.go +++ b/pkg/transformer/eth_getUncleCountByBlockNumber.go @@ -1,8 +1,8 @@ package transformer import ( + "github.com/kaonone/eth-rpc-gate/pkg/eth" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" ) type ETHGetUncleCountByBlockNumber struct { @@ -12,7 +12,7 @@ func (p *ETHGetUncleCountByBlockNumber) Method() string { return "eth_getUncleCountByBlockNumber" } -func (p *ETHGetUncleCountByBlockNumber) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ETHGetUncleCountByBlockNumber) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { // hardcoded to 0 return "0x0", nil } diff --git a/pkg/transformer/eth_hashrate.go b/pkg/transformer/eth_hashrate.go index a319eaf9..699aa486 100644 --- a/pkg/transformer/eth_hashrate.go +++ b/pkg/transformer/eth_hashrate.go @@ -5,36 +5,36 @@ import ( "math" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" ) -//ProxyETHGetHashrate implements ETHProxy +// ProxyETHGetHashrate implements ETHProxy type ProxyETHHashrate struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyETHHashrate) Method() string { return "eth_hashrate" } -func (p *ProxyETHHashrate) Request(_ *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHHashrate) Request(_ *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { return p.request(c.Request().Context()) } -func (p *ProxyETHHashrate) request(ctx context.Context) (*eth.HashrateResponse, eth.JSONRPCError) { - qtumresp, err := p.Qtum.GetHashrate(ctx) +func (p *ProxyETHHashrate) request(ctx context.Context) (*eth.HashrateResponse, *eth.JSONRPCError) { + kaonresp, err := p.Kaon.GetHashrate(ctx) if err != nil { return nil, eth.NewCallbackError(err.Error()) } - // qtum res -> eth res - return p.ToResponse(qtumresp), nil + // kaon res -> eth res + return p.ToResponse(kaonresp), nil } -func (p *ProxyETHHashrate) ToResponse(qtumresp *qtum.GetHashrateResponse) *eth.HashrateResponse { - hexVal := hexutil.EncodeUint64(math.Float64bits(qtumresp.Difficulty)) +func (p *ProxyETHHashrate) ToResponse(kaonresp *kaon.GetHashrateResponse) *eth.HashrateResponse { + hexVal := hexutil.EncodeUint64(math.Float64bits(kaonresp.Difficulty)) ethresp := eth.HashrateResponse(hexVal) return ðresp } diff --git a/pkg/transformer/eth_hashrate_test.go b/pkg/transformer/eth_hashrate_test.go index 6d71b3d7..d90850e9 100644 --- a/pkg/transformer/eth_hashrate_test.go +++ b/pkg/transformer/eth_hashrate_test.go @@ -6,9 +6,9 @@ import ( "testing" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" ) func TestHashrateRequest(t *testing.T) { @@ -20,21 +20,21 @@ func TestHashrateRequest(t *testing.T) { } mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) if err != nil { t.Fatal(err) } exampleResponse := `{"enabled": true, "staking": false, "errors": "", "currentblocktx": 0, "pooledtx": 0, "difficulty": 4.656542373906925e-010, "search-interval": 0, "weight": 0, "netstakeweight": 0, "expectedtime": 0}` - getHashrateResponse := qtum.GetHashrateResponse{} + getHashrateResponse := kaon.GetHashrateResponse{} unmarshalRequest([]byte(exampleResponse), &getHashrateResponse) - err = mockedClientDoer.AddResponse(qtum.MethodGetStakingInfo, getHashrateResponse) + err = mockedClientDoer.AddResponse(kaon.MethodGetStakingInfo, getHashrateResponse) if err != nil { t.Fatal(err) } - proxyEth := ProxyETHHashrate{qtumClient} + proxyEth := ProxyETHHashrate{kaonClient} got, jsonErr := proxyEth.Request(request, internal.NewEchoContext()) if jsonErr != nil { t.Fatal(jsonErr) diff --git a/pkg/transformer/eth_mining.go b/pkg/transformer/eth_mining.go index fa45f05e..1501e15e 100644 --- a/pkg/transformer/eth_mining.go +++ b/pkg/transformer/eth_mining.go @@ -3,35 +3,35 @@ package transformer import ( "context" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" ) -//ProxyETHGetHashrate implements ETHProxy +// ProxyETHGetHashrate implements ETHProxy type ProxyETHMining struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyETHMining) Method() string { return "eth_mining" } -func (p *ProxyETHMining) Request(_ *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHMining) Request(_ *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { return p.request(c.Request().Context()) } -func (p *ProxyETHMining) request(ctx context.Context) (*eth.MiningResponse, eth.JSONRPCError) { - qtumresp, err := p.Qtum.GetMining(ctx) +func (p *ProxyETHMining) request(ctx context.Context) (*eth.MiningResponse, *eth.JSONRPCError) { + kaonresp, err := p.Kaon.GetMining(ctx) if err != nil { return nil, eth.NewCallbackError(err.Error()) } - // qtum res -> eth res - return p.ToResponse(qtumresp), nil + // kaon res -> eth res + return p.ToResponse(kaonresp), nil } -func (p *ProxyETHMining) ToResponse(qtumresp *qtum.GetMiningResponse) *eth.MiningResponse { - ethresp := eth.MiningResponse(qtumresp.Staking) +func (p *ProxyETHMining) ToResponse(kaonresp *kaon.GetMiningResponse) *eth.MiningResponse { + ethresp := eth.MiningResponse(kaonresp.Staking) return ðresp } diff --git a/pkg/transformer/eth_mining_test.go b/pkg/transformer/eth_mining_test.go index 95630b36..cc8e7b8a 100644 --- a/pkg/transformer/eth_mining_test.go +++ b/pkg/transformer/eth_mining_test.go @@ -4,9 +4,9 @@ import ( "encoding/json" "testing" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" ) func TestMiningRequest(t *testing.T) { @@ -18,18 +18,18 @@ func TestMiningRequest(t *testing.T) { } mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) if err != nil { t.Fatal(err) } - getMiningResponse := qtum.GetMiningResponse{Staking: true} - err = mockedClientDoer.AddResponse(qtum.MethodGetStakingInfo, getMiningResponse) + getMiningResponse := kaon.GetMiningResponse{Staking: true} + err = mockedClientDoer.AddResponse(kaon.MethodGetStakingInfo, getMiningResponse) if err != nil { t.Fatal(err) } - proxyEth := ProxyETHMining{qtumClient} + proxyEth := ProxyETHMining{kaonClient} got, jsonErr := proxyEth.Request(request, internal.NewEchoContext()) if jsonErr != nil { t.Fatal(jsonErr) diff --git a/pkg/transformer/eth_net_listening.go b/pkg/transformer/eth_net_listening.go index 62c1995f..c8733766 100644 --- a/pkg/transformer/eth_net_listening.go +++ b/pkg/transformer/eth_net_listening.go @@ -1,21 +1,21 @@ package transformer import ( + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" ) -// ProxyETHGetCode implements ETHProxy +// ProxyNetListening implements ETHProxy type ProxyNetListening struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyNetListening) Method() string { return "net_listening" } -func (p *ProxyNetListening) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyNetListening) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { networkInfo, err := p.GetNetworkInfo(c.Request().Context()) if err != nil { p.GetDebugLogger().Log("method", p.Method(), "msg", "Failed to query network info", "err", err) diff --git a/pkg/transformer/eth_net_listening_test.go b/pkg/transformer/eth_net_listening_test.go index 16b8359c..54ded40d 100644 --- a/pkg/transformer/eth_net_listening_test.go +++ b/pkg/transformer/eth_net_listening_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "testing" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" ) func TestNetListeningInactive(t *testing.T) { @@ -25,18 +25,18 @@ func testNetListeningRequest(t *testing.T, active bool) { } mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) if err != nil { t.Fatal(err) } - networkInfoResponse := qtum.NetworkInfoResponse{NetworkActive: active} - err = mockedClientDoer.AddResponseWithRequestID(2, qtum.MethodGetNetworkInfo, networkInfoResponse) + networkInfoResponse := kaon.NetworkInfoResponse{NetworkActive: active} + err = mockedClientDoer.AddResponseWithRequestID(2, kaon.MethodGetNetworkInfo, networkInfoResponse) if err != nil { t.Fatal(err) } - proxyEth := ProxyNetListening{qtumClient} + proxyEth := ProxyNetListening{kaonClient} got, jsonErr := proxyEth.Request(request, internal.NewEchoContext()) if jsonErr != nil { t.Fatal(jsonErr) diff --git a/pkg/transformer/eth_net_peerCount.go b/pkg/transformer/eth_net_peerCount.go index ac415e9d..7598f45f 100644 --- a/pkg/transformer/eth_net_peerCount.go +++ b/pkg/transformer/eth_net_peerCount.go @@ -4,25 +4,25 @@ import ( "context" "github.com/dcb9/go-ethereum/common/hexutil" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" ) // ProxyNetPeerCount implements ETHProxy type ProxyNetPeerCount struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyNetPeerCount) Method() string { return "net_peerCount" } -func (p *ProxyNetPeerCount) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyNetPeerCount) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { return p.request(c.Request().Context()) } -func (p *ProxyNetPeerCount) request(ctx context.Context) (*eth.NetPeerCountResponse, eth.JSONRPCError) { +func (p *ProxyNetPeerCount) request(ctx context.Context) (*eth.NetPeerCountResponse, *eth.JSONRPCError) { peerInfos, err := p.GetPeerInfo(ctx) if err != nil { return nil, eth.NewCallbackError(err.Error()) diff --git a/pkg/transformer/eth_net_peerCount_test.go b/pkg/transformer/eth_net_peerCount_test.go index 08dea2d2..89931638 100644 --- a/pkg/transformer/eth_net_peerCount_test.go +++ b/pkg/transformer/eth_net_peerCount_test.go @@ -6,9 +6,9 @@ import ( "testing" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" ) func TestPeerCountRequest(t *testing.T) { @@ -29,21 +29,21 @@ func testPeerCountRequest(t *testing.T, clients int) { } mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) if err != nil { t.Fatal(err) } - getPeerInfoResponse := []qtum.GetPeerInfoResponse{} + getPeerInfoResponse := []kaon.GetPeerInfoResponse{} for i := 0; i < clients; i++ { - getPeerInfoResponse = append(getPeerInfoResponse, qtum.GetPeerInfoResponse{}) + getPeerInfoResponse = append(getPeerInfoResponse, kaon.GetPeerInfoResponse{}) } - err = mockedClientDoer.AddResponseWithRequestID(2, qtum.MethodGetPeerInfo, getPeerInfoResponse) + err = mockedClientDoer.AddResponseWithRequestID(2, kaon.MethodGetPeerInfo, getPeerInfoResponse) if err != nil { t.Fatal(err) } - proxyEth := ProxyNetPeerCount{qtumClient} + proxyEth := ProxyNetPeerCount{kaonClient} got, jsonErr := proxyEth.Request(request, internal.NewEchoContext()) if jsonErr != nil { t.Fatal(jsonErr) diff --git a/pkg/transformer/eth_net_version.go b/pkg/transformer/eth_net_version.go index adda03cc..fefb1168 100644 --- a/pkg/transformer/eth_net_version.go +++ b/pkg/transformer/eth_net_version.go @@ -2,26 +2,26 @@ package transformer import ( "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" ) // ProxyETHNetVersion implements ETHProxy type ProxyETHNetVersion struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyETHNetVersion) Method() string { return "net_version" } -func (p *ProxyETHNetVersion) Request(_ *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHNetVersion) Request(_ *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { return p.request() } -func (p *ProxyETHNetVersion) request() (*eth.NetVersionResponse, eth.JSONRPCError) { - networkID, err := getChainId(p.Qtum) +func (p *ProxyETHNetVersion) request() (*eth.NetVersionResponse, *eth.JSONRPCError) { + networkID, err := getChainId(p.Kaon) if err != nil { return nil, err } diff --git a/pkg/transformer/eth_newBlockFilter.go b/pkg/transformer/eth_newBlockFilter.go index 639252b5..30f56743 100644 --- a/pkg/transformer/eth_newBlockFilter.go +++ b/pkg/transformer/eth_newBlockFilter.go @@ -4,14 +4,14 @@ import ( "context" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" ) // ProxyETHNewBlockFilter implements ETHProxy type ProxyETHNewBlockFilter struct { - *qtum.Qtum + *kaon.Kaon filter *eth.FilterSimulator } @@ -19,11 +19,11 @@ func (p *ProxyETHNewBlockFilter) Method() string { return "eth_newBlockFilter" } -func (p *ProxyETHNewBlockFilter) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHNewBlockFilter) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { return p.request(c.Request().Context()) } -func (p *ProxyETHNewBlockFilter) request(ctx context.Context) (eth.NewBlockFilterResponse, eth.JSONRPCError) { +func (p *ProxyETHNewBlockFilter) request(ctx context.Context) (eth.NewBlockFilterResponse, *eth.JSONRPCError) { blockCount, err := p.GetBlockCount(ctx) if err != nil { return "", eth.NewCallbackError(err.Error()) diff --git a/pkg/transformer/eth_newFilter.go b/pkg/transformer/eth_newFilter.go index 5f780b63..6db91dd4 100644 --- a/pkg/transformer/eth_newFilter.go +++ b/pkg/transformer/eth_newFilter.go @@ -5,14 +5,14 @@ import ( "encoding/json" "github.com/dcb9/go-ethereum/common/hexutil" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" ) // ProxyETHNewFilter implements ETHProxy type ProxyETHNewFilter struct { - *qtum.Qtum + *kaon.Kaon filter *eth.FilterSimulator } @@ -20,7 +20,7 @@ func (p *ProxyETHNewFilter) Method() string { return "eth_newFilter" } -func (p *ProxyETHNewFilter) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHNewFilter) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { var req eth.NewFilterRequest if err := json.Unmarshal(rawreq.Params, &req); err != nil { // TODO: Correct error code? @@ -30,14 +30,14 @@ func (p *ProxyETHNewFilter) Request(rawreq *eth.JSONRPCRequest, c echo.Context) return p.request(c.Request().Context(), &req) } -func (p *ProxyETHNewFilter) request(ctx context.Context, ethreq *eth.NewFilterRequest) (*eth.NewFilterResponse, eth.JSONRPCError) { +func (p *ProxyETHNewFilter) request(ctx context.Context, ethreq *eth.NewFilterRequest) (*eth.NewFilterResponse, *eth.JSONRPCError) { - from, err := getBlockNumberByRawParam(ctx, p.Qtum, ethreq.FromBlock, true) + from, err := getBlockNumberByRawParam(ctx, p.Kaon, ethreq.FromBlock, true) if err != nil { return nil, err } - to, err := getBlockNumberByRawParam(ctx, p.Qtum, ethreq.ToBlock, true) + to, err := getBlockNumberByRawParam(ctx, p.Kaon, ethreq.ToBlock, true) if err != nil { return nil, err } @@ -52,7 +52,7 @@ func (p *ProxyETHNewFilter) request(ctx context.Context, ethreq *eth.NewFilterRe if err != nil { return nil, eth.NewCallbackError(err.Error()) } - filter.Data.Store("topics", qtum.NewSearchLogsTopics(topics)) + filter.Data.Store("topics", kaon.NewSearchLogsTopics(topics)) } resp := eth.NewFilterResponse(hexutil.EncodeUint64(filter.ID)) return &resp, nil diff --git a/pkg/transformer/eth_personal_unlockAccount.go b/pkg/transformer/eth_personal_unlockAccount.go index a104ce72..569bd23c 100644 --- a/pkg/transformer/eth_personal_unlockAccount.go +++ b/pkg/transformer/eth_personal_unlockAccount.go @@ -1,8 +1,8 @@ package transformer import ( + "github.com/kaonone/eth-rpc-gate/pkg/eth" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" ) // ProxyETHPersonalUnlockAccount implements ETHProxy @@ -12,6 +12,6 @@ func (p *ProxyETHPersonalUnlockAccount) Method() string { return "personal_unlockAccount" } -func (p *ProxyETHPersonalUnlockAccount) Request(req *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHPersonalUnlockAccount) Request(req *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { return eth.PersonalUnlockAccountResponse(true), nil } diff --git a/pkg/transformer/eth_protocolVersion.go b/pkg/transformer/eth_protocolVersion.go index bbf5197c..629929a5 100644 --- a/pkg/transformer/eth_protocolVersion.go +++ b/pkg/transformer/eth_protocolVersion.go @@ -1,8 +1,8 @@ package transformer import ( + "github.com/kaonone/eth-rpc-gate/pkg/eth" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" ) type ETHProtocolVersion struct { @@ -12,6 +12,6 @@ func (p *ETHProtocolVersion) Method() string { return "eth_protocolVersion" } -func (p *ETHProtocolVersion) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ETHProtocolVersion) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { return "0x41", nil } diff --git a/pkg/transformer/eth_protocolVersion_test.go b/pkg/transformer/eth_protocolVersion_test.go index 68a45196..6cdc8402 100644 --- a/pkg/transformer/eth_protocolVersion_test.go +++ b/pkg/transformer/eth_protocolVersion_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "testing" - "github.com/qtumproject/janus/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/internal" ) func TestProtocolVersionReturnsHardcodedValue(t *testing.T) { diff --git a/pkg/transformer/eth_sendTransaction.go b/pkg/transformer/eth_sendTransaction.go index b7931541..359bda70 100644 --- a/pkg/transformer/eth_sendTransaction.go +++ b/pkg/transformer/eth_sendTransaction.go @@ -1,10 +1,10 @@ package transformer import ( + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/utils" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" - "github.com/qtumproject/janus/pkg/utils" "github.com/shopspring/decimal" ) @@ -12,14 +12,14 @@ var MinimumGasLimit = int64(22000) // ProxyETHSendTransaction implements ETHProxy type ProxyETHSendTransaction struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyETHSendTransaction) Method() string { return "eth_sendTransaction" } -func (p *ProxyETHSendTransaction) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHSendTransaction) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { var req eth.SendTransactionRequest err := unmarshalRequest(rawreq.Params, &req) if err != nil { @@ -32,7 +32,7 @@ func (p *ProxyETHSendTransaction) Request(rawreq *eth.JSONRPCRequest, c echo.Con } var result interface{} - var jsonErr eth.JSONRPCError + var jsonErr *eth.JSONRPCError if req.IsCreateContract() { result, jsonErr = p.requestCreateContract(&req) @@ -51,8 +51,8 @@ func (p *ProxyETHSendTransaction) Request(rawreq *eth.JSONRPCRequest, c echo.Con return result, jsonErr } -func (p *ProxyETHSendTransaction) requestSendToContract(ethtx *eth.SendTransactionRequest) (*eth.SendTransactionResponse, eth.JSONRPCError) { - gasLimit, gasPrice, err := EthGasToQtum(ethtx) +func (p *ProxyETHSendTransaction) requestSendToContract(ethtx *eth.SendTransactionRequest) (*eth.SendTransactionResponse, *eth.JSONRPCError) { + gasLimit, gasPrice, err := EthGasToKaon(ethtx) if err != nil { return nil, eth.NewInvalidParamsError(err.Error()) } @@ -60,16 +60,16 @@ func (p *ProxyETHSendTransaction) requestSendToContract(ethtx *eth.SendTransacti amount := decimal.NewFromFloat(0.0) if ethtx.Value != "" { var err error - amount, err = EthValueToQtumAmount(ethtx.Value, ZeroSatoshi) + amount, err = EthValueToKaonAmount(ethtx.Value, ZeroSatoshi) if err != nil { return nil, eth.NewInvalidParamsError(err.Error()) } } - qtumreq := qtum.SendToContractRequest{ + kaonreq := kaon.SendToContractRequest{ ContractAddress: utils.RemoveHexPrefix(ethtx.To), Datahex: utils.RemoveHexPrefix(ethtx.Data), - Amount: amount, + Amount: kaon.TransformAmount(amount), GasLimit: gasLimit, GasPrice: gasPrice, } @@ -79,11 +79,11 @@ func (p *ProxyETHSendTransaction) requestSendToContract(ethtx *eth.SendTransacti if err != nil { return nil, eth.NewCallbackError(err.Error()) } - qtumreq.SenderAddress = from + kaonreq.SenderAddress = from } - var resp *qtum.SendToContractResponse - if err := p.Qtum.Request(qtum.MethodSendToContract, &qtumreq, &resp); err != nil { + var resp *kaon.SendToContractResponse + if err := p.Kaon.Request(kaon.MethodSendToContract, &kaonreq, &resp); err != nil { return nil, eth.NewCallbackError(err.Error()) } @@ -91,39 +91,39 @@ func (p *ProxyETHSendTransaction) requestSendToContract(ethtx *eth.SendTransacti return ðresp, nil } -func (p *ProxyETHSendTransaction) requestSendToAddress(req *eth.SendTransactionRequest) (*eth.SendTransactionResponse, eth.JSONRPCError) { - getQtumWalletAddress := func(addr string) (string, error) { +func (p *ProxyETHSendTransaction) requestSendToAddress(req *eth.SendTransactionRequest) (*eth.SendTransactionResponse, *eth.JSONRPCError) { + getKaonWalletAddress := func(addr string) (string, error) { if utils.IsEthHexAddress(addr) { return p.FromHexAddress(utils.RemoveHexPrefix(addr)) } return addr, nil } - from, err := getQtumWalletAddress(req.From) + from, err := getKaonWalletAddress(req.From) if err != nil { return nil, eth.NewInvalidParamsError(err.Error()) } - to, err := getQtumWalletAddress(req.To) + to, err := getKaonWalletAddress(req.To) if err != nil { return nil, eth.NewInvalidParamsError(err.Error()) } - amount, err := EthValueToQtumAmount(req.Value, ZeroSatoshi) + amount, err := EthValueToKaonAmount(req.Value, ZeroSatoshi) if err != nil { return nil, eth.NewInvalidParamsError(err.Error()) } - p.GetDebugLogger().Log("msg", "successfully converted from wei to QTUM", "wei", req.Value, "qtum", amount) + p.GetDebugLogger().Log("msg", "successfully converted from wei to KAON", "wei", req.Value, "kaon", amount) - qtumreq := qtum.SendToAddressRequest{ + kaonreq := kaon.SendToAddressRequest{ Address: to, - Amount: amount, + Amount: kaon.TransformAmount(amount), SenderAddress: from, } - var qtumresp qtum.SendToAddressResponse - if err := p.Qtum.Request(qtum.MethodSendToAddress, &qtumreq, &qtumresp); err != nil { + var kaonresp kaon.SendToAddressResponse + if err := p.Kaon.Request(kaon.MethodSendToAddress, &kaonreq, &kaonresp); err != nil { // this can fail with: // "error": { // "code": -3, @@ -134,18 +134,18 @@ func (p *ProxyETHSendTransaction) requestSendToAddress(req *eth.SendTransactionR return nil, eth.NewCallbackError(err.Error()) } - ethresp := eth.SendTransactionResponse(utils.AddHexPrefix(string(qtumresp))) + ethresp := eth.SendTransactionResponse(utils.AddHexPrefix(string(kaonresp))) return ðresp, nil } -func (p *ProxyETHSendTransaction) requestCreateContract(req *eth.SendTransactionRequest) (*eth.SendTransactionResponse, eth.JSONRPCError) { - gasLimit, gasPrice, err := EthGasToQtum(req) +func (p *ProxyETHSendTransaction) requestCreateContract(req *eth.SendTransactionRequest) (*eth.SendTransactionResponse, *eth.JSONRPCError) { + gasLimit, gasPrice, err := EthGasToKaon(req) if err != nil { return nil, eth.NewInvalidParamsError(err.Error()) } - qtumreq := &qtum.CreateContractRequest{ + kaonreq := &kaon.CreateContractRequest{ ByteCode: utils.RemoveHexPrefix(req.Data), GasLimit: gasLimit, GasPrice: gasPrice, @@ -160,11 +160,11 @@ func (p *ProxyETHSendTransaction) requestCreateContract(req *eth.SendTransaction } } - qtumreq.SenderAddress = from + kaonreq.SenderAddress = from } - var resp *qtum.CreateContractResponse - if err := p.Qtum.Request(qtum.MethodCreateContract, qtumreq, &resp); err != nil { + var resp *kaon.CreateContractResponse + if err := p.Kaon.Request(kaon.MethodCreateContract, kaonreq, &resp); err != nil { return nil, eth.NewCallbackError(err.Error()) } diff --git a/pkg/transformer/eth_sign.go b/pkg/transformer/eth_sign.go index fc1ba2fc..56c740dc 100644 --- a/pkg/transformer/eth_sign.go +++ b/pkg/transformer/eth_sign.go @@ -8,22 +8,22 @@ import ( "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/utils" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" - "github.com/qtumproject/janus/pkg/utils" ) // ProxyETHGetLogs implements ETHProxy type ProxyETHSign struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyETHSign) Method() string { return "eth_sign" } -func (p *ProxyETHSign) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHSign) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { var req eth.SignRequest if err := unmarshalRequest(rawreq.Params, &req); err != nil { p.GetDebugLogger().Log("method", p.Method(), "error", err) @@ -33,7 +33,7 @@ func (p *ProxyETHSign) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (inte addr := utils.RemoveHexPrefix(req.Account) - acc := p.Qtum.Accounts.FindByHexAddress(addr) + acc := p.Kaon.Accounts.FindByHexAddress(addr) if acc == nil { p.GetDebugLogger().Log("method", p.Method(), "account", addr, "msg", "Unknown account") return nil, eth.NewInvalidParamsError(fmt.Sprintf("No such account: %s", addr)) @@ -58,12 +58,12 @@ func signMessage(key *btcec.PrivateKey, msg []byte) ([]byte, error) { return btcec.SignCompact(secp256k1, key, msghash, true) } -var qtumSignMessagePrefix = []byte("\u0015Qtum Signed Message:\n") +var kaonSignMessagePrefix = []byte("\u0015Kaon Signed Message:\n") func paddedMessage(msg []byte) []byte { var wbuf bytes.Buffer - wbuf.Write(qtumSignMessagePrefix) + wbuf.Write(kaonSignMessagePrefix) var msglenbuf [binary.MaxVarintLen64]byte msglen := binary.PutUvarint(msglenbuf[:], uint64(len(msg))) diff --git a/pkg/transformer/eth_signTransaction.go b/pkg/transformer/eth_signTransaction.go index ee6d840b..a62d383a 100644 --- a/pkg/transformer/eth_signTransaction.go +++ b/pkg/transformer/eth_signTransaction.go @@ -5,23 +5,23 @@ import ( "fmt" "strings" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/utils" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" - "github.com/qtumproject/janus/pkg/utils" "github.com/shopspring/decimal" ) // ProxyETHSendTransaction implements ETHProxy type ProxyETHSignTransaction struct { - *qtum.Qtum + *kaon.Kaon } func (p *ProxyETHSignTransaction) Method() string { return "eth_signTransaction" } -func (p *ProxyETHSignTransaction) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHSignTransaction) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { var req eth.SendTransactionRequest if err := unmarshalRequest(rawreq.Params, &req); err != nil { // TODO: Correct error code? @@ -46,27 +46,27 @@ func (p *ProxyETHSignTransaction) Request(rawreq *eth.JSONRPCRequest, c echo.Con return nil, eth.NewInvalidParamsError("Unknown operation") } -func (p *ProxyETHSignTransaction) getRequiredUtxos(ctx context.Context, from string, neededAmount decimal.Decimal) ([]qtum.RawTxInputs, decimal.Decimal, error) { - //convert address to qtum address +func (p *ProxyETHSignTransaction) getRequiredUtxos(ctx context.Context, from string, neededAmount decimal.Decimal) ([]kaon.RawTxInputs, decimal.Decimal, error) { + //convert address to Kaon address addr := utils.RemoveHexPrefix(from) base58Addr, err := p.FromHexAddress(addr) if err != nil { return nil, decimal.Decimal{}, err } // need to get utxos with txid and vouts. In order to do this we get a list of unspent transactions and begin summing them up - var getaddressutxos *qtum.GetAddressUTXOsRequest = &qtum.GetAddressUTXOsRequest{Addresses: []string{base58Addr}} - qtumresp, err := p.GetAddressUTXOs(ctx, getaddressutxos) + var getaddressutxos *kaon.GetAddressUTXOsRequest = &kaon.GetAddressUTXOsRequest{Addresses: []string{base58Addr}} + kaonresp, err := p.GetAddressUTXOs(ctx, getaddressutxos) if err != nil { return nil, decimal.Decimal{}, err } //Convert minSumAmount to Satoshis - minimumSum := convertFromQtumToSatoshis(neededAmount) - var utxos []qtum.RawTxInputs + minimumSum := convertFromKaonToSatoshis(neededAmount) + var utxos []kaon.RawTxInputs var minUTXOsSum decimal.Decimal - for _, utxo := range *qtumresp { - minUTXOsSum = minUTXOsSum.Add(utxo.Satoshis) - utxos = append(utxos, qtum.RawTxInputs{TxID: utxo.TXID, Vout: utxo.OutputIndex}) + for _, utxo := range *kaonresp { + minUTXOsSum = minUTXOsSum.Add(utxo.Satoshis.Decimal) + utxos = append(utxos, kaon.RawTxInputs{TxID: utxo.TXID, Vout: utxo.OutputIndex}) if minUTXOsSum.GreaterThanOrEqual(minimumSum) { return utxos, minUTXOsSum, nil } @@ -86,8 +86,8 @@ func calculateNeededAmount(value, gasLimit, gasPrice decimal.Decimal) decimal.De return value.Add(gasLimit.Mul(gasPrice)) } -func (p *ProxyETHSignTransaction) requestSendToContract(ctx context.Context, ethtx *eth.SendTransactionRequest) (string, eth.JSONRPCError) { - gasLimit, gasPrice, err := EthGasToQtum(ethtx) +func (p *ProxyETHSignTransaction) requestSendToContract(ctx context.Context, ethtx *eth.SendTransactionRequest) (string, *eth.JSONRPCError) { + gasLimit, gasPrice, err := EthGasToKaon(ethtx) if err != nil { return "", eth.NewInvalidParamsError(err.Error()) } @@ -95,7 +95,7 @@ func (p *ProxyETHSignTransaction) requestSendToContract(ctx context.Context, eth amount := decimal.NewFromFloat(0.0) if ethtx.Value != "" { var err error - amount, err = EthValueToQtumAmount(ethtx.Value, ZeroSatoshi) + amount, err = EthValueToKaonAmount(ethtx.Value, ZeroSatoshi) if err != nil { return "", eth.NewInvalidParamsError(err.Error()) } @@ -105,7 +105,11 @@ func (p *ProxyETHSignTransaction) requestSendToContract(ctx context.Context, eth if err != nil { return "", eth.NewInvalidParamsError(err.Error()) } - neededAmount := calculateNeededAmount(amount, decimal.NewFromBigInt(gasLimit, 0), newGasPrice) + gasLimitFormatted, errEncode := utils.ToDecimal(gasLimit) + if errEncode != nil { + return "", eth.NewCallbackError("something went wrong with signing the transaction; transaction incomplete") + } + neededAmount := calculateNeededAmount(amount, *gasLimitFormatted, newGasPrice) inputs, balance, err := p.getRequiredUtxos(ctx, ethtx.From, neededAmount) if err != nil { @@ -117,10 +121,10 @@ func (p *ProxyETHSignTransaction) requestSendToContract(ctx context.Context, eth return "", eth.NewCallbackError(err.Error()) } - contractInteractTx := &qtum.SendToContractRawRequest{ + contractInteractTx := &kaon.SendToContractRawRequest{ ContractAddress: utils.RemoveHexPrefix(ethtx.To), Datahex: utils.RemoveHexPrefix(ethtx.Data), - Amount: amount, + Amount: kaon.TransformAmount(amount), GasLimit: gasLimit, GasPrice: gasPrice, } @@ -135,19 +139,19 @@ func (p *ProxyETHSignTransaction) requestSendToContract(ctx context.Context, eth fromAddr := utils.RemoveHexPrefix(ethtx.From) - acc := p.Qtum.Accounts.FindByHexAddress(strings.ToLower(fromAddr)) + acc := p.Kaon.Accounts.FindByHexAddress(strings.ToLower(fromAddr)) if acc == nil { return "", eth.NewInvalidParamsError(fmt.Sprintf("No such account: %s", fromAddr)) } - rawtxreq := []interface{}{inputs, []interface{}{map[string]*qtum.SendToContractRawRequest{"contract": contractInteractTx}, map[string]decimal.Decimal{contractInteractTx.SenderAddress: change}}} + rawtxreq := []interface{}{inputs, []interface{}{map[string]*kaon.SendToContractRawRequest{"contract": contractInteractTx}, map[string]decimal.Decimal{contractInteractTx.SenderAddress: change}}} var rawTx string - if err := p.Qtum.Request(qtum.MethodCreateRawTx, rawtxreq, &rawTx); err != nil { + if err := p.Kaon.Request(kaon.MethodCreateRawTx, rawtxreq, &rawTx); err != nil { return "", eth.NewCallbackError(err.Error()) } - var resp *qtum.SignRawTxResponse - if err := p.Qtum.Request(qtum.MethodSignRawTx, []interface{}{rawTx}, &resp); err != nil { + var resp *kaon.SignRawTxResponse + if err := p.Kaon.Request(kaon.MethodSignRawTx, []interface{}{rawTx}, &resp); err != nil { return "", eth.NewCallbackError(err.Error()) } if !resp.Complete { @@ -156,25 +160,25 @@ func (p *ProxyETHSignTransaction) requestSendToContract(ctx context.Context, eth return utils.AddHexPrefix(resp.Hex), nil } -func (p *ProxyETHSignTransaction) requestSendToAddress(ctx context.Context, req *eth.SendTransactionRequest) (string, eth.JSONRPCError) { - getQtumWalletAddress := func(addr string) (string, error) { +func (p *ProxyETHSignTransaction) requestSendToAddress(ctx context.Context, req *eth.SendTransactionRequest) (string, *eth.JSONRPCError) { + getKaonWalletAddress := func(addr string) (string, error) { if utils.IsEthHexAddress(addr) { return p.FromHexAddress(utils.RemoveHexPrefix(addr)) } return addr, nil } - to, err := getQtumWalletAddress(req.To) + to, err := getKaonWalletAddress(req.To) if err != nil { return "", eth.NewCallbackError(err.Error()) } - from, err := getQtumWalletAddress(req.From) + from, err := getKaonWalletAddress(req.From) if err != nil { return "", eth.NewCallbackError(err.Error()) } - amount, err := EthValueToQtumAmount(req.Value, ZeroSatoshi) + amount, err := EthValueToKaonAmount(req.Value, ZeroSatoshi) if err != nil { return "", eth.NewInvalidParamsError(err.Error()) } @@ -192,13 +196,13 @@ func (p *ProxyETHSignTransaction) requestSendToAddress(ctx context.Context, req var addressValMap = map[string]decimal.Decimal{to: amount, from: change} rawtxreq := []interface{}{inputs, addressValMap} var rawTx string - if err := p.Qtum.Request(qtum.MethodCreateRawTx, rawtxreq, &rawTx); err != nil { + if err := p.Kaon.Request(kaon.MethodCreateRawTx, rawtxreq, &rawTx); err != nil { return "", eth.NewCallbackError(err.Error()) } - var resp *qtum.SignRawTxResponse + var resp *kaon.SignRawTxResponse signrawtxreq := []interface{}{rawTx} - if err := p.Qtum.Request(qtum.MethodSignRawTx, signrawtxreq, &resp); err != nil { + if err := p.Kaon.Request(kaon.MethodSignRawTx, signrawtxreq, &resp); err != nil { return "", eth.NewCallbackError(err.Error()) } if !resp.Complete { @@ -207,8 +211,8 @@ func (p *ProxyETHSignTransaction) requestSendToAddress(ctx context.Context, req return utils.AddHexPrefix(resp.Hex), nil } -func (p *ProxyETHSignTransaction) requestCreateContract(ctx context.Context, req *eth.SendTransactionRequest) (string, eth.JSONRPCError) { - gasLimit, gasPrice, err := EthGasToQtum(req) +func (p *ProxyETHSignTransaction) requestCreateContract(ctx context.Context, req *eth.SendTransactionRequest) (string, *eth.JSONRPCError) { + gasLimit, gasPrice, err := EthGasToKaon(req) if err != nil { return "", eth.NewInvalidParamsError(err.Error()) } @@ -221,7 +225,7 @@ func (p *ProxyETHSignTransaction) requestCreateContract(ctx context.Context, req } } - contractDeploymentTx := &qtum.CreateContractRawRequest{ + contractDeploymentTx := &kaon.CreateContractRawRequest{ ByteCode: utils.RemoveHexPrefix(req.Data), GasLimit: gasLimit, GasPrice: gasPrice, @@ -232,7 +236,11 @@ func (p *ProxyETHSignTransaction) requestCreateContract(ctx context.Context, req if err != nil { return "", eth.NewInvalidParamsError(err.Error()) } - neededAmount := calculateNeededAmount(decimal.NewFromFloat(0.0), decimal.NewFromBigInt(gasLimit, 0), newGasPrice) + gasLimitFormatted, errEncode := utils.ToDecimal(gasLimit) + if errEncode != nil { + return "", eth.NewCallbackError("something went wrong with signing the transaction; transaction incomplete") + } + neededAmount := calculateNeededAmount(decimal.NewFromFloat(0.0), *gasLimitFormatted, newGasPrice) inputs, balance, err := p.getRequiredUtxos(ctx, req.From, neededAmount) if err != nil { @@ -244,15 +252,15 @@ func (p *ProxyETHSignTransaction) requestCreateContract(ctx context.Context, req return "", eth.NewCallbackError(err.Error()) } - rawtxreq := []interface{}{inputs, []interface{}{map[string]*qtum.CreateContractRawRequest{"contract": contractDeploymentTx}, map[string]decimal.Decimal{from: change}}} + rawtxreq := []interface{}{inputs, []interface{}{map[string]*kaon.CreateContractRawRequest{"contract": contractDeploymentTx}, map[string]decimal.Decimal{from: change}}} var rawTx string - if err := p.Qtum.Request(qtum.MethodCreateRawTx, rawtxreq, &rawTx); err != nil { + if err := p.Kaon.Request(kaon.MethodCreateRawTx, rawtxreq, &rawTx); err != nil { return "", eth.NewCallbackError(err.Error()) } - var resp *qtum.SignRawTxResponse + var resp *kaon.SignRawTxResponse signrawtxreq := []interface{}{rawTx} - if err := p.Qtum.Request(qtum.MethodSignRawTx, signrawtxreq, &resp); err != nil { + if err := p.Kaon.Request(kaon.MethodSignRawTx, signrawtxreq, &resp); err != nil { return "", eth.NewCallbackError(err.Error()) } if !resp.Complete { diff --git a/pkg/transformer/eth_subscribe.go b/pkg/transformer/eth_subscribe.go index de32e60d..5573be99 100644 --- a/pkg/transformer/eth_subscribe.go +++ b/pkg/transformer/eth_subscribe.go @@ -1,15 +1,15 @@ package transformer import ( + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/notifier" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/notifier" - "github.com/qtumproject/janus/pkg/qtum" ) // ETHSubscribe implements ETHProxy type ETHSubscribe struct { - *qtum.Qtum + *kaon.Kaon *notifier.Agent } @@ -17,7 +17,7 @@ func (p *ETHSubscribe) Method() string { return "eth_subscribe" } -func (p *ETHSubscribe) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ETHSubscribe) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { notifier := getNotifier(c) if notifier == nil { p.GetLogger().Log("msg", "eth_subscribe only supported over websocket") @@ -44,7 +44,7 @@ func (p *ETHSubscribe) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (inte return p.request(&req, notifier) } -func (p *ETHSubscribe) request(req *eth.EthSubscriptionRequest, notifier *notifier.Notifier) (*eth.EthSubscriptionResponse, eth.JSONRPCError) { +func (p *ETHSubscribe) request(req *eth.EthSubscriptionRequest, notifier *notifier.Notifier) (*eth.EthSubscriptionResponse, *eth.JSONRPCError) { notifier.ResponseRequired() id, err := p.NewSubscription(notifier, req) response := eth.EthSubscriptionResponse(id) diff --git a/pkg/transformer/eth_uninstallFilter.go b/pkg/transformer/eth_uninstallFilter.go index 1c48f4ba..110cb34e 100644 --- a/pkg/transformer/eth_uninstallFilter.go +++ b/pkg/transformer/eth_uninstallFilter.go @@ -2,14 +2,14 @@ package transformer import ( "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" ) // ProxyETHUninstallFilter implements ETHProxy type ProxyETHUninstallFilter struct { - *qtum.Qtum + *kaon.Kaon filter *eth.FilterSimulator } @@ -17,7 +17,7 @@ func (p *ProxyETHUninstallFilter) Method() string { return "eth_uninstallFilter" } -func (p *ProxyETHUninstallFilter) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyETHUninstallFilter) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { var req eth.UninstallFilterRequest if err := unmarshalRequest(rawreq.Params, &req); err != nil { // TODO: Correct error code? @@ -27,7 +27,7 @@ func (p *ProxyETHUninstallFilter) Request(rawreq *eth.JSONRPCRequest, c echo.Con return p.request(&req) } -func (p *ProxyETHUninstallFilter) request(ethreq *eth.UninstallFilterRequest) (eth.UninstallFilterResponse, eth.JSONRPCError) { +func (p *ProxyETHUninstallFilter) request(ethreq *eth.UninstallFilterRequest) (eth.UninstallFilterResponse, *eth.JSONRPCError) { id, err := hexutil.DecodeUint64(string(*ethreq)) if err != nil { return false, eth.NewInvalidParamsError(err.Error()) diff --git a/pkg/transformer/eth_unsubscribe.go b/pkg/transformer/eth_unsubscribe.go index 81ed621b..674a22b8 100644 --- a/pkg/transformer/eth_unsubscribe.go +++ b/pkg/transformer/eth_unsubscribe.go @@ -1,15 +1,15 @@ package transformer import ( + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/notifier" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/notifier" - "github.com/qtumproject/janus/pkg/qtum" ) // ETHUnsubscribe implements ETHProxy type ETHUnsubscribe struct { - *qtum.Qtum + *kaon.Kaon *notifier.Agent } @@ -17,7 +17,7 @@ func (p *ETHUnsubscribe) Method() string { return "eth_unsubscribe" } -func (p *ETHUnsubscribe) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ETHUnsubscribe) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { notifier := getNotifier(c) if notifier == nil { p.GetLogger().Log("msg", "eth_unsubscribe only supported over websocket") @@ -44,7 +44,7 @@ func (p *ETHUnsubscribe) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (in return p.request(&req, notifier) } -func (p *ETHUnsubscribe) request(req *eth.EthUnsubscribeRequest, notifier *notifier.Notifier) (eth.EthUnsubscribeResponse, eth.JSONRPCError) { +func (p *ETHUnsubscribe) request(req *eth.EthUnsubscribeRequest, notifier *notifier.Notifier) (eth.EthUnsubscribeResponse, *eth.JSONRPCError) { if len(*req) != 1 { // TODO: Correct error code? return false, eth.NewInvalidParamsError("requires one parameter") diff --git a/pkg/transformer/qtum_generate.go b/pkg/transformer/kaon_generate.go similarity index 73% rename from pkg/transformer/qtum_generate.go rename to pkg/transformer/kaon_generate.go index e1353c94..fb116410 100644 --- a/pkg/transformer/qtum_generate.go +++ b/pkg/transformer/kaon_generate.go @@ -4,23 +4,23 @@ import ( "reflect" "strconv" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/utils" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" - "github.com/qtumproject/janus/pkg/utils" ) -type ProxyQTUMGenerateToAddress struct { - *qtum.Qtum +type ProxyKAONGenerateToAddress struct { + *kaon.Kaon } -var _ ETHProxy = (*ProxyQTUMGenerateToAddress)(nil) +var _ ETHProxy = (*ProxyKAONGenerateToAddress)(nil) -func (p *ProxyQTUMGenerateToAddress) Method() string { +func (p *ProxyKAONGenerateToAddress) Method() string { return "dev_generatetoaddress" } -func (p *ProxyQTUMGenerateToAddress) Request(req *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyKAONGenerateToAddress) Request(req *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { if !p.CanGenerate() { return nil, eth.NewInvalidRequestError("Can only generate on regtest") } @@ -38,7 +38,7 @@ func (p *ProxyQTUMGenerateToAddress) Request(req *eth.JSONRPCRequest, c echo.Con return p.request(params) } -func (p *ProxyQTUMGenerateToAddress) request(params []interface{}) (*[]string, eth.JSONRPCError) { +func (p *ProxyKAONGenerateToAddress) request(params []interface{}) (*[]string, *eth.JSONRPCError) { blocks := params[0] generateTo, ok := params[1].(string) if !ok { @@ -71,7 +71,7 @@ func (p *ProxyQTUMGenerateToAddress) request(params []interface{}) (*[]string, e } var response []string - err = p.Client.Request(qtum.MethodGenerateToAddress, []interface{}{blocksInteger, base58Address}, &response) + err = p.Client.Request(kaon.MethodGenerateToAddress, []interface{}{blocksInteger, base58Address}, &response) if err != nil { return nil, eth.NewInvalidRequestError(err.Error()) } diff --git a/pkg/transformer/qtum_genericStringArguments.go b/pkg/transformer/kaon_genericStringArguments.go similarity index 55% rename from pkg/transformer/qtum_genericStringArguments.go rename to pkg/transformer/kaon_genericStringArguments.go index f1d027a0..4a0e5dd2 100644 --- a/pkg/transformer/qtum_genericStringArguments.go +++ b/pkg/transformer/kaon_genericStringArguments.go @@ -1,24 +1,24 @@ package transformer import ( + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" ) -type ProxyQTUMGenericStringArguments struct { - *qtum.Qtum +type ProxyKAONGenericStringArguments struct { + *kaon.Kaon prefix string method string } -var _ ETHProxy = (*ProxyQTUMGenericStringArguments)(nil) +var _ ETHProxy = (*ProxyKAONGenericStringArguments)(nil) -func (p *ProxyQTUMGenericStringArguments) Method() string { +func (p *ProxyKAONGenericStringArguments) Method() string { return p.prefix + "_" + p.method } -func (p *ProxyQTUMGenericStringArguments) Request(req *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyKAONGenericStringArguments) Request(req *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { var params eth.StringsArguments if err := unmarshalRequest(req.Params, ¶ms); err != nil { // TODO: Correct error code? @@ -26,13 +26,13 @@ func (p *ProxyQTUMGenericStringArguments) Request(req *eth.JSONRPCRequest, c ech } if len(params) != 1 { - return nil, eth.NewInvalidParamsError("require 1 argument: the base58 Qtum address") + return nil, eth.NewInvalidParamsError("require 1 argument: the base58 Kaon address") } return p.request(params) } -func (p *ProxyQTUMGenericStringArguments) request(params eth.StringsArguments) (*string, eth.JSONRPCError) { +func (p *ProxyKAONGenericStringArguments) request(params eth.StringsArguments) (*string, *eth.JSONRPCError) { var response string err := p.Client.Request(p.method, params, &response) if err != nil { diff --git a/pkg/transformer/qtum_getUTXOs.go b/pkg/transformer/kaon_getUTXOs.go similarity index 71% rename from pkg/transformer/qtum_getUTXOs.go rename to pkg/transformer/kaon_getUTXOs.go index 7098c743..35c739b1 100644 --- a/pkg/transformer/qtum_getUTXOs.go +++ b/pkg/transformer/kaon_getUTXOs.go @@ -5,24 +5,24 @@ import ( "fmt" "math/big" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/utils" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" - "github.com/qtumproject/janus/pkg/utils" "github.com/shopspring/decimal" ) -type ProxyQTUMGetUTXOs struct { - *qtum.Qtum +type ProxyKAONGetUTXOs struct { + *kaon.Kaon } -var _ ETHProxy = (*ProxyQTUMGetUTXOs)(nil) +var _ ETHProxy = (*ProxyKAONGetUTXOs)(nil) -func (p *ProxyQTUMGetUTXOs) Method() string { - return "qtum_getUTXOs" +func (p *ProxyKAONGetUTXOs) Method() string { + return "kaon_getUTXOs" } -func (p *ProxyQTUMGetUTXOs) Request(req *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *ProxyKAONGetUTXOs) Request(req *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { var params eth.GetUTXOsRequest if err := unmarshalRequest(req.Params, ¶ms); err != nil { // TODO: Correct error code? @@ -38,30 +38,30 @@ func (p *ProxyQTUMGetUTXOs) Request(req *eth.JSONRPCRequest, c echo.Context) (in return p.request(c.Request().Context(), params) } -func (p *ProxyQTUMGetUTXOs) request(ctx context.Context, params eth.GetUTXOsRequest) (*eth.GetUTXOsResponse, eth.JSONRPCError) { +func (p *ProxyKAONGetUTXOs) request(ctx context.Context, params eth.GetUTXOsRequest) (*eth.GetUTXOsResponse, *eth.JSONRPCError) { address, err := convertETHAddress(utils.RemoveHexPrefix(params.Address), p.Chain()) if err != nil { - return nil, eth.NewInvalidParamsError("couldn't convert Ethereum address to Qtum address") + return nil, eth.NewInvalidParamsError("couldn't convert Ethereum address to Kaon address") } - req := qtum.GetAddressUTXOsRequest{ + req := kaon.GetAddressUTXOsRequest{ Addresses: []string{address}, } - resp, err := p.Qtum.GetAddressUTXOs(ctx, &req) + resp, err := p.Kaon.GetAddressUTXOs(ctx, &req) if err != nil { return nil, eth.NewCallbackError(err.Error()) } - blockCount, err := p.Qtum.GetBlockCount(ctx) + blockCount, err := p.Kaon.GetBlockCount(ctx) if err != nil { return nil, eth.NewCallbackError(err.Error()) } - matureBlockHeight := big.NewInt(int64(p.Qtum.GetMatureBlockHeight())) + matureBlockHeight := big.NewInt(int64(p.Kaon.GetMatureBlockHeight())) //Convert minSumAmount to Satoshis - minimumSum := convertFromQtumToSatoshis(params.MinSumAmount) + minimumSum := convertFromKaonToSatoshis(params.MinSumAmount) queryingAll := minimumSum.Equal(decimal.Zero) allUtxoTypes := false @@ -78,7 +78,7 @@ func (p *ProxyQTUMGetUTXOs) request(ctx context.Context, params eth.GetUTXOsRequ utxoTypes[typ] = true } - var utxos []eth.QtumUTXO + var utxos []eth.KaonUTXO var minUTXOsSum decimal.Decimal for _, utxo := range *resp { ethUTXO := toEthResponseType(utxo) @@ -93,7 +93,6 @@ func (p *ProxyQTUMGetUTXOs) request(ctx context.Context, params eth.GetUTXOsRequ } } - // TODO: This doesn't work on regtest coinbase if utxo.IsStake { matureAt := big.NewInt(utxo.Height.Int64()).Add( big.NewInt(utxo.Height.Int64()), @@ -117,7 +116,7 @@ func (p *ProxyQTUMGetUTXOs) request(ctx context.Context, params eth.GetUTXOsRequ ethUTXO.Spendable = true if ethUTXO.Safe { - minUTXOsSum = minUTXOsSum.Add(utxo.Satoshis) + minUTXOsSum = minUTXOsSum.Add(utxo.Satoshis.Decimal) } utxos = append(utxos, ethUTXO) if !queryingAll && minUTXOsSum.GreaterThanOrEqual(minimumSum) { @@ -132,11 +131,11 @@ func (p *ProxyQTUMGetUTXOs) request(ctx context.Context, params eth.GetUTXOsRequ return nil, eth.NewCallbackError("required minimum amount is greater than total amount of UTXOs") } -func toEthResponseType(utxo qtum.UTXO) eth.QtumUTXO { - return eth.QtumUTXO{ +func toEthResponseType(utxo kaon.UTXO) eth.KaonUTXO { + return eth.KaonUTXO{ Address: utxo.Address, TXID: utxo.TXID, Vout: utxo.OutputIndex, - Amount: convertFromSatoshisToQtum(utxo.Satoshis).String(), + Amount: convertFromSatoshisToKaon(utxo.Satoshis.Decimal).String(), } } diff --git a/pkg/transformer/log.go b/pkg/transformer/log.go index ffaf98e8..9b1f595d 100644 --- a/pkg/transformer/log.go +++ b/pkg/transformer/log.go @@ -3,25 +3,25 @@ package transformer import ( "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" ) -func GetLogger(proxy ETHProxy, q *qtum.Qtum) log.Logger { +func GetLogger(proxy ETHProxy, q *kaon.Kaon) log.Logger { method := proxy.Method() logger := q.Client.GetLogger() return log.WithPrefix(level.Info(logger), method) } func GetLoggerFromETHCall(proxy *ProxyETHCall) log.Logger { - return GetLogger(proxy, proxy.Qtum) + return GetLogger(proxy, proxy.Kaon) } -func GetDebugLogger(proxy ETHProxy, q *qtum.Qtum) log.Logger { +func GetDebugLogger(proxy ETHProxy, q *kaon.Kaon) log.Logger { method := proxy.Method() logger := q.Client.GetDebugLogger() return log.WithPrefix(level.Debug(logger), method) } func GetDebugLoggerFromETHCall(proxy *ProxyETHCall) log.Logger { - return GetDebugLogger(proxy, proxy.Qtum) + return GetDebugLogger(proxy, proxy.Kaon) } diff --git a/pkg/transformer/notifier.go b/pkg/transformer/notifier.go index 8e3d9039..51f21f8c 100644 --- a/pkg/transformer/notifier.go +++ b/pkg/transformer/notifier.go @@ -1,8 +1,8 @@ package transformer import ( + "github.com/kaonone/eth-rpc-gate/pkg/notifier" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/notifier" ) func getNotifier(c echo.Context) *notifier.Notifier { diff --git a/pkg/transformer/tests_common.go b/pkg/transformer/tests_common.go index 0cd30f2d..b10ba388 100644 --- a/pkg/transformer/tests_common.go +++ b/pkg/transformer/tests_common.go @@ -4,11 +4,11 @@ import ( "encoding/json" "testing" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" ) -type ETHProxyInitializer = func(*qtum.Qtum) ETHProxy +type ETHProxyInitializer = func(*kaon.Kaon) ETHProxy func testETHProxyRequest(t *testing.T, initializer ETHProxyInitializer, requestParams []json.RawMessage, want interface{}) { request, err := internal.PrepareEthRPCRequest(1, requestParams) @@ -17,12 +17,12 @@ func testETHProxyRequest(t *testing.T, initializer ETHProxyInitializer, requestP } mockedClientDoer := internal.NewDoerMappedMock() - qtumClient, err := internal.CreateMockedClient(mockedClientDoer) + kaonClient, err := internal.CreateMockedClient(mockedClientDoer) internal.SetupGetBlockByHashResponses(t, mockedClientDoer) //preparing proxy & executing request - proxyEth := initializer(qtumClient) + proxyEth := initializer(kaonClient) got, jsonErr := proxyEth.Request(request, internal.NewEchoContext()) if jsonErr != nil { t.Fatalf("Failed to process request on %T.Request(%s): %s", proxyEth, requestParams, jsonErr) diff --git a/pkg/transformer/transformer.go b/pkg/transformer/transformer.go index 46216563..4382e526 100644 --- a/pkg/transformer/transformer.go +++ b/pkg/transformer/transformer.go @@ -2,28 +2,28 @@ package transformer import ( "github.com/go-kit/kit/log" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/notifier" "github.com/labstack/echo" "github.com/pkg/errors" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/notifier" - "github.com/qtumproject/janus/pkg/qtum" ) type Transformer struct { - qtumClient *qtum.Qtum + kaonClient *kaon.Kaon debugMode bool logger log.Logger transformers map[string]ETHProxy } // New creates a new Transformer -func New(qtumClient *qtum.Qtum, proxies []ETHProxy, opts ...Option) (*Transformer, error) { - if qtumClient == nil { - return nil, errors.New("qtumClient cannot be nil") +func New(kaonClient *kaon.Kaon, proxies []ETHProxy, opts ...Option) (*Transformer, error) { + if kaonClient == nil { + return nil, errors.New("kaonClient cannot be nil") } t := &Transformer{ - qtumClient: qtumClient, + kaonClient: kaonClient, logger: log.NewNopLogger(), } @@ -60,7 +60,7 @@ func (t *Transformer) Register(p ETHProxy) error { } // Transform takes a Transformer and transforms the request from ETH request and returns the proxy request -func (t *Transformer) Transform(req *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (t *Transformer) Transform(req *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { proxy, err := t.getProxy(req.Method) if err != nil { return nil, err @@ -72,7 +72,7 @@ func (t *Transformer) Transform(req *eth.JSONRPCRequest, c echo.Context) (interf return resp, nil } -func (t *Transformer) getProxy(method string) (ETHProxy, eth.JSONRPCError) { +func (t *Transformer) getProxy(method string) (ETHProxy, *eth.JSONRPCError) { proxy, ok := t.transformers[method] if !ok { return nil, eth.NewMethodNotFoundError(method) @@ -85,39 +85,42 @@ func (t *Transformer) IsDebugEnabled() bool { } // DefaultProxies are the default proxy methods made available -func DefaultProxies(qtumRPCClient *qtum.Qtum, agent *notifier.Agent) []ETHProxy { +func DefaultProxies(kaonRPCClient *kaon.Kaon, agent *notifier.Agent) []ETHProxy { filter := eth.NewFilterSimulator() - getFilterChanges := &ProxyETHGetFilterChanges{Qtum: qtumRPCClient, filter: filter} - ethCall := &ProxyETHCall{Qtum: qtumRPCClient} + getFilterChanges := &ProxyETHGetFilterChanges{Kaon: kaonRPCClient, filter: filter} + ethCall := &ProxyETHCall{Kaon: kaonRPCClient} ethProxies := []ETHProxy{ ethCall, - &ProxyNetListening{Qtum: qtumRPCClient}, + &ProxyNetListening{Kaon: kaonRPCClient}, &ProxyETHPersonalUnlockAccount{}, - &ProxyETHChainId{Qtum: qtumRPCClient}, - &ProxyETHBlockNumber{Qtum: qtumRPCClient}, - &ProxyETHHashrate{Qtum: qtumRPCClient}, - &ProxyETHMining{Qtum: qtumRPCClient}, - &ProxyETHNetVersion{Qtum: qtumRPCClient}, - &ProxyETHGetTransactionByHash{Qtum: qtumRPCClient}, - &ProxyETHGetTransactionByBlockNumberAndIndex{Qtum: qtumRPCClient}, - &ProxyETHGetLogs{Qtum: qtumRPCClient}, - &ProxyETHGetTransactionReceipt{Qtum: qtumRPCClient}, - &ProxyETHSendTransaction{Qtum: qtumRPCClient}, - &ProxyETHAccounts{Qtum: qtumRPCClient}, - &ProxyETHGetCode{Qtum: qtumRPCClient}, - - &ProxyETHNewFilter{Qtum: qtumRPCClient, filter: filter}, - &ProxyETHNewBlockFilter{Qtum: qtumRPCClient, filter: filter}, + &ProxyETHChainId{Kaon: kaonRPCClient}, + &ProxyETHBlockNumber{Kaon: kaonRPCClient}, + &ProxyETHHashrate{Kaon: kaonRPCClient}, + &ProxyETHMining{Kaon: kaonRPCClient}, + &ProxyETHNetVersion{Kaon: kaonRPCClient}, + &ProxyETHGetTransactionByHash{Kaon: kaonRPCClient}, + &ProxyETHGetTransactionByBlockNumberAndIndex{Kaon: kaonRPCClient}, + &ProxyETHGetLogs{Kaon: kaonRPCClient}, + &ProxyETHGetTransactionReceipt{Kaon: kaonRPCClient}, + &ProxyETHSendTransaction{Kaon: kaonRPCClient}, + &ProxyETHDebugTraceBlockByNumber{Kaon: kaonRPCClient}, + &ProxyETHTraceBlock{Kaon: kaonRPCClient}, + &ProxyETHDebugTraceTransaction{Kaon: kaonRPCClient}, + &ProxyETHAccounts{Kaon: kaonRPCClient}, + &ProxyETHGetCode{Kaon: kaonRPCClient}, + + &ProxyETHNewFilter{Kaon: kaonRPCClient, filter: filter}, + &ProxyETHNewBlockFilter{Kaon: kaonRPCClient, filter: filter}, getFilterChanges, &ProxyETHGetFilterLogs{ProxyETHGetFilterChanges: getFilterChanges}, - &ProxyETHUninstallFilter{Qtum: qtumRPCClient, filter: filter}, + &ProxyETHUninstallFilter{Kaon: kaonRPCClient, filter: filter}, &ProxyETHEstimateGas{ProxyETHCall: ethCall}, - &ProxyETHGetBlockByNumber{Qtum: qtumRPCClient}, - &ProxyETHGetBlockByHash{Qtum: qtumRPCClient}, - &ProxyETHGetBalance{Qtum: qtumRPCClient}, - &ProxyETHGetStorageAt{Qtum: qtumRPCClient}, + &ProxyETHGetBlockByNumber{Kaon: kaonRPCClient}, + &ProxyETHGetBlockByHash{Kaon: kaonRPCClient}, + &ProxyETHGetBalance{Kaon: kaonRPCClient}, + &ProxyETHGetStorageAt{Kaon: kaonRPCClient}, ÐGetCompilers{}, ÐProtocolVersion{}, ÐGetUncleByBlockHashAndIndex{}, @@ -125,33 +128,33 @@ func DefaultProxies(qtumRPCClient *qtum.Qtum, agent *notifier.Agent) []ETHProxy ÐGetUncleCountByBlockNumber{}, &Web3ClientVersion{}, &Web3Sha3{}, - &ProxyETHSign{Qtum: qtumRPCClient}, - &ProxyETHGasPrice{Qtum: qtumRPCClient}, - &ProxyETHTxCount{Qtum: qtumRPCClient}, - &ProxyETHSignTransaction{Qtum: qtumRPCClient}, - &ProxyETHSendRawTransaction{Qtum: qtumRPCClient}, + &ProxyETHSign{Kaon: kaonRPCClient}, + &ProxyETHGasPrice{Kaon: kaonRPCClient}, + &ProxyETHTxCount{Kaon: kaonRPCClient}, + &ProxyETHSignTransaction{Kaon: kaonRPCClient}, + &ProxyETHSendRawTransaction{Kaon: kaonRPCClient}, - ÐSubscribe{Qtum: qtumRPCClient, Agent: agent}, - ÐUnsubscribe{Qtum: qtumRPCClient, Agent: agent}, + ÐSubscribe{Kaon: kaonRPCClient, Agent: agent}, + ÐUnsubscribe{Kaon: kaonRPCClient, Agent: agent}, - &ProxyQTUMGetUTXOs{Qtum: qtumRPCClient}, - &ProxyQTUMGenerateToAddress{Qtum: qtumRPCClient}, + &ProxyKAONGetUTXOs{Kaon: kaonRPCClient}, + &ProxyKAONGenerateToAddress{Kaon: kaonRPCClient}, - &ProxyNetPeerCount{Qtum: qtumRPCClient}, + &ProxyNetPeerCount{Kaon: kaonRPCClient}, } - permittedQtumCalls := []string{ - qtum.MethodGetHexAddress, - qtum.MethodFromHexAddress, + permittedKaonCalls := []string{ + kaon.MethodGetHexAddress, + kaon.MethodFromHexAddress, } - for _, qtumMethod := range permittedQtumCalls { + for _, kaonMethod := range permittedKaonCalls { ethProxies = append( ethProxies, - &ProxyQTUMGenericStringArguments{ - Qtum: qtumRPCClient, + &ProxyKAONGenericStringArguments{ + Kaon: kaonRPCClient, prefix: "dev", - method: qtumMethod, + method: kaonMethod, }, ) } diff --git a/pkg/transformer/type.go b/pkg/transformer/type.go index 2eefd071..a228f1a6 100644 --- a/pkg/transformer/type.go +++ b/pkg/transformer/type.go @@ -3,8 +3,8 @@ package transformer import ( "errors" + "github.com/kaonone/eth-rpc-gate/pkg/eth" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" ) var UnmarshalRequestErr = errors.New("Input is invalid") @@ -12,6 +12,6 @@ var UnmarshalRequestErr = errors.New("Input is invalid") type Option func(*Transformer) error type ETHProxy interface { - Request(*eth.JSONRPCRequest, echo.Context) (interface{}, eth.JSONRPCError) + Request(*eth.JSONRPCRequest, echo.Context) (interface{}, *eth.JSONRPCError) Method() string } diff --git a/pkg/transformer/util.go b/pkg/transformer/util.go index f8249d75..4147f095 100644 --- a/pkg/transformer/util.go +++ b/pkg/transformer/util.go @@ -11,28 +11,28 @@ import ( "strings" "github.com/btcsuite/btcutil/base58" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/qtum" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/kaonone/eth-rpc-gate/pkg/utils" "github.com/pkg/errors" - "github.com/qtumproject/janus/pkg/utils" "github.com/shopspring/decimal" ) var ZeroSatoshi = decimal.NewFromInt(0) -var OneSatoshi = decimal.NewFromFloat(0.00000001) -var MinimumGas = decimal.NewFromFloat(0.0000004) +var OneSatoshi = decimal.NewFromFloat(1e-18) +var MinimumGas = decimal.NewFromFloat(1e-9) type EthGas interface { GasHex() string GasPriceHex() string } -func EthGasToQtum(g EthGas) (gasLimit *big.Int, gasPrice string, err error) { +func EthGasToKaon(g EthGas) (gasLimit *big.Int, gasPrice string, err error) { gasLimit = g.(*eth.SendTransactionRequest).Gas.Int - gasPriceDecimal, err := EthValueToQtumAmount(g.GasPriceHex(), MinimumGas) + gasPriceDecimal, err := EthValueToKaonAmount(g.GasPriceHex(), MinimumGas) if err != nil { return nil, "0.0", err } @@ -44,10 +44,10 @@ func EthGasToQtum(g EthGas) (gasLimit *big.Int, gasPrice string, err error) { return } -func QtumGasToEth(g EthGas) (gasLimit *big.Int, gasPrice string, err error) { +func KaonGasToEth(g EthGas) (gasLimit *big.Int, gasPrice string, err error) { gasLimit = g.(*eth.SendTransactionRequest).Gas.Int - gasPriceDecimal, err := EthValueToQtumAmount(g.GasPriceHex(), MinimumGas) + gasPriceDecimal, err := EthValueToKaonAmount(g.GasPriceHex(), MinimumGas) if err != nil { return nil, "0.0", err } @@ -59,7 +59,7 @@ func QtumGasToEth(g EthGas) (gasLimit *big.Int, gasPrice string, err error) { return } -func EthValueToQtumAmount(val string, defaultValue decimal.Decimal) (decimal.Decimal, error) { +func EthValueToKaonAmount(val string, defaultValue decimal.Decimal) (decimal.Decimal, error) { if val == "" { return defaultValue, nil } @@ -74,55 +74,51 @@ func EthValueToQtumAmount(val string, defaultValue decimal.Decimal) (decimal.Dec return ZeroSatoshi, errors.New("decimal.NewFromString was not a success") } - return EthDecimalValueToQtumAmount(ethValDecimal), nil + return EthDecimalValueToKaonAmount(ethValDecimal), nil } -func EthDecimalValueToQtumAmount(ethValDecimal decimal.Decimal) decimal.Decimal { - // Convert Wei to Qtum - // 10000000000 - // one satoshi is 0.00000001 - // we need to drop precision for values smaller than that - // 1e-8? - maximumPrecision := ethValDecimal.Mul(decimal.NewFromFloat(float64(1e-9))).Floor() - // was 1e-10 - amount := maximumPrecision.Mul(decimal.NewFromFloat(float64(1e-9))) - - return amount +func EthDecimalValueToKaonAmount(ethValDecimal decimal.Decimal) decimal.Decimal { + return ethValDecimal } -func QtumValueToETHAmount(val string, defaultValue decimal.Decimal) (decimal.Decimal, error) { +func KaonValueToETHAmount(val string, defaultValue decimal.Decimal) (decimal.Decimal, error) { if val == "" { return defaultValue, nil } - qtumVal, err := utils.DecodeBig(val) + kaonVal, err := utils.DecodeBig(val) if err != nil { return ZeroSatoshi, err } - qtumValDecimal, err := decimal.NewFromString(qtumVal.String()) + kaonValDecimal, err := decimal.NewFromString(kaonVal.String()) if err != nil { return ZeroSatoshi, errors.New("decimal.NewFromString was not a success") } - return QtumDecimalValueToETHAmount(qtumValDecimal), nil + return KaonDecimalValueToETHAmount(kaonValDecimal), nil } -func QtumDecimalValueToETHAmount(qtumValDecimal decimal.Decimal) decimal.Decimal { - // Computes inverse of EthDecimalValueToQtumAmount - amount := qtumValDecimal.Div(decimal.NewFromFloat(float64(1e-18))) - - return amount +func KaonDecimalValueToETHAmount(kaonValDecimal decimal.Decimal) decimal.Decimal { + return kaonValDecimal } -func formatQtumAmount(amount decimal.Decimal) (string, error) { - decimalAmount := amount.Mul(decimal.NewFromFloat(float64(1e18))) +func formatKaonAmount(amount decimal.Decimal) (string, error) { + decimalAmount := amount //convert decimal to Integer - result := decimalAmount.BigInt() + result, err := utils.ToBigInt(&decimalAmount) + if err != nil { + return "0x0", err + } - if !decimalAmount.Equals(decimal.NewFromBigInt(result, 0)) { - return "0x0", errors.New("decimal.BigInt() was not a success") + check, err := utils.ToDecimal(result) + if err != nil { + return "0x0", err + } + + if !decimalAmount.Equals(*check) { + return "0x0", errors.New("decimal BigInt() was not a success") } return hexutil.EncodeBig(result), nil @@ -138,10 +134,10 @@ func unmarshalRequest(data []byte, v interface{}) error { // Function for getting the sender address of a non-contract transaction by ID. // Does not handle OP_SENDER addresses, because it is only present in contract TXs // -// TODO: Investigate if limitations on Qtum RPC command GetRawTransaction can cause issues here -// Brief explanation: A default config Qtum node can only serve this command for transactions in the mempool, so it will likely break for SOME setup at SOME point. +// TODO: Investigate if limitations on Kaon RPC command GetRawTransaction can cause issues here +// Brief explanation: A default config Kaon node can only serve this command for transactions in the mempool, so it will likely break for SOME setup at SOME point. // However the same info can be found with getblock verbosity = 2, so maybe use that instead? -func getNonContractTxSenderAddress(ctx context.Context, p *qtum.Qtum, tx *qtum.DecodedRawTransactionResponse) (string, error) { +func getNonContractTxSenderAddress(ctx context.Context, p *kaon.Kaon, tx *kaon.DecodedRawTransactionResponse) (string, error) { // Fetch raw Tx struct, which contains address data for Vins rawTx, err := p.GetRawTransaction(ctx, tx.ID, false) @@ -149,46 +145,102 @@ func getNonContractTxSenderAddress(ctx context.Context, p *qtum.Qtum, tx *qtum.D return "", errors.New("Couldn't get raw Transaction data from Transaction ID: " + err.Error()) } - // If Tx has no vins it's either a reward transaction or invalid/corrupt (Right?). This is outside the intended scope of this function, so throw an error + // If Tx has no vins it's invalid/corrupt. This is outside the intended scope of this function, so throw an error if len(rawTx.Vins) == 0 { return "", errors.New("Transaction has 0 Vins and thus no valid sender address") } // Take the address of the first Vin as sender address, as per design decision // TODO: Make this not loop, it's not necessary and can in theory produce unintended behavior without causing an error - // TODO (research): Is the raw TX Vin list always in the "correct" order? It has to be for this function to produce correct behavior for _, in := range rawTx.Vins { if len(in.Address) == 0 { continue } - hexAddress, err := utils.ConvertQtumAddress(in.Address) - if err != nil { - return "", err + hexAddress, err := utils.ConvertKaonAddress(in.Address) + if err == nil { + return utils.AddHexPrefix(hexAddress), nil + } else { + // P2Sh address(such as MUrenj2sPqEVTiNbHQ2RARiZYyTAAeKiDX) and BECH32 address (such as qc1qkt33x6hkrrlwlr6v59wptwy6zskyrjfe40y0lx) + // will cause ConvertKaonAddress to fall + hexAddress, err := p.Base58AddressToHex(in.Address) + if err == nil { + return utils.AddHexPrefix(hexAddress), nil + } else { + return "", err + } } - return utils.AddHexPrefix(hexAddress), nil } + return "", errors.New("Couldn't find sender address the transaction") + + // This actually will produce unexpected behaviour + // TODO: remove after testing // If we get here, we have no Vins with a valid address, so search for sender address in previous Tx's vouts - hexAddr, err := searchSenderAddressInPreviousTransactions(ctx, p, rawTx) + // hexAddr, err := searchSenderAddressInPreviousTransactions(ctx, p, rawTx) + // if err != nil { + // return "", errors.New("Couldn't find sender address in previous transactions: " + err.Error()) + // } + + // return utils.AddHexPrefix(hexAddr), nil +} + +func getNonContractTxSenderAddressFromBlockTx(ctx context.Context, p *kaon.Kaon, tx *kaon.BlockTransactionDetails) (string, error) { + // Fetch raw Tx struct, which contains address data for Vins + rawTx, err := p.GetRawTransaction(ctx, tx.ID, false) + if err != nil { - return "", errors.New("Couldn't find sender address in previous transactions: " + err.Error()) + return "", errors.New("Couldn't get raw Transaction data from Transaction ID: " + err.Error()) } - return utils.AddHexPrefix(hexAddr), nil + // If Tx has no vins it's invalid/corrupt. This is outside the intended scope of this function, so throw an error + if len(rawTx.Vins) == 0 { + return "", errors.New("Transaction has 0 Vins and thus no valid sender address") + } + + // Take the address of the first Vin as sender address, as per design decision + // TODO: Make this not loop, it's not necessary and can in theory produce unintended behavior without causing an error + for _, in := range rawTx.Vins { + if len(in.Address) == 0 { + continue + } + hexAddress, err := utils.ConvertKaonAddress(in.Address) + if err == nil { + return utils.AddHexPrefix(hexAddress), nil + } else { + // P2Sh address(such as MUrenj2sPqEVTiNbHQ2RARiZYyTAAeKiDX) and BECH32 address (such as qc1qkt33x6hkrrlwlr6v59wptwy6zskyrjfe40y0lx) + // will cause ConvertKaonAddress to fall + hexAddress, err := p.Base58AddressToHex(in.Address) + if err == nil { + return utils.AddHexPrefix(hexAddress), nil + } else { + return "", err + } + } + } + + return "", errors.New("Couldn't find sender address the transaction") } // Searchs recursively for the sender address in previous transactions -func searchSenderAddressInPreviousTransactions(ctx context.Context, p *qtum.Qtum, rawTx *qtum.GetRawTransactionResponse) (string, error) { +func searchSenderAddressInPreviousTransactions(ctx context.Context, p *kaon.Kaon, rawTx *kaon.GetRawTransactionResponse) (string, error) { // search within current rawTx for vin containing opcode OP_SPEND var vout int64 = -1 var txid string = "" for _, vin := range rawTx.Vins { - if vin.ScriptSig.Asm == "OP_SPEND" { + if vin.ScriptSig.ASM == "OP_SPEND" { vout = vin.VoutN txid = vin.ID break } } + if vout == -1 { // Try again, there is chance for an empty value call where only gas was spent + for _, vin := range rawTx.Vins { + parts := strings.Split(vin.ScriptSig.ASM, " ") + if len(parts) >= 2 && len(parts[len(parts)-1]) == 40 { // addr as a last piece detected + return parts[len(parts)-1], nil // TODO: verify that it is a sender in any case + } + } + } if vout == -1 { return "", errors.New("Couldn't find OP_SPEND in transaction Vins") } @@ -200,11 +252,7 @@ func searchSenderAddressInPreviousTransactions(ctx context.Context, p *qtum.Qtum } // check opcodes contained in vout found in previous transaction prevVout := prevRawTx.Vouts[vout] - scriptASM, err := qtum.DisasmScript(prevVout.Details.Hex) - if err != nil { - return "", errors.New("Couldn't disasmbly the hex script: " + err.Error()) - } - script := strings.Split(scriptASM, " ") + script := strings.Split(prevVout.Details.ASM, " ") finalOp := script[len(script)-1] switch finalOp { // If the vout is an OP_SPEND recurse and keep fetching until we find an OP_CREATE or OP_CALL @@ -212,10 +260,10 @@ func searchSenderAddressInPreviousTransactions(ctx context.Context, p *qtum.Qtum return searchSenderAddressInPreviousTransactions(ctx, p, prevRawTx) // If we find an OP_CREATE, compute the contract address and set that as the "from" case "OP_CREATE": - createInfo, err := qtum.ParseCreateSenderASM(script) + createInfo, err := kaon.ParseCreateSenderASM(script) if err != nil { // Check for OP_CREATE without OP_SENDER - createInfo, err = qtum.ParseCreateASM(script) + createInfo, err = kaon.ParseCreateASM(script) if err != nil { return "", errors.WithMessage(err, "couldn't parse create sender ASM") } @@ -223,10 +271,10 @@ func searchSenderAddressInPreviousTransactions(ctx context.Context, p *qtum.Qtum return createInfo.From, nil // If it's an OP_CALL, extract the contract address and use that as the "from" address case "OP_CALL": - callInfo, err := qtum.ParseCallSenderASM(script) + callInfo, err := kaon.ParseCallSenderASM(script) if err != nil { // Check for OP_CALL without OP_SENDER - callInfo, err = qtum.ParseCallASM(script) + callInfo, err = kaon.ParseCallASM(script) if err != nil { return "", errors.WithMessage(err, "couldn't parse call sender ASM") } @@ -238,30 +286,58 @@ func searchSenderAddressInPreviousTransactions(ctx context.Context, p *qtum.Qtum // NOTE: // -// - is not for reward transactions -// // - returning address already has 0x prefix +func findNonContractTxReceiverAddress(p *kaon.Kaon, vouts []*kaon.DecodedRawTransactionOutV) (string, error) { + for _, vout := range vouts { + for _, address := range vout.ScriptPubKey.Addresses { + if address != "" { + hex, err := utils.ConvertKaonAddress(address) + if err == nil { + return utils.AddHexPrefix(hex), nil + } else { + // P2Sh address(such as MUrenj2sPqEVTiNbHQ2RARiZYyTAAeKiDX) and BECH32 address (such as qc1qkt33x6hkrrlwlr6v59wptwy6zskyrjfe40y0lx) + // will cause ConvertKaonAddress to fall + hex, err := p.Base58AddressToHex(address) + if err == nil { + return utils.AddHexPrefix(hex), nil + } else { + return "", err + } + } + } + } + } + return "", errors.New("not found") +} + +// NOTE: // -// TODO: researching -// -// - Vout[0].Addresses[i] != "" - temporary solution -func findNonContractTxReceiverAddress(vouts []*qtum.DecodedRawTransactionOutV) (string, error) { +// - returning address already has 0x prefix +func findNonContractTxReceiverAddressFromBlockTx(p *kaon.Kaon, vouts []kaon.BlockTransactionVout) (string, error) { for _, vout := range vouts { for _, address := range vout.ScriptPubKey.Addresses { if address != "" { - hex, err := utils.ConvertQtumAddress(address) - if err != nil { - return "", err + hex, err := utils.ConvertKaonAddress(address) + if err == nil { + return utils.AddHexPrefix(hex), nil + } else { + // P2Sh address(such as MUrenj2sPqEVTiNbHQ2RARiZYyTAAeKiDX) and BECH32 address (such as qc1qkt33x6hkrrlwlr6v59wptwy6zskyrjfe40y0lx) + // will cause ConvertKaonAddress to fall + hex, err := p.Base58AddressToHex(address) + if err == nil { + return utils.AddHexPrefix(hex), nil + } else { + return "", err + } } - return utils.AddHexPrefix(hex), nil } } } return "", errors.New("not found") } -func getBlockNumberByHash(ctx context.Context, p *qtum.Qtum, hash string) (uint64, error) { - block, err := p.GetBlock(ctx, hash) +func getBlockNumberByHash(ctx context.Context, p *kaon.Kaon, hash string) (uint64, error) { + block, err := p.GetBlock(ctx, hash, true) if err != nil { return 0, errors.WithMessage(err, "couldn't get block") } @@ -269,8 +345,8 @@ func getBlockNumberByHash(ctx context.Context, p *qtum.Qtum, hash string) (uint6 return uint64(block.Height), nil } -func getTransactionIndexInBlock(ctx context.Context, p *qtum.Qtum, txHash string, blockHash string) (int64, error) { - block, err := p.GetBlock(ctx, blockHash) +func getTransactionIndexInBlock(ctx context.Context, p *kaon.Kaon, txHash string, blockHash string) (int64, error) { + block, err := p.GetBlock(ctx, blockHash, true) if err != nil { return -1, errors.WithMessage(err, "couldn't get block") } @@ -284,7 +360,7 @@ func getTransactionIndexInBlock(ctx context.Context, p *qtum.Qtum, txHash string return -1, errors.New("not found") } -func formatQtumNonce(nonce int) string { +func formatKaonNonce(nonce int) string { var ( hexedNonce = strconv.FormatInt(int64(nonce), 16) missedCharsNum = 16 - len(hexedNonce) @@ -295,7 +371,7 @@ func formatQtumNonce(nonce int) string { return "0x" + hexedNonce } -// Returns Qtum block number. Result depends on a passed raw param. Raw param's slice of bytes should +// Returns Kaon block number. Result depends on a passed raw param. Raw param's slice of bytes should // has one of the following values: // - hex string representation of a number of a specific block // - integer - returns the value @@ -304,7 +380,7 @@ func formatQtumNonce(nonce int) string { // - string "pending" - for the pending state/transactions // // Uses defaultVal to differntiate from a eth_getBlockByNumber req and eth_getLogs/eth_newFilter -func getBlockNumberByRawParam(ctx context.Context, p *qtum.Qtum, rawParam json.RawMessage, defaultVal bool) (*big.Int, eth.JSONRPCError) { +func getBlockNumberByRawParam(ctx context.Context, p *kaon.Kaon, rawParam json.RawMessage, defaultVal bool) (*big.Int, *eth.JSONRPCError) { var param string if isBytesOfString(rawParam) { param = string(rawParam[1 : len(rawParam)-1]) // trim \" runes @@ -319,7 +395,7 @@ func getBlockNumberByRawParam(ctx context.Context, p *qtum.Qtum, rawParam json.R return getBlockNumberByParam(ctx, p, param, defaultVal) } -func getBlockNumberByParam(ctx context.Context, p *qtum.Qtum, param string, defaultVal bool) (*big.Int, eth.JSONRPCError) { +func getBlockNumberByParam(ctx context.Context, p *kaon.Kaon, param string, defaultVal bool) (*big.Int, *eth.JSONRPCError) { if len(param) < 1 { if defaultVal { res, err := p.GetBlockChainInfo(ctx) @@ -379,10 +455,10 @@ func isBytesOfString(v json.RawMessage) bool { return true } -// Converts Ethereum address to a Qtum address, where `address` represents -// Ethereum address without `0x` prefix and `chain` represents target Qtum +// Converts Ethereum address to a Kaon address, where `address` represents +// Ethereum address without `0x` prefix and `chain` represents target Kaon // chain -func convertETHAddress(address string, chain string) (qtumAddress string, _ error) { +func convertETHAddress(address string, chain string) (kaonAddress string, _ error) { addrBytes, err := hex.DecodeString(address) if err != nil { return "", errors.Wrapf(err, "couldn't decode hexed address - %q", address) @@ -390,33 +466,33 @@ func convertETHAddress(address string, chain string) (qtumAddress string, _ erro var prefix []byte switch chain { - case qtum.ChainMain: - chainPrefix, err := qtum.PrefixMainChainAddress.AsBytes() + case kaon.ChainMain: + chainPrefix, err := kaon.PrefixMainChainAddress.AsBytes() if err != nil { - return "", errors.WithMessagef(err, "couldn't convert %q Qtum chain prefix to slice of bytes", chain) + return "", errors.WithMessagef(err, "couldn't convert %q Kaon chain prefix to slice of bytes", chain) } prefix = chainPrefix - case qtum.ChainTest, qtum.ChainRegTest: - chainPrefix, err := qtum.PrefixTestChainAddress.AsBytes() + case kaon.ChainTest, kaon.ChainRegTest: + chainPrefix, err := kaon.PrefixTestChainAddress.AsBytes() if err != nil { - return "", errors.WithMessagef(err, "couldn't convert %q Qtum chain prefix to slice of bytes", chain) + return "", errors.WithMessagef(err, "couldn't convert %q Kaon chain prefix to slice of bytes", chain) } prefix = chainPrefix default: - return "", errors.Errorf("unsupported %q Qtum chain", chain) + return "", errors.Errorf("unsupported %q Kaon chain", chain) } var ( prefixedAddrBytes = append(prefix, addrBytes...) - checksum = qtum.CalcAddressChecksum(prefixedAddrBytes) - qtumAddressBytes = append(prefixedAddrBytes, checksum...) + checksum = kaon.CalcAddressChecksum(prefixedAddrBytes) + kaonAddressBytes = append(prefixedAddrBytes, checksum...) ) - return base58.Encode(qtumAddressBytes), nil + return base58.Encode(kaonAddressBytes), nil } -func processFilter(p *ProxyETHGetFilterChanges, rawreq *eth.JSONRPCRequest) (*eth.Filter, eth.JSONRPCError) { +func processFilter(p *ProxyETHGetFilterChanges, rawreq *eth.JSONRPCRequest) (*eth.Filter, *eth.JSONRPCError) { var req eth.GetFilterChangesRequest if err := unmarshalRequest(rawreq.Params, &req); err != nil { // TODO: Correct error code? @@ -437,16 +513,17 @@ func processFilter(p *ProxyETHGetFilterChanges, rawreq *eth.JSONRPCRequest) (*et return filter, nil } -// Converts a satoshis to qtum balance -func convertFromSatoshisToQtum(inSatoshis decimal.Decimal) decimal.Decimal { - return inSatoshis.Div(decimal.NewFromFloat(float64(1e8))) +// Converts a satoshis to kaon balance +// TODO: extend for future delimiter values to support different options +func convertFromSatoshisToKaon(inSatoshis decimal.Decimal) decimal.Decimal { + return inSatoshis //.Div(decimal.NewFromFloat(float64(1e8))) } -// Converts a qtum balance to satoshis -func convertFromQtumToSatoshis(inQtum decimal.Decimal) decimal.Decimal { - return inQtum.Mul(decimal.NewFromFloat(float64(1e8))) +// Converts a kaon balance to satoshis +func convertFromKaonToSatoshis(inKaon decimal.Decimal) decimal.Decimal { + return inKaon //.Mul(decimal.NewFromFloat(float64(1e8))) } func convertFromSatoshiToWei(inSatoshis *big.Int) *big.Int { - return inSatoshis.Mul(inSatoshis, big.NewInt(1e10)) + return inSatoshis //.Mul(inSatoshis, big.NewInt(1e10)) } diff --git a/pkg/transformer/util_test.go b/pkg/transformer/util_test.go index 3344bfe7..03136e59 100644 --- a/pkg/transformer/util_test.go +++ b/pkg/transformer/util_test.go @@ -4,15 +4,15 @@ import ( "fmt" "testing" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/internal" - "github.com/qtumproject/janus/pkg/qtum" - "github.com/qtumproject/janus/pkg/utils" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/kaon" + "github.com/kaonone/eth-rpc-gate/pkg/utils" "github.com/shopspring/decimal" "github.com/stretchr/testify/require" ) -func TestEthValueToQtumAmount(t *testing.T) { +func TestEthValueToKaonAmount(t *testing.T) { cases := []map[string]interface{}{ { "in": "0xde0b6b3a7640000", @@ -35,7 +35,7 @@ func TestEthValueToQtumAmount(t *testing.T) { for _, c := range cases { in := c["in"].(string) want := c["want"].(decimal.Decimal) - got, err := EthValueToQtumAmount(in, MinimumGas) + got, err := EthValueToKaonAmount(in, MinimumGas) if err != nil { t.Error(err) } @@ -47,7 +47,7 @@ func TestEthValueToQtumAmount(t *testing.T) { } } -func TestQtumValueToEthAmount(t *testing.T) { +func TestKaonValueToEthAmount(t *testing.T) { cases := []decimal.Decimal{ decimal.NewFromFloat(1), decimal.NewFromFloat(0.5), @@ -56,19 +56,19 @@ func TestQtumValueToEthAmount(t *testing.T) { } for _, c := range cases { in := c - eth := QtumDecimalValueToETHAmount(in) - out := EthDecimalValueToQtumAmount(eth) + eth := KaonDecimalValueToETHAmount(in) + out := EthDecimalValueToKaonAmount(eth) // TODO: Refactor to use new testing utilities? if !in.Equals(out) { - t.Errorf("in: %s, eth: %v, qtum: %v", in, eth, out) + t.Errorf("in: %s, eth: %v, kaon: %v", in, eth, out) } } } -func TestQtumAmountToEthValue(t *testing.T) { +func TestKaonAmountToEthValue(t *testing.T) { in, want := decimal.NewFromFloat(0.1), "0x16345785d8a0000" - got, err := formatQtumAmount(in) + got, err := formatKaonAmount(in) if err != nil { t.Error(err) } @@ -76,9 +76,9 @@ func TestQtumAmountToEthValue(t *testing.T) { internal.CheckTestResultUnspecifiedInputMarshal(in, want, got, t, false) } -func TestLowestQtumAmountToEthValue(t *testing.T) { +func TestLowestKaonAmountToEthValue(t *testing.T) { in, want := decimal.NewFromFloat(0.00000001), "0x2540be400" - got, err := formatQtumAmount(in) + got, err := formatKaonAmount(in) if err != nil { t.Error(err) } @@ -90,49 +90,49 @@ func TestAddressesConversion(t *testing.T) { t.Parallel() inputs := []struct { - qtumChain string + kaonChain string ethAddress string - qtumAddress string + kaonAddress string }{ { - qtumChain: qtum.ChainTest, + kaonChain: kaon.ChainTest, ethAddress: "6c89a1a6ca2ae7c00b248bb2832d6f480f27da68", - qtumAddress: "qTTH1Yr2eKCuDLqfxUyBLCAjmomQ8pyrBt", + kaonAddress: "uTTH1Yr2eKCuDLqfxUyBLCAjmomQ8pyrBt", }, // Test cases for addresses defined here: - // - https://github.com/hayeah/openzeppelin-solidity/blob/qtum/QTUM-NOTES.md#create-test-accounts + // - https://github.com/hayeah/openzeppelin-solidity/blob/kaon/QTUM-NOTES.md#create-test-accounts // // NOTE: Ethereum addresses are without `0x` prefix, as it expects by conversion functions { - qtumChain: qtum.ChainTest, - ethAddress: "7926223070547d2d15b2ef5e7383e541c338ffe9", - qtumAddress: "qUbxboqjBRp96j3La8D1RYkyqx5uQbJPoW", + kaonChain: kaon.ChainTest, + ethAddress: "1CE507204a6fC8fd6aA7e54D1481d30ACB0Dbead", + kaonAddress: "ar2SzdHghSgeacypPn7zfDe3qfKAEwimus", }, { - qtumChain: qtum.ChainTest, - ethAddress: "2352be3db3177f0a07efbe6da5857615b8c9901d", - qtumAddress: "qLn9vqbr2Gx3TsVR9QyTVB5mrMoh4x43Uf", + kaonChain: kaon.ChainTest, + ethAddress: "3f501c368cb9ddb5f27ed72ac0d602724adfa175", + kaonAddress: "auASFMxv45WgjCW6wkpDuHWjxXhzNA9mjP", }, { - qtumChain: qtum.ChainTest, - ethAddress: "69b004ac2b3993bf2fdf56b02746a1f57997420d", - qtumAddress: "qTCCy8qy7pW94EApdoBjYc1vQ2w68UnXPi", + kaonChain: kaon.ChainTest, + ethAddress: "57ed9afd4668ab81b648e68d2a76227434d6a8ee", + kaonAddress: "awQb8vf21idkFoZiYPA4hWgtuPyko2qUaR", }, { - qtumChain: qtum.ChainTest, - ethAddress: "8c647515f03daeefd09872d7530fa8d8450f069a", - qtumAddress: "qWMi6ne9mDQFatRGejxdDYVUV9rQVkAFGp", + kaonChain: kaon.ChainTest, + ethAddress: "1dd46713aa54541c74f4ef391b59b55133f675ec", + kaonAddress: "ar7PkgNdY1HkDtUo3D4GTsYrcqoHBJygNQ", }, { - qtumChain: qtum.ChainTest, - ethAddress: "2191744eb5ebeac90e523a817b77a83a0058003b", - qtumAddress: "qLcshhsRS6HKeTKRYFdpXnGVZxw96QQcfm", + kaonChain: kaon.ChainTest, + ethAddress: "c3530fe16dd1cc69dae31dc6f029ca57feab5536", + kaonAddress: "b7CSynDNwb2LQcCWXs8Qn79LUkgMdsK61S", }, { - qtumChain: qtum.ChainTest, - ethAddress: "88b0bf4b301c21f8a47be2188bad6467ad556dcf", - qtumAddress: "qW28njWueNpBXYWj2KDmtFG2gbLeALeHfV", + kaonChain: kaon.ChainTest, + ethAddress: "6c880fa6feb2a5917bcc1afc8afa0e4f61776a8f", + kaonAddress: "ayHXgXugbHDDR8cBjX2ZVLfkGE78QTeW2Z", }, } @@ -143,12 +143,12 @@ func TestAddressesConversion(t *testing.T) { ) // TODO: Investigate why this testing setup is so different t.Run(testDesc, func(t *testing.T) { - qtumAddress, err := convertETHAddress(in.ethAddress, in.qtumChain) - require.NoError(t, err, "couldn't convert Ethereum address to Qtum address") - require.Equal(t, in.qtumAddress, qtumAddress, "unexpected converted Qtum address value") + kaonAddress, err := convertETHAddress(in.ethAddress, in.kaonChain) + require.NoError(t, err, "couldn't convert Ethereum address to Kaon address") + require.Equal(t, in.kaonAddress, kaonAddress, "unexpected converted Kaon address value") - ethAddress, err := utils.ConvertQtumAddress(in.qtumAddress) - require.NoError(t, err, "couldn't convert Qtum address to Ethereum address") + ethAddress, err := utils.ConvertKaonAddress(in.kaonAddress) + require.NoError(t, err, "couldn't convert Kaon address to Ethereum address") require.Equal(t, in.ethAddress, ethAddress, "unexpected converted Ethereum address value") }) } @@ -161,13 +161,13 @@ func TestSendTransactionRequestHasDefaultGasPriceAndAmount(t *testing.T) { t.Fatal(err) } defaultGasPriceInWei := req.GasPrice.Int - defaultGasPriceInQTUM := EthDecimalValueToQtumAmount(decimal.NewFromBigInt(defaultGasPriceInWei, 1)) + defaultGasPriceInKAON := EthDecimalValueToKaonAmount(decimal.NewFromBigInt(defaultGasPriceInWei, 1)) // TODO: Refactor to use new testing utilities? - if !defaultGasPriceInQTUM.Equals(MinimumGas) { - t.Fatalf("Default gas price does not convert to QTUM minimum gas price, got: %s want: %s", defaultGasPriceInQTUM.String(), MinimumGas.String()) + if !defaultGasPriceInKAON.Equals(MinimumGas) { + t.Fatalf("Default gas price does not convert to KAON minimum gas price, got: %s want: %s", defaultGasPriceInKAON.String(), MinimumGas.String()) } - if eth.DefaultGasAmountForQtum.String() != req.Gas.Int.String() { - t.Fatalf("Default gas amount does not match expected default, got: %s want: %s", req.Gas.Int.String(), eth.DefaultGasAmountForQtum.String()) + if eth.DefaultGasAmountForKaon.String() != req.Gas.Int.String() { + t.Fatalf("Default gas amount does not match expected default, got: %s want: %s", req.Gas.Int.String(), eth.DefaultGasAmountForKaon.String()) } } diff --git a/pkg/transformer/web3_clientVersion.go b/pkg/transformer/web3_clientVersion.go index c4a1cc68..042c3f2b 100644 --- a/pkg/transformer/web3_clientVersion.go +++ b/pkg/transformer/web3_clientVersion.go @@ -3,26 +3,26 @@ package transformer import ( "runtime" + "github.com/kaonone/eth-rpc-gate/pkg/eth" + "github.com/kaonone/eth-rpc-gate/pkg/params" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" - "github.com/qtumproject/janus/pkg/params" ) // Web3ClientVersion implements web3_clientVersion type Web3ClientVersion struct { - // *qtum.Qtum + // *kaon.Kaon } func (p *Web3ClientVersion) Method() string { return "web3_clientVersion" } -func (p *Web3ClientVersion) Request(_ *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { - return "Janus/" + params.VersionWithGitSha + "/" + runtime.GOOS + "-" + runtime.GOARCH + "/" + runtime.Version(), nil +func (p *Web3ClientVersion) Request(_ *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { + return "eth-rpc-gate/" + params.VersionWithGitSha + "/" + runtime.GOOS + "-" + runtime.GOARCH + "/" + runtime.Version(), nil } -// func (p *Web3ClientVersion) ToResponse(ethresp *qtum.CallContractResponse) *eth.CallResponse { +// func (p *Web3ClientVersion) ToResponse(ethresp *kaon.CallContractResponse) *eth.CallResponse { // data := utils.AddHexPrefix(ethresp.ExecutionResult.Output) -// qtumresp := eth.CallResponse(data) -// return &qtumresp +// kaonresp := eth.CallResponse(data) +// return &kaonresp // } diff --git a/pkg/transformer/web3_sha3.go b/pkg/transformer/web3_sha3.go index 3a9681ba..ce1751bb 100644 --- a/pkg/transformer/web3_sha3.go +++ b/pkg/transformer/web3_sha3.go @@ -5,8 +5,8 @@ import ( "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" + "github.com/kaonone/eth-rpc-gate/pkg/eth" "github.com/labstack/echo" - "github.com/qtumproject/janus/pkg/eth" ) type Web3Sha3 struct{} @@ -15,7 +15,7 @@ func (p *Web3Sha3) Method() string { return "web3_sha3" } -func (p *Web3Sha3) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, eth.JSONRPCError) { +func (p *Web3Sha3) Request(rawreq *eth.JSONRPCRequest, c echo.Context) (interface{}, *eth.JSONRPCError) { var err error var req eth.Web3Sha3Request if err = json.Unmarshal(rawreq.Params, &req); err != nil { diff --git a/pkg/transformer/web3_sha3_test.go b/pkg/transformer/web3_sha3_test.go index cc20cd7b..6b5173d4 100644 --- a/pkg/transformer/web3_sha3_test.go +++ b/pkg/transformer/web3_sha3_test.go @@ -4,7 +4,7 @@ import ( "encoding/json" "testing" - "github.com/qtumproject/janus/pkg/internal" + "github.com/kaonone/eth-rpc-gate/pkg/internal" ) func TestWeb3Sha3Request(t *testing.T) { diff --git a/pkg/utils/hex.go b/pkg/utils/hex.go index e92caf46..960ee2f0 100644 --- a/pkg/utils/hex.go +++ b/pkg/utils/hex.go @@ -30,6 +30,26 @@ func AddHexPrefix(hex string) string { return "0x" + hex } +func AddHexWithLengthPrefix(hex string) string { + // Remove existing "0x" prefix if present + if strings.HasPrefix(hex, "0x") { + hex = hex[2:] + } + + // Calculate the number of leading zeroes needed + requiredLength := 64 + currentLength := len(hex) + zeroesNeeded := requiredLength - currentLength + + // Add leading zeroes + for i := 0; i < zeroesNeeded; i++ { + hex = "0" + hex + } + + // Add "0x" prefix + return "0x" + hex +} + func AddHexPrefixIfNotEmpty(hex string) string { if hex == "" { return hex @@ -37,6 +57,16 @@ func AddHexPrefixIfNotEmpty(hex string) string { return AddHexPrefix(hex) } +func AddHexWithLengthPrefixIfNotEmpty(hex string) string { + if hex == "" { + return hex + } + if hex == "0" { + return "" + } + return AddHexWithLengthPrefix(hex) +} + // DecodeBig decodes a hex string whether input is with 0x prefix or not. func DecodeBig(input string) (*big.Int, error) { input = AddHexPrefix(input) @@ -46,8 +76,8 @@ func DecodeBig(input string) (*big.Int, error) { return hexutil.DecodeBig(input) } -// Converts Qtum address to an Ethereum address -func ConvertQtumAddress(address string) (ethAddress string, _ error) { +// Converts Kaon address to an Ethereum address +func ConvertKaonAddress(address string) (ethAddress string, _ error) { if n := len(address); n < 22 { return "", errors.Errorf("invalid address: length is less than 22 bytes - %d", n) } @@ -57,7 +87,7 @@ func ConvertQtumAddress(address string) (ethAddress string, _ error) { return "", errors.Errorf("invalid address") } - // Drop Qtum chain prefix and checksum suffix + // Drop Kaon chain prefix and checksum suffix ethAddrBytes := base58.Decode(address)[1:21] return hex.EncodeToString(ethAddrBytes), nil diff --git a/pkg/utils/hex_test.go b/pkg/utils/hex_test.go index 898f4655..20b71720 100644 --- a/pkg/utils/hex_test.go +++ b/pkg/utils/hex_test.go @@ -5,11 +5,12 @@ import ( "testing" ) -func TestConvertQtumAddress(t *testing.T) { +func TestConvertKaonAddress(t *testing.T) { + // TODO: fix bech32addressMainnet := "qc1q3422djj7p4mjsgn7m3k3kymd2s36jnrpzcn7xx" bech32addressTestnet := "tq1qxagv83u8vgg656de4aa04xvxe7jfzguwmg020n" legacyaddressMainnet := "QYmyzKNjoox5LkaiUvibZdM252bftQotDx" - legacyAddressTesnet := "qUbxboqjBRp96j3La8D1RYkyqx5uQbJPoW" + legacyAddressTesnet := "ar2SzdHghSgeacypPn7zfDe3qfKAEwimus" var tests = []struct { address string @@ -19,13 +20,13 @@ func TestConvertQtumAddress(t *testing.T) { {bech32addressMainnet, "", errors.New("invalid address")}, {bech32addressTestnet, "", errors.New("invalid address")}, {legacyaddressMainnet, "8585918c3ee7168ee9d79dd9b5883eb65d0e0db0", nil}, - {legacyAddressTesnet, "7926223070547d2d15b2ef5e7383e541c338ffe9", nil}, + {legacyAddressTesnet, "1CE507204a6fC8fd6aA7e54D1481d30ACB0Dbead", nil}, } for _, tt := range tests { testname := tt.address t.Run(testname, func(t *testing.T) { - got, _ := ConvertQtumAddress(tt.address) + got, _ := ConvertKaonAddress(tt.address) if got != tt.want { t.Errorf("got %s, want %s", got, tt.want) } diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 5065a9db..1d906a94 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -1,5 +1,11 @@ package utils +import ( + "math/big" + + "github.com/shopspring/decimal" +) + func InStrSlice(s []string, str string) bool { for _, v := range s { if v == str { @@ -9,3 +15,21 @@ func InStrSlice(s []string, str string) bool { return false } + +// Specific decimal.Decimal to big.Int conversion to support big values +func ToBigInt(value *decimal.Decimal) (*big.Int, error) { + return value.BigInt(), nil +} + +// Specific decimal.Decimal to big.Int conversion to support big values +func ToDecimal(value *big.Int) (*decimal.Decimal, error) { + dst := new(decimal.Decimal) + + str, errEncode := value.MarshalText() + if errEncode != nil { + return dst, errEncode + } + + dst.UnmarshalText(str) + return dst, nil +}