parent
4d51f937c4
commit
aa0f2ede6d
|
@ -10,7 +10,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/status-im/status-go/geth/api"
|
"github.com/status-im/status-go/geth/api"
|
||||||
"github.com/status-im/status-go/geth/common"
|
|
||||||
"github.com/status-im/status-go/geth/params"
|
"github.com/status-im/status-go/geth/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -170,7 +169,7 @@ func (cs *commandSet) Logout() error {
|
||||||
|
|
||||||
// CompleteTransaction instructs API to complete sending of a given transaction.
|
// CompleteTransaction instructs API to complete sending of a given transaction.
|
||||||
func (cs *commandSet) CompleteTransaction(id, password string) (string, error) {
|
func (cs *commandSet) CompleteTransaction(id, password string) (string, error) {
|
||||||
txHash, err := cs.statusAPI.CompleteTransaction(common.QueuedTxID(id), password)
|
txHash, err := cs.statusAPI.CompleteTransaction(id, password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
gethcommon "github.com/ethereum/go-ethereum/common"
|
gethcommon "github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/golang/mock/gomock"
|
"github.com/golang/mock/gomock"
|
||||||
"github.com/status-im/status-go/geth/common"
|
|
||||||
. "github.com/status-im/status-go/t/utils"
|
. "github.com/status-im/status-go/t/utils"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
@ -30,8 +29,8 @@ func TestVerifyAccountPassword(t *testing.T) {
|
||||||
defer os.RemoveAll(emptyKeyStoreDir) //nolint: errcheck
|
defer os.RemoveAll(emptyKeyStoreDir) //nolint: errcheck
|
||||||
|
|
||||||
// import account keys
|
// import account keys
|
||||||
require.NoError(t, common.ImportTestAccount(keyStoreDir, GetAccount1PKFile()))
|
require.NoError(t, ImportTestAccount(keyStoreDir, GetAccount1PKFile()))
|
||||||
require.NoError(t, common.ImportTestAccount(keyStoreDir, GetAccount2PKFile()))
|
require.NoError(t, ImportTestAccount(keyStoreDir, GetAccount2PKFile()))
|
||||||
|
|
||||||
account1Address := gethcommon.BytesToAddress(gethcommon.FromHex(TestConfig.Account1.Address))
|
account1Address := gethcommon.BytesToAddress(gethcommon.FromHex(TestConfig.Account1.Address))
|
||||||
|
|
||||||
|
@ -103,7 +102,7 @@ func TestVerifyAccountPasswordWithAccountBeforeEIP55(t *testing.T) {
|
||||||
defer os.RemoveAll(keyStoreDir) //nolint: errcheck
|
defer os.RemoveAll(keyStoreDir) //nolint: errcheck
|
||||||
|
|
||||||
// Import keys and make sure one was created before EIP55 introduction.
|
// Import keys and make sure one was created before EIP55 introduction.
|
||||||
err = common.ImportTestAccount(keyStoreDir, "test-account3-before-eip55.pk")
|
err = ImportTestAccount(keyStoreDir, "test-account3-before-eip55.pk")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
accManager := NewManager(nil)
|
accManager := NewManager(nil)
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
gethcommon "github.com/ethereum/go-ethereum/common"
|
gethcommon "github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/status-im/status-go/geth/account"
|
"github.com/status-im/status-go/geth/account"
|
||||||
"github.com/status-im/status-go/geth/common"
|
|
||||||
"github.com/status-im/status-go/geth/jail"
|
"github.com/status-im/status-go/geth/jail"
|
||||||
"github.com/status-im/status-go/geth/node"
|
"github.com/status-im/status-go/geth/node"
|
||||||
"github.com/status-im/status-go/geth/params"
|
"github.com/status-im/status-go/geth/params"
|
||||||
|
@ -147,28 +146,28 @@ func (api *StatusAPI) Logout() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendTransaction creates a new transaction and waits until it's complete.
|
// SendTransaction creates a new transaction and waits until it's complete.
|
||||||
func (api *StatusAPI) SendTransaction(ctx context.Context, args common.SendTxArgs) (gethcommon.Hash, error) {
|
func (api *StatusAPI) SendTransaction(ctx context.Context, args transactions.SendTxArgs) (gethcommon.Hash, error) {
|
||||||
return api.b.SendTransaction(ctx, args)
|
return api.b.SendTransaction(ctx, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompleteTransaction instructs backend to complete sending of a given transaction
|
// CompleteTransaction instructs backend to complete sending of a given transaction
|
||||||
func (api *StatusAPI) CompleteTransaction(id common.QueuedTxID, password string) (gethcommon.Hash, error) {
|
func (api *StatusAPI) CompleteTransaction(id string, password string) (gethcommon.Hash, error) {
|
||||||
return api.b.CompleteTransaction(id, password)
|
return api.b.CompleteTransaction(id, password)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompleteTransactions instructs backend to complete sending of multiple transactions
|
// CompleteTransactions instructs backend to complete sending of multiple transactions
|
||||||
func (api *StatusAPI) CompleteTransactions(ids []common.QueuedTxID, password string) map[common.QueuedTxID]common.TransactionResult {
|
func (api *StatusAPI) CompleteTransactions(ids []string, password string) map[string]transactions.Result {
|
||||||
return api.b.CompleteTransactions(ids, password)
|
return api.b.CompleteTransactions(ids, password)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DiscardTransaction discards a given transaction from transaction queue
|
// DiscardTransaction discards a given transaction from transaction queue
|
||||||
func (api *StatusAPI) DiscardTransaction(id common.QueuedTxID) error {
|
func (api *StatusAPI) DiscardTransaction(id string) error {
|
||||||
return api.b.txQueueManager.DiscardTransaction(id)
|
return api.b.DiscardTransaction(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DiscardTransactions discards given multiple transactions from transaction queue
|
// DiscardTransactions discards given multiple transactions from transaction queue
|
||||||
func (api *StatusAPI) DiscardTransactions(ids []common.QueuedTxID) map[common.QueuedTxID]common.RawDiscardTransactionResult {
|
func (api *StatusAPI) DiscardTransactions(ids []string) map[string]error {
|
||||||
return api.b.txQueueManager.DiscardTransactions(ids)
|
return api.b.DiscardTransactions(ids)
|
||||||
}
|
}
|
||||||
|
|
||||||
// JailParse creates a new jail cell context, with the given chatID as identifier.
|
// JailParse creates a new jail cell context, with the given chatID as identifier.
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
|
||||||
"github.com/status-im/status-go/geth/account"
|
"github.com/status-im/status-go/geth/account"
|
||||||
"github.com/status-im/status-go/geth/common"
|
|
||||||
"github.com/status-im/status-go/geth/jail"
|
"github.com/status-im/status-go/geth/jail"
|
||||||
"github.com/status-im/status-go/geth/node"
|
"github.com/status-im/status-go/geth/node"
|
||||||
"github.com/status-im/status-go/geth/notifications/push/fcm"
|
"github.com/status-im/status-go/geth/notifications/push/fcm"
|
||||||
|
@ -193,11 +192,11 @@ func (b *StatusBackend) CallRPC(inputJSON string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendTransaction creates a new transaction and waits until it's complete.
|
// SendTransaction creates a new transaction and waits until it's complete.
|
||||||
func (b *StatusBackend) SendTransaction(ctx context.Context, args common.SendTxArgs) (hash gethcommon.Hash, err error) {
|
func (b *StatusBackend) SendTransaction(ctx context.Context, args transactions.SendTxArgs) (hash gethcommon.Hash, err error) {
|
||||||
if ctx == nil {
|
if ctx == nil {
|
||||||
ctx = context.Background()
|
ctx = context.Background()
|
||||||
}
|
}
|
||||||
tx := common.CreateTransaction(ctx, args)
|
tx := transactions.Create(ctx, args)
|
||||||
if err = b.txQueueManager.QueueTransaction(tx); err != nil {
|
if err = b.txQueueManager.QueueTransaction(tx); err != nil {
|
||||||
return hash, err
|
return hash, err
|
||||||
}
|
}
|
||||||
|
@ -227,7 +226,7 @@ func (b *StatusBackend) getVerifiedAccount(password string) (*account.SelectedEx
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompleteTransaction instructs backend to complete sending of a given transaction
|
// CompleteTransaction instructs backend to complete sending of a given transaction
|
||||||
func (b *StatusBackend) CompleteTransaction(id common.QueuedTxID, password string) (hash gethcommon.Hash, err error) {
|
func (b *StatusBackend) CompleteTransaction(id string, password string) (hash gethcommon.Hash, err error) {
|
||||||
selectedAccount, err := b.getVerifiedAccount(password)
|
selectedAccount, err := b.getVerifiedAccount(password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = b.txQueueManager.NotifyErrored(id, err)
|
_ = b.txQueueManager.NotifyErrored(id, err)
|
||||||
|
@ -238,11 +237,11 @@ func (b *StatusBackend) CompleteTransaction(id common.QueuedTxID, password strin
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompleteTransactions instructs backend to complete sending of multiple transactions
|
// CompleteTransactions instructs backend to complete sending of multiple transactions
|
||||||
func (b *StatusBackend) CompleteTransactions(ids []common.QueuedTxID, password string) map[common.QueuedTxID]common.TransactionResult {
|
func (b *StatusBackend) CompleteTransactions(ids []string, password string) map[string]transactions.Result {
|
||||||
results := make(map[common.QueuedTxID]common.TransactionResult)
|
results := make(map[string]transactions.Result)
|
||||||
for _, txID := range ids {
|
for _, txID := range ids {
|
||||||
txHash, txErr := b.CompleteTransaction(txID, password)
|
txHash, txErr := b.CompleteTransaction(txID, password)
|
||||||
results[txID] = common.TransactionResult{
|
results[txID] = transactions.Result{
|
||||||
Hash: txHash,
|
Hash: txHash,
|
||||||
Error: txErr,
|
Error: txErr,
|
||||||
}
|
}
|
||||||
|
@ -251,13 +250,21 @@ func (b *StatusBackend) CompleteTransactions(ids []common.QueuedTxID, password s
|
||||||
}
|
}
|
||||||
|
|
||||||
// DiscardTransaction discards a given transaction from transaction queue
|
// DiscardTransaction discards a given transaction from transaction queue
|
||||||
func (b *StatusBackend) DiscardTransaction(id common.QueuedTxID) error {
|
func (b *StatusBackend) DiscardTransaction(id string) error {
|
||||||
return b.txQueueManager.DiscardTransaction(id)
|
return b.txQueueManager.DiscardTransaction(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DiscardTransactions discards given multiple transactions from transaction queue
|
// DiscardTransactions discards given multiple transactions from transaction queue
|
||||||
func (b *StatusBackend) DiscardTransactions(ids []common.QueuedTxID) map[common.QueuedTxID]common.RawDiscardTransactionResult {
|
func (b *StatusBackend) DiscardTransactions(ids []string) map[string]error {
|
||||||
return b.txQueueManager.DiscardTransactions(ids)
|
results := make(map[string]error)
|
||||||
|
for _, txID := range ids {
|
||||||
|
err := b.DiscardTransaction(txID)
|
||||||
|
if err != nil {
|
||||||
|
results[txID] = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results
|
||||||
}
|
}
|
||||||
|
|
||||||
// registerHandlers attaches Status callback handlers to running node
|
// registerHandlers attaches Status callback handlers to running node
|
||||||
|
|
|
@ -1,170 +0,0 @@
|
||||||
package common
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
||||||
"github.com/status-im/status-go/geth/params"
|
|
||||||
"github.com/status-im/status-go/static"
|
|
||||||
)
|
|
||||||
|
|
||||||
// errors
|
|
||||||
var (
|
|
||||||
ErrDeprecatedMethod = errors.New("Method is depricated and will be removed in future release")
|
|
||||||
ErrInvalidSendTxArgs = errors.New("Transaction arguments are invalid (are both 'input' and 'data' fields used?)")
|
|
||||||
)
|
|
||||||
|
|
||||||
// TransactionResult is a JSON returned from transaction complete function (used internally)
|
|
||||||
type TransactionResult struct {
|
|
||||||
Hash common.Hash
|
|
||||||
Error error
|
|
||||||
}
|
|
||||||
|
|
||||||
// RawDiscardTransactionResult is list of results from CompleteTransactions() (used internally)
|
|
||||||
type RawDiscardTransactionResult struct {
|
|
||||||
Error error
|
|
||||||
}
|
|
||||||
|
|
||||||
// QueuedTxID queued transaction identifier
|
|
||||||
type QueuedTxID string
|
|
||||||
|
|
||||||
// QueuedTx holds enough information to complete the queued transaction.
|
|
||||||
type QueuedTx struct {
|
|
||||||
ID QueuedTxID
|
|
||||||
Context context.Context
|
|
||||||
Args SendTxArgs
|
|
||||||
Result chan TransactionResult
|
|
||||||
}
|
|
||||||
|
|
||||||
// SendTxArgs represents the arguments to submit a new transaction into the transaction pool.
|
|
||||||
// This struct is based on go-ethereum's type in internal/ethapi/api.go, but we have freedom
|
|
||||||
// over the exact layout of this struct.
|
|
||||||
type SendTxArgs struct {
|
|
||||||
From common.Address `json:"from"`
|
|
||||||
To *common.Address `json:"to"`
|
|
||||||
Gas *hexutil.Uint64 `json:"gas"`
|
|
||||||
GasPrice *hexutil.Big `json:"gasPrice"`
|
|
||||||
Value *hexutil.Big `json:"value"`
|
|
||||||
Nonce *hexutil.Uint64 `json:"nonce"`
|
|
||||||
// We keep both "input" and "data" for backward compatibility.
|
|
||||||
// "input" is a preferred field.
|
|
||||||
// see `vendor/github.com/ethereum/go-ethereum/internal/ethapi/api.go:1107`
|
|
||||||
Input hexutil.Bytes `json:"input"`
|
|
||||||
Data hexutil.Bytes `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Valid checks whether this structure is filled in correctly.
|
|
||||||
func (args SendTxArgs) Valid() bool {
|
|
||||||
// if at least one of the fields is empty, it is a valid struct
|
|
||||||
if isNilOrEmpty(args.Input) || isNilOrEmpty(args.Data) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// we only allow both fields to present if they have the same data
|
|
||||||
return bytes.Equal(args.Input, args.Data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetInput returns either Input or Data field's value dependent on what is filled.
|
|
||||||
func (args SendTxArgs) GetInput() hexutil.Bytes {
|
|
||||||
if !isNilOrEmpty(args.Input) {
|
|
||||||
return args.Input
|
|
||||||
}
|
|
||||||
|
|
||||||
return args.Data
|
|
||||||
}
|
|
||||||
|
|
||||||
func isNilOrEmpty(bytes hexutil.Bytes) bool {
|
|
||||||
return bytes == nil || len(bytes) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// StopRPCCallError defines a error type specific for killing a execution process.
|
|
||||||
type StopRPCCallError struct {
|
|
||||||
Err error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error returns the internal error associated with the critical error.
|
|
||||||
func (c StopRPCCallError) Error() string {
|
|
||||||
return c.Err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
// CompleteTransactionResult is a JSON returned from transaction complete function (used in exposed method)
|
|
||||||
type CompleteTransactionResult struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Hash string `json:"hash"`
|
|
||||||
Error string `json:"error"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// CompleteTransactionsResult is list of results from CompleteTransactions() (used in exposed method)
|
|
||||||
type CompleteTransactionsResult struct {
|
|
||||||
Results map[string]CompleteTransactionResult `json:"results"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// DiscardTransactionResult is a JSON returned from transaction discard function
|
|
||||||
type DiscardTransactionResult struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Error string `json:"error"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// DiscardTransactionsResult is a list of results from DiscardTransactions()
|
|
||||||
type DiscardTransactionsResult struct {
|
|
||||||
Results map[string]DiscardTransactionResult `json:"results"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type account struct {
|
|
||||||
Address string
|
|
||||||
Password string
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestConfig contains shared (among different test packages) parameters
|
|
||||||
type TestConfig struct {
|
|
||||||
Node struct {
|
|
||||||
SyncSeconds time.Duration
|
|
||||||
HTTPPort int
|
|
||||||
WSPort int
|
|
||||||
}
|
|
||||||
Account1 account
|
|
||||||
Account2 account
|
|
||||||
Account3 account
|
|
||||||
}
|
|
||||||
|
|
||||||
// NotifyResult is a JSON returned from notify message
|
|
||||||
type NotifyResult struct {
|
|
||||||
Status bool `json:"status"`
|
|
||||||
Error string `json:"error,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
const passphraseEnvName = "ACCOUNT_PASSWORD"
|
|
||||||
|
|
||||||
// LoadTestConfig loads test configuration values from disk
|
|
||||||
func LoadTestConfig(networkID int) (*TestConfig, error) {
|
|
||||||
var testConfig TestConfig
|
|
||||||
|
|
||||||
configData := static.MustAsset("config/test-data.json")
|
|
||||||
if err := json.Unmarshal(configData, &testConfig); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if networkID == params.StatusChainNetworkID {
|
|
||||||
accountsData := static.MustAsset("config/status-chain-accounts.json")
|
|
||||||
if err := json.Unmarshal(accountsData, &testConfig); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
accountsData := static.MustAsset("config/public-chain-accounts.json")
|
|
||||||
if err := json.Unmarshal(accountsData, &testConfig); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
pass := os.Getenv(passphraseEnvName)
|
|
||||||
testConfig.Account1.Password = pass
|
|
||||||
testConfig.Account2.Password = pass
|
|
||||||
}
|
|
||||||
|
|
||||||
return &testConfig, nil
|
|
||||||
}
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
|
|
||||||
gethcommon "github.com/ethereum/go-ethereum/common"
|
gethcommon "github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/status-im/status-go/geth/common"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Call represents a unit of a rpc request which is to be executed.
|
// Call represents a unit of a rpc request which is to be executed.
|
||||||
|
@ -144,31 +143,3 @@ func (c Call) ParseGasPrice() *hexutil.Big {
|
||||||
|
|
||||||
return (*hexutil.Big)(parsedValue)
|
return (*hexutil.Big)(parsedValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ToSendTxArgs converts Call to SendTxArgs.
|
|
||||||
func (c Call) ToSendTxArgs() common.SendTxArgs {
|
|
||||||
var err error
|
|
||||||
var fromAddr, toAddr gethcommon.Address
|
|
||||||
|
|
||||||
fromAddr, err = c.ParseFromAddress()
|
|
||||||
if err != nil {
|
|
||||||
fromAddr = gethcommon.HexToAddress("0x0")
|
|
||||||
}
|
|
||||||
|
|
||||||
toAddr, err = c.ParseToAddress()
|
|
||||||
if err != nil {
|
|
||||||
toAddr = gethcommon.HexToAddress("0x0")
|
|
||||||
}
|
|
||||||
|
|
||||||
input := c.ParseInput()
|
|
||||||
data := c.ParseData()
|
|
||||||
return common.SendTxArgs{
|
|
||||||
To: &toAddr,
|
|
||||||
From: fromAddr,
|
|
||||||
Value: c.ParseValue(),
|
|
||||||
Input: input,
|
|
||||||
Data: data,
|
|
||||||
Gas: c.ParseGas(),
|
|
||||||
GasPrice: c.ParseGasPrice(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ package transactions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
"github.com/status-im/status-go/geth/common"
|
|
||||||
"github.com/status-im/status-go/geth/signal"
|
"github.com/status-im/status-go/geth/signal"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -35,34 +34,34 @@ var txReturnCodes = map[error]int{
|
||||||
|
|
||||||
// SendTransactionEvent is a signal sent on a send transaction request
|
// SendTransactionEvent is a signal sent on a send transaction request
|
||||||
type SendTransactionEvent struct {
|
type SendTransactionEvent struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Args common.SendTxArgs `json:"args"`
|
Args SendTxArgs `json:"args"`
|
||||||
MessageID string `json:"message_id"`
|
MessageID string `json:"message_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyOnEnqueue returns handler that processes incoming tx queue requests
|
// NotifyOnEnqueue returns handler that processes incoming tx queue requests
|
||||||
func NotifyOnEnqueue(queuedTx *common.QueuedTx) {
|
func NotifyOnEnqueue(queuedTx *QueuedTx) {
|
||||||
signal.Send(signal.Envelope{
|
signal.Send(signal.Envelope{
|
||||||
Type: EventTransactionQueued,
|
Type: EventTransactionQueued,
|
||||||
Event: SendTransactionEvent{
|
Event: SendTransactionEvent{
|
||||||
ID: string(queuedTx.ID),
|
ID: queuedTx.ID,
|
||||||
Args: queuedTx.Args,
|
Args: queuedTx.Args,
|
||||||
MessageID: common.MessageIDFromContext(queuedTx.Context),
|
MessageID: messageIDFromContext(queuedTx.Context),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReturnSendTransactionEvent is a JSON returned whenever transaction send is returned
|
// ReturnSendTransactionEvent is a JSON returned whenever transaction send is returned
|
||||||
type ReturnSendTransactionEvent struct {
|
type ReturnSendTransactionEvent struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Args common.SendTxArgs `json:"args"`
|
Args SendTxArgs `json:"args"`
|
||||||
MessageID string `json:"message_id"`
|
MessageID string `json:"message_id"`
|
||||||
ErrorMessage string `json:"error_message"`
|
ErrorMessage string `json:"error_message"`
|
||||||
ErrorCode int `json:"error_code,string"`
|
ErrorCode int `json:"error_code,string"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyOnReturn returns handler that processes responses from internal tx manager
|
// NotifyOnReturn returns handler that processes responses from internal tx manager
|
||||||
func NotifyOnReturn(queuedTx *common.QueuedTx, err error) {
|
func NotifyOnReturn(queuedTx *QueuedTx, err error) {
|
||||||
// we don't want to notify a user if tx was sent successfully
|
// we don't want to notify a user if tx was sent successfully
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return
|
return
|
||||||
|
@ -74,9 +73,9 @@ func NotifyOnReturn(queuedTx *common.QueuedTx, err error) {
|
||||||
signal.Send(signal.Envelope{
|
signal.Send(signal.Envelope{
|
||||||
Type: EventTransactionFailed,
|
Type: EventTransactionFailed,
|
||||||
Event: ReturnSendTransactionEvent{
|
Event: ReturnSendTransactionEvent{
|
||||||
ID: string(queuedTx.ID),
|
ID: queuedTx.ID,
|
||||||
Args: queuedTx.Args,
|
Args: queuedTx.Args,
|
||||||
MessageID: common.MessageIDFromContext(queuedTx.Context),
|
MessageID: messageIDFromContext(queuedTx.Context),
|
||||||
ErrorMessage: err.Error(),
|
ErrorMessage: err.Error(),
|
||||||
ErrorCode: sendTransactionErrorCode(err),
|
ErrorCode: sendTransactionErrorCode(err),
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package queue
|
package transactions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -9,7 +9,6 @@ import (
|
||||||
gethcommon "github.com/ethereum/go-ethereum/common"
|
gethcommon "github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/status-im/status-go/geth/account"
|
"github.com/status-im/status-go/geth/account"
|
||||||
"github.com/status-im/status-go/geth/common"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -41,11 +40,11 @@ type empty struct{}
|
||||||
// TxQueue is capped container that holds pending transactions
|
// TxQueue is capped container that holds pending transactions
|
||||||
type TxQueue struct {
|
type TxQueue struct {
|
||||||
mu sync.RWMutex // to guard transactions map
|
mu sync.RWMutex // to guard transactions map
|
||||||
transactions map[common.QueuedTxID]*common.QueuedTx
|
transactions map[string]*QueuedTx
|
||||||
inprogress map[common.QueuedTxID]empty
|
inprogress map[string]empty
|
||||||
|
|
||||||
// TODO(dshulyak) research why eviction is done in separate goroutine
|
// TODO(dshulyak) research why eviction is done in separate goroutine
|
||||||
evictableIDs chan common.QueuedTxID
|
evictableIDs chan string
|
||||||
enqueueTicker chan struct{}
|
enqueueTicker chan struct{}
|
||||||
|
|
||||||
// when this channel is closed, all queue channels processing must cease (incoming queue, processing queued items etc)
|
// when this channel is closed, all queue channels processing must cease (incoming queue, processing queued items etc)
|
||||||
|
@ -54,16 +53,16 @@ type TxQueue struct {
|
||||||
log log.Logger
|
log log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a transaction queue.
|
// newQueue creates a transaction queue.
|
||||||
func New() *TxQueue {
|
func newQueue() *TxQueue {
|
||||||
|
|
||||||
logger := log.New("package", "status-go/geth/transactions/queue.TxQueue")
|
logger := log.New("package", "status-go/geth/transactions.TxQueue")
|
||||||
|
|
||||||
logger.Info("initializing transaction queue")
|
logger.Info("initializing transaction queue")
|
||||||
return &TxQueue{
|
return &TxQueue{
|
||||||
transactions: make(map[common.QueuedTxID]*common.QueuedTx),
|
transactions: make(map[string]*QueuedTx),
|
||||||
inprogress: make(map[common.QueuedTxID]empty),
|
inprogress: make(map[string]empty),
|
||||||
evictableIDs: make(chan common.QueuedTxID, DefaultTxQueueCap), // will be used to evict in FIFO
|
evictableIDs: make(chan string, DefaultTxQueueCap), // will be used to evict in FIFO
|
||||||
enqueueTicker: make(chan struct{}),
|
enqueueTicker: make(chan struct{}),
|
||||||
log: logger,
|
log: logger,
|
||||||
}
|
}
|
||||||
|
@ -99,7 +98,7 @@ func (q *TxQueue) Stop() {
|
||||||
|
|
||||||
// evictionLoop frees up queue to accommodate another transaction item
|
// evictionLoop frees up queue to accommodate another transaction item
|
||||||
func (q *TxQueue) evictionLoop() {
|
func (q *TxQueue) evictionLoop() {
|
||||||
defer HaltOnPanic()
|
defer haltOnPanic()
|
||||||
evict := func() {
|
evict := func() {
|
||||||
if q.Count() >= DefaultTxQueueCap { // eviction is required to accommodate another/last item
|
if q.Count() >= DefaultTxQueueCap { // eviction is required to accommodate another/last item
|
||||||
q.Remove(<-q.evictableIDs)
|
q.Remove(<-q.evictableIDs)
|
||||||
|
@ -125,13 +124,13 @@ func (q *TxQueue) Reset() {
|
||||||
q.mu.Lock()
|
q.mu.Lock()
|
||||||
defer q.mu.Unlock()
|
defer q.mu.Unlock()
|
||||||
|
|
||||||
q.transactions = make(map[common.QueuedTxID]*common.QueuedTx)
|
q.transactions = make(map[string]*QueuedTx)
|
||||||
q.evictableIDs = make(chan common.QueuedTxID, DefaultTxQueueCap)
|
q.evictableIDs = make(chan string, DefaultTxQueueCap)
|
||||||
q.inprogress = make(map[common.QueuedTxID]empty)
|
q.inprogress = make(map[string]empty)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enqueue enqueues incoming transaction
|
// Enqueue enqueues incoming transaction
|
||||||
func (q *TxQueue) Enqueue(tx *common.QueuedTx) error {
|
func (q *TxQueue) Enqueue(tx *QueuedTx) error {
|
||||||
q.log.Info("enqueue transaction", "ID", tx.ID)
|
q.log.Info("enqueue transaction", "ID", tx.ID)
|
||||||
q.mu.RLock()
|
q.mu.RLock()
|
||||||
if _, ok := q.transactions[tx.ID]; ok {
|
if _, ok := q.transactions[tx.ID]; ok {
|
||||||
|
@ -156,7 +155,7 @@ func (q *TxQueue) Enqueue(tx *common.QueuedTx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns transaction by transaction identifier
|
// Get returns transaction by transaction identifier
|
||||||
func (q *TxQueue) Get(id common.QueuedTxID) (*common.QueuedTx, error) {
|
func (q *TxQueue) Get(id string) (*QueuedTx, error) {
|
||||||
q.mu.RLock()
|
q.mu.RLock()
|
||||||
defer q.mu.RUnlock()
|
defer q.mu.RUnlock()
|
||||||
|
|
||||||
|
@ -167,7 +166,7 @@ func (q *TxQueue) Get(id common.QueuedTxID) (*common.QueuedTx, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// LockInprogress returns error if transaction is already inprogress.
|
// LockInprogress returns error if transaction is already inprogress.
|
||||||
func (q *TxQueue) LockInprogress(id common.QueuedTxID) error {
|
func (q *TxQueue) LockInprogress(id string) error {
|
||||||
q.mu.Lock()
|
q.mu.Lock()
|
||||||
defer q.mu.Unlock()
|
defer q.mu.Unlock()
|
||||||
if _, ok := q.transactions[id]; ok {
|
if _, ok := q.transactions[id]; ok {
|
||||||
|
@ -181,20 +180,20 @@ func (q *TxQueue) LockInprogress(id common.QueuedTxID) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove removes transaction by transaction identifier
|
// Remove removes transaction by transaction identifier
|
||||||
func (q *TxQueue) Remove(id common.QueuedTxID) {
|
func (q *TxQueue) Remove(id string) {
|
||||||
q.mu.Lock()
|
q.mu.Lock()
|
||||||
defer q.mu.Unlock()
|
defer q.mu.Unlock()
|
||||||
q.remove(id)
|
q.remove(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *TxQueue) remove(id common.QueuedTxID) {
|
func (q *TxQueue) remove(id string) {
|
||||||
delete(q.transactions, id)
|
delete(q.transactions, id)
|
||||||
delete(q.inprogress, id)
|
delete(q.inprogress, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Done removes transaction from queue if no error or error is not transient
|
// Done removes transaction from queue if no error or error is not transient
|
||||||
// and notify subscribers
|
// and notify subscribers
|
||||||
func (q *TxQueue) Done(id common.QueuedTxID, hash gethcommon.Hash, err error) error {
|
func (q *TxQueue) Done(id string, hash gethcommon.Hash, err error) error {
|
||||||
q.mu.Lock()
|
q.mu.Lock()
|
||||||
defer q.mu.Unlock()
|
defer q.mu.Unlock()
|
||||||
tx, ok := q.transactions[id]
|
tx, ok := q.transactions[id]
|
||||||
|
@ -205,16 +204,16 @@ func (q *TxQueue) Done(id common.QueuedTxID, hash gethcommon.Hash, err error) er
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *TxQueue) done(tx *common.QueuedTx, hash gethcommon.Hash, err error) {
|
func (q *TxQueue) done(tx *QueuedTx, hash gethcommon.Hash, err error) {
|
||||||
delete(q.inprogress, tx.ID)
|
delete(q.inprogress, tx.ID)
|
||||||
// hash is updated only if err is nil, but transaction is not removed from a queue
|
// hash is updated only if err is nil, but transaction is not removed from a queue
|
||||||
if err == nil {
|
if err == nil {
|
||||||
q.transactions[tx.ID].Result <- common.TransactionResult{Hash: hash, Error: err}
|
q.transactions[tx.ID].Result <- Result{Hash: hash, Error: err}
|
||||||
q.remove(tx.ID)
|
q.remove(tx.ID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if _, transient := transientErrs[err.Error()]; !transient {
|
if _, transient := transientErrs[err.Error()]; !transient {
|
||||||
q.transactions[tx.ID].Result <- common.TransactionResult{Error: err}
|
q.transactions[tx.ID].Result <- Result{Error: err}
|
||||||
q.remove(tx.ID)
|
q.remove(tx.ID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -227,7 +226,7 @@ func (q *TxQueue) Count() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Has checks whether transaction with a given identifier exists in queue
|
// Has checks whether transaction with a given identifier exists in queue
|
||||||
func (q *TxQueue) Has(id common.QueuedTxID) bool {
|
func (q *TxQueue) Has(id string) bool {
|
||||||
q.mu.RLock()
|
q.mu.RLock()
|
||||||
defer q.mu.RUnlock()
|
defer q.mu.RUnlock()
|
||||||
_, ok := q.transactions[id]
|
_, ok := q.transactions[id]
|
|
@ -1,29 +0,0 @@
|
||||||
package queue
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/status-im/status-go/geth/common"
|
|
||||||
"github.com/status-im/status-go/geth/signal"
|
|
||||||
)
|
|
||||||
|
|
||||||
//ErrTxQueueRunFailure - error running transaction queue
|
|
||||||
var ErrTxQueueRunFailure = errors.New("error running transaction queue")
|
|
||||||
|
|
||||||
// HaltOnPanic recovers from panic, logs issue, sends upward notification, and exits
|
|
||||||
func HaltOnPanic() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
err := fmt.Errorf("%v: %v", ErrTxQueueRunFailure, r)
|
|
||||||
|
|
||||||
// send signal up to native app
|
|
||||||
signal.Send(signal.Envelope{
|
|
||||||
Type: signal.EventNodeCrashed,
|
|
||||||
Event: signal.NodeCrashEvent{
|
|
||||||
Error: err,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
common.Fatalf(err) // os.exit(1) is called internally
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
package queue
|
package transactions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
@ -8,7 +8,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||||
gethcommon "github.com/ethereum/go-ethereum/common"
|
gethcommon "github.com/ethereum/go-ethereum/common"
|
||||||
|
|
||||||
"github.com/status-im/status-go/geth/common"
|
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,7 +21,7 @@ type QueueTestSuite struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *QueueTestSuite) SetupTest() {
|
func (s *QueueTestSuite) SetupTest() {
|
||||||
s.queue = New()
|
s.queue = newQueue()
|
||||||
s.queue.Start()
|
s.queue.Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +30,7 @@ func (s *QueueTestSuite) TearDownTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *QueueTestSuite) TestLockInprogressTransaction() {
|
func (s *QueueTestSuite) TestLockInprogressTransaction() {
|
||||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{})
|
tx := Create(context.Background(), SendTxArgs{})
|
||||||
s.NoError(s.queue.Enqueue(tx))
|
s.NoError(s.queue.Enqueue(tx))
|
||||||
enquedTx, err := s.queue.Get(tx.ID)
|
enquedTx, err := s.queue.Get(tx.ID)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
@ -43,7 +42,7 @@ func (s *QueueTestSuite) TestLockInprogressTransaction() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *QueueTestSuite) TestGetTransaction() {
|
func (s *QueueTestSuite) TestGetTransaction() {
|
||||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{})
|
tx := Create(context.Background(), SendTxArgs{})
|
||||||
s.NoError(s.queue.Enqueue(tx))
|
s.NoError(s.queue.Enqueue(tx))
|
||||||
for i := 2; i > 0; i-- {
|
for i := 2; i > 0; i-- {
|
||||||
enquedTx, err := s.queue.Get(tx.ID)
|
enquedTx, err := s.queue.Get(tx.ID)
|
||||||
|
@ -53,16 +52,16 @@ func (s *QueueTestSuite) TestGetTransaction() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *QueueTestSuite) TestAlreadyEnqueued() {
|
func (s *QueueTestSuite) TestAlreadyEnqueued() {
|
||||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{})
|
tx := Create(context.Background(), SendTxArgs{})
|
||||||
s.NoError(s.queue.Enqueue(tx))
|
s.NoError(s.queue.Enqueue(tx))
|
||||||
s.Equal(ErrQueuedTxExist, s.queue.Enqueue(tx))
|
s.Equal(ErrQueuedTxExist, s.queue.Enqueue(tx))
|
||||||
// try to enqueue another tx to double check locking
|
// try to enqueue another tx to double check locking
|
||||||
tx = common.CreateTransaction(context.Background(), common.SendTxArgs{})
|
tx = Create(context.Background(), SendTxArgs{})
|
||||||
s.NoError(s.queue.Enqueue(tx))
|
s.NoError(s.queue.Enqueue(tx))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *QueueTestSuite) testDone(hash gethcommon.Hash, err error) *common.QueuedTx {
|
func (s *QueueTestSuite) testDone(hash gethcommon.Hash, err error) *QueuedTx {
|
||||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{})
|
tx := Create(context.Background(), SendTxArgs{})
|
||||||
s.NoError(s.queue.Enqueue(tx))
|
s.NoError(s.queue.Enqueue(tx))
|
||||||
s.NoError(s.queue.Done(tx.ID, hash, err))
|
s.NoError(s.queue.Done(tx.ID, hash, err))
|
||||||
return tx
|
return tx
|
||||||
|
@ -116,16 +115,16 @@ func (s QueueTestSuite) TestMultipleDone() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *QueueTestSuite) TestEviction() {
|
func (s *QueueTestSuite) TestEviction() {
|
||||||
var first *common.QueuedTx
|
var first *QueuedTx
|
||||||
for i := 0; i < DefaultTxQueueCap; i++ {
|
for i := 0; i < DefaultTxQueueCap; i++ {
|
||||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{})
|
tx := Create(context.Background(), SendTxArgs{})
|
||||||
if first == nil {
|
if first == nil {
|
||||||
first = tx
|
first = tx
|
||||||
}
|
}
|
||||||
s.NoError(s.queue.Enqueue(tx))
|
s.NoError(s.queue.Enqueue(tx))
|
||||||
}
|
}
|
||||||
s.Equal(DefaultTxQueueCap, s.queue.Count())
|
s.Equal(DefaultTxQueueCap, s.queue.Count())
|
||||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{})
|
tx := Create(context.Background(), SendTxArgs{})
|
||||||
s.NoError(s.queue.Enqueue(tx))
|
s.NoError(s.queue.Enqueue(tx))
|
||||||
s.Equal(DefaultTxQueueCap, s.queue.Count())
|
s.Equal(DefaultTxQueueCap, s.queue.Count())
|
||||||
s.False(s.queue.Has(first.ID))
|
s.False(s.queue.Has(first.ID))
|
|
@ -12,9 +12,8 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/status-im/status-go/geth/account"
|
"github.com/status-im/status-go/geth/account"
|
||||||
"github.com/status-im/status-go/geth/common"
|
|
||||||
"github.com/status-im/status-go/geth/rpc"
|
"github.com/status-im/status-go/geth/rpc"
|
||||||
"github.com/status-im/status-go/geth/transactions/queue"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -36,7 +35,7 @@ type RPCClientProvider interface {
|
||||||
// Manager provides means to manage internal Status Backend (injected into LES)
|
// Manager provides means to manage internal Status Backend (injected into LES)
|
||||||
type Manager struct {
|
type Manager struct {
|
||||||
rpcClientProvider RPCClientProvider
|
rpcClientProvider RPCClientProvider
|
||||||
txQueue *queue.TxQueue
|
txQueue *TxQueue
|
||||||
ethTxClient EthTransactor
|
ethTxClient EthTransactor
|
||||||
notify bool
|
notify bool
|
||||||
completionTimeout time.Duration
|
completionTimeout time.Duration
|
||||||
|
@ -52,7 +51,7 @@ type Manager struct {
|
||||||
func NewManager(rpcClientProvider RPCClientProvider) *Manager {
|
func NewManager(rpcClientProvider RPCClientProvider) *Manager {
|
||||||
return &Manager{
|
return &Manager{
|
||||||
rpcClientProvider: rpcClientProvider,
|
rpcClientProvider: rpcClientProvider,
|
||||||
txQueue: queue.New(),
|
txQueue: newQueue(),
|
||||||
addrLock: &AddrLocker{},
|
addrLock: &AddrLocker{},
|
||||||
notify: true,
|
notify: true,
|
||||||
completionTimeout: DefaultTxSendCompletionTimeout,
|
completionTimeout: DefaultTxSendCompletionTimeout,
|
||||||
|
@ -83,14 +82,14 @@ func (m *Manager) Stop() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TransactionQueue returns a reference to the queue.
|
// TransactionQueue returns a reference to the queue.
|
||||||
func (m *Manager) TransactionQueue() *queue.TxQueue {
|
func (m *Manager) TransactionQueue() *TxQueue {
|
||||||
return m.txQueue
|
return m.txQueue
|
||||||
}
|
}
|
||||||
|
|
||||||
// QueueTransaction puts a transaction into the queue.
|
// QueueTransaction puts a transaction into the queue.
|
||||||
func (m *Manager) QueueTransaction(tx *common.QueuedTx) error {
|
func (m *Manager) QueueTransaction(tx *QueuedTx) error {
|
||||||
if !tx.Args.Valid() {
|
if !tx.Args.Valid() {
|
||||||
return common.ErrInvalidSendTxArgs
|
return ErrInvalidSendTxArgs
|
||||||
}
|
}
|
||||||
to := "<nil>"
|
to := "<nil>"
|
||||||
if tx.Args.To != nil {
|
if tx.Args.To != nil {
|
||||||
|
@ -106,8 +105,8 @@ func (m *Manager) QueueTransaction(tx *common.QueuedTx) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) txDone(tx *common.QueuedTx, hash gethcommon.Hash, err error) {
|
func (m *Manager) txDone(tx *QueuedTx, hash gethcommon.Hash, err error) {
|
||||||
if err := m.txQueue.Done(tx.ID, hash, err); err == queue.ErrQueuedTxIDNotFound {
|
if err := m.txQueue.Done(tx.ID, hash, err); err == ErrQueuedTxIDNotFound {
|
||||||
m.log.Warn("transaction is already removed from a queue", "ID", tx.ID)
|
m.log.Warn("transaction is already removed from a queue", "ID", tx.ID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -118,7 +117,7 @@ func (m *Manager) txDone(tx *common.QueuedTx, hash gethcommon.Hash, err error) {
|
||||||
|
|
||||||
// WaitForTransaction adds a transaction to the queue and blocks
|
// WaitForTransaction adds a transaction to the queue and blocks
|
||||||
// until it's completed, discarded or times out.
|
// until it's completed, discarded or times out.
|
||||||
func (m *Manager) WaitForTransaction(tx *common.QueuedTx) common.TransactionResult {
|
func (m *Manager) WaitForTransaction(tx *QueuedTx) Result {
|
||||||
m.log.Info("wait for transaction", "id", tx.ID)
|
m.log.Info("wait for transaction", "id", tx.ID)
|
||||||
// now wait up until transaction is:
|
// now wait up until transaction is:
|
||||||
// - completed (via CompleteQueuedTransaction),
|
// - completed (via CompleteQueuedTransaction),
|
||||||
|
@ -135,7 +134,7 @@ func (m *Manager) WaitForTransaction(tx *common.QueuedTx) common.TransactionResu
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotifyErrored sends a notification for the given transaction
|
// NotifyErrored sends a notification for the given transaction
|
||||||
func (m *Manager) NotifyErrored(id common.QueuedTxID, inputError error) error {
|
func (m *Manager) NotifyErrored(id string, inputError error) error {
|
||||||
tx, err := m.txQueue.Get(id)
|
tx, err := m.txQueue.Get(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.log.Warn("error getting a queued transaction", "err", err)
|
m.log.Warn("error getting a queued transaction", "err", err)
|
||||||
|
@ -150,7 +149,7 @@ func (m *Manager) NotifyErrored(id common.QueuedTxID, inputError error) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CompleteTransaction instructs backend to complete sending of a given transaction.
|
// CompleteTransaction instructs backend to complete sending of a given transaction.
|
||||||
func (m *Manager) CompleteTransaction(id common.QueuedTxID, account *account.SelectedExtKey) (hash gethcommon.Hash, err error) {
|
func (m *Manager) CompleteTransaction(id string, account *account.SelectedExtKey) (hash gethcommon.Hash, err error) {
|
||||||
m.log.Info("complete transaction", "id", id)
|
m.log.Info("complete transaction", "id", id)
|
||||||
tx, err := m.txQueue.Get(id)
|
tx, err := m.txQueue.Get(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -173,21 +172,21 @@ func (m *Manager) CompleteTransaction(id common.QueuedTxID, account *account.Sel
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure that only account which created the tx can complete it
|
// make sure that only account which created the tx can complete it
|
||||||
func (m *Manager) validateAccount(tx *common.QueuedTx, selectedAccount *account.SelectedExtKey) error {
|
func (m *Manager) validateAccount(tx *QueuedTx, selectedAccount *account.SelectedExtKey) error {
|
||||||
if selectedAccount == nil {
|
if selectedAccount == nil {
|
||||||
return account.ErrNoAccountSelected
|
return account.ErrNoAccountSelected
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure that only account which created the tx can complete it
|
// make sure that only account which created the tx can complete it
|
||||||
if tx.Args.From.Hex() != selectedAccount.Address.Hex() {
|
if tx.Args.From.Hex() != selectedAccount.Address.Hex() {
|
||||||
m.log.Warn("queued transaction does not belong to the selected account", "err", queue.ErrInvalidCompleteTxSender)
|
m.log.Warn("queued transaction does not belong to the selected account", "err", ErrInvalidCompleteTxSender)
|
||||||
return queue.ErrInvalidCompleteTxSender
|
return ErrInvalidCompleteTxSender
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Manager) completeTransaction(selectedAccount *account.SelectedExtKey, queuedTx *common.QueuedTx) (hash gethcommon.Hash, err error) {
|
func (m *Manager) completeTransaction(selectedAccount *account.SelectedExtKey, queuedTx *QueuedTx) (hash gethcommon.Hash, err error) {
|
||||||
m.log.Info("complete transaction", "id", queuedTx.ID)
|
m.log.Info("complete transaction", "id", queuedTx.ID)
|
||||||
m.addrLock.LockAddr(queuedTx.Args.From)
|
m.addrLock.LockAddr(queuedTx.Args.From)
|
||||||
var localNonce uint64
|
var localNonce uint64
|
||||||
|
@ -217,7 +216,7 @@ func (m *Manager) completeTransaction(selectedAccount *account.SelectedExtKey, q
|
||||||
}
|
}
|
||||||
args := queuedTx.Args
|
args := queuedTx.Args
|
||||||
if !args.Valid() {
|
if !args.Valid() {
|
||||||
return hash, common.ErrInvalidSendTxArgs
|
return hash, ErrInvalidSendTxArgs
|
||||||
}
|
}
|
||||||
gasPrice := (*big.Int)(args.GasPrice)
|
gasPrice := (*big.Int)(args.GasPrice)
|
||||||
if args.GasPrice == nil {
|
if args.GasPrice == nil {
|
||||||
|
@ -280,7 +279,7 @@ func (m *Manager) completeTransaction(selectedAccount *account.SelectedExtKey, q
|
||||||
}
|
}
|
||||||
|
|
||||||
// DiscardTransaction discards a given transaction from transaction queue
|
// DiscardTransaction discards a given transaction from transaction queue
|
||||||
func (m *Manager) DiscardTransaction(id common.QueuedTxID) error {
|
func (m *Manager) DiscardTransaction(id string) error {
|
||||||
tx, err := m.txQueue.Get(id)
|
tx, err := m.txQueue.Get(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -292,28 +291,11 @@ func (m *Manager) DiscardTransaction(id common.QueuedTxID) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// DiscardTransactions discards given multiple transactions from transaction queue
|
|
||||||
func (m *Manager) DiscardTransactions(ids []common.QueuedTxID) map[common.QueuedTxID]common.RawDiscardTransactionResult {
|
|
||||||
results := make(map[common.QueuedTxID]common.RawDiscardTransactionResult)
|
|
||||||
|
|
||||||
for _, txID := range ids {
|
|
||||||
err := m.DiscardTransaction(txID)
|
|
||||||
if err != nil {
|
|
||||||
results[txID] = common.RawDiscardTransactionResult{
|
|
||||||
Error: err,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return results
|
|
||||||
}
|
|
||||||
|
|
||||||
// SendTransactionRPCHandler is a handler for eth_sendTransaction method.
|
// SendTransactionRPCHandler is a handler for eth_sendTransaction method.
|
||||||
// It accepts one param which is a slice with a map of transaction params.
|
// It accepts one param which is a slice with a map of transaction params.
|
||||||
func (m *Manager) SendTransactionRPCHandler(ctx context.Context, args ...interface{}) (interface{}, error) {
|
func (m *Manager) SendTransactionRPCHandler(ctx context.Context, args ...interface{}) (interface{}, error) {
|
||||||
m.log.Info("SendTransactionRPCHandler called")
|
m.log.Info("SendTransactionRPCHandler called")
|
||||||
rpcCall := rpc.Call{Params: args}
|
tx := Create(ctx, m.rpcCalltoSendTxArgs(args...))
|
||||||
tx := common.CreateTransaction(ctx, rpcCall.ToSendTxArgs())
|
|
||||||
if err := m.QueueTransaction(tx); err != nil {
|
if err := m.QueueTransaction(tx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -323,3 +305,31 @@ func (m *Manager) SendTransactionRPCHandler(ctx context.Context, args ...interfa
|
||||||
}
|
}
|
||||||
return rst.Hash.Hex(), nil
|
return rst.Hash.Hex(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Manager) rpcCalltoSendTxArgs(args ...interface{}) SendTxArgs {
|
||||||
|
var err error
|
||||||
|
var fromAddr, toAddr gethcommon.Address
|
||||||
|
|
||||||
|
rpcCall := rpc.Call{Params: args}
|
||||||
|
fromAddr, err = rpcCall.ParseFromAddress()
|
||||||
|
if err != nil {
|
||||||
|
fromAddr = gethcommon.HexToAddress("0x0")
|
||||||
|
}
|
||||||
|
|
||||||
|
toAddr, err = rpcCall.ParseToAddress()
|
||||||
|
if err != nil {
|
||||||
|
toAddr = gethcommon.HexToAddress("0x0")
|
||||||
|
}
|
||||||
|
|
||||||
|
input := rpcCall.ParseInput()
|
||||||
|
data := rpcCall.ParseData()
|
||||||
|
return SendTxArgs{
|
||||||
|
To: &toAddr,
|
||||||
|
From: fromAddr,
|
||||||
|
Value: rpcCall.ParseValue(),
|
||||||
|
Input: input,
|
||||||
|
Data: data,
|
||||||
|
Gas: rpcCall.ParseGas(),
|
||||||
|
GasPrice: rpcCall.ParseGasPrice(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -19,11 +19,9 @@ import (
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
|
||||||
"github.com/status-im/status-go/geth/account"
|
"github.com/status-im/status-go/geth/account"
|
||||||
"github.com/status-im/status-go/geth/common"
|
|
||||||
"github.com/status-im/status-go/geth/params"
|
"github.com/status-im/status-go/geth/params"
|
||||||
"github.com/status-im/status-go/geth/rpc"
|
"github.com/status-im/status-go/geth/rpc"
|
||||||
"github.com/status-im/status-go/geth/transactions/fake"
|
"github.com/status-im/status-go/geth/transactions/fake"
|
||||||
"github.com/status-im/status-go/geth/transactions/queue"
|
|
||||||
. "github.com/status-im/status-go/t/utils"
|
. "github.com/status-im/status-go/t/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -75,7 +73,7 @@ var (
|
||||||
testNonce = hexutil.Uint64(10)
|
testNonce = hexutil.Uint64(10)
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *TxQueueTestSuite) setupTransactionPoolAPI(tx *common.QueuedTx, returnNonce, resultNonce hexutil.Uint64, account *account.SelectedExtKey, txErr error) {
|
func (s *TxQueueTestSuite) setupTransactionPoolAPI(tx *QueuedTx, returnNonce, resultNonce hexutil.Uint64, account *account.SelectedExtKey, txErr error) {
|
||||||
// Expect calls to gas functions only if there are no user defined values.
|
// Expect calls to gas functions only if there are no user defined values.
|
||||||
// And also set the expected gas and gas price for RLP encoding the expected tx.
|
// And also set the expected gas and gas price for RLP encoding the expected tx.
|
||||||
var usedGas hexutil.Uint64
|
var usedGas hexutil.Uint64
|
||||||
|
@ -99,7 +97,7 @@ func (s *TxQueueTestSuite) setupTransactionPoolAPI(tx *common.QueuedTx, returnNo
|
||||||
s.txServiceMock.EXPECT().SendRawTransaction(gomock.Any(), data).Return(gethcommon.Hash{}, txErr)
|
s.txServiceMock.EXPECT().SendRawTransaction(gomock.Any(), data).Return(gethcommon.Hash{}, txErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TxQueueTestSuite) rlpEncodeTx(tx *common.QueuedTx, config *params.NodeConfig, account *account.SelectedExtKey, nonce *hexutil.Uint64, gas hexutil.Uint64, gasPrice *big.Int) hexutil.Bytes {
|
func (s *TxQueueTestSuite) rlpEncodeTx(tx *QueuedTx, config *params.NodeConfig, account *account.SelectedExtKey, nonce *hexutil.Uint64, gas hexutil.Uint64, gasPrice *big.Int) hexutil.Bytes {
|
||||||
newTx := types.NewTransaction(
|
newTx := types.NewTransaction(
|
||||||
uint64(*nonce),
|
uint64(*nonce),
|
||||||
gethcommon.Address(*tx.Args.To),
|
gethcommon.Address(*tx.Args.To),
|
||||||
|
@ -152,7 +150,7 @@ func (s *TxQueueTestSuite) TestCompleteTransaction() {
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
s.T().Run(testCase.name, func(t *testing.T) {
|
s.T().Run(testCase.name, func(t *testing.T) {
|
||||||
s.SetupTest()
|
s.SetupTest()
|
||||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{
|
tx := Create(context.Background(), SendTxArgs{
|
||||||
From: account.FromAddress(TestConfig.Account1.Address),
|
From: account.FromAddress(TestConfig.Account1.Address),
|
||||||
To: account.ToAddress(TestConfig.Account2.Address),
|
To: account.ToAddress(TestConfig.Account2.Address),
|
||||||
Gas: testCase.gas,
|
Gas: testCase.gas,
|
||||||
|
@ -190,7 +188,7 @@ func (s *TxQueueTestSuite) TestCompleteTransactionMultipleTimes() {
|
||||||
AccountKey: &keystore.Key{PrivateKey: key},
|
AccountKey: &keystore.Key{PrivateKey: key},
|
||||||
}
|
}
|
||||||
|
|
||||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{
|
tx := Create(context.Background(), SendTxArgs{
|
||||||
From: account.FromAddress(TestConfig.Account1.Address),
|
From: account.FromAddress(TestConfig.Account1.Address),
|
||||||
To: account.ToAddress(TestConfig.Account2.Address),
|
To: account.ToAddress(TestConfig.Account2.Address),
|
||||||
})
|
})
|
||||||
|
@ -216,7 +214,7 @@ func (s *TxQueueTestSuite) TestCompleteTransactionMultipleTimes() {
|
||||||
defer mu.Unlock()
|
defer mu.Unlock()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
completedTx++
|
completedTx++
|
||||||
} else if err == queue.ErrQueuedTxInProgress {
|
} else if err == ErrQueuedTxInProgress {
|
||||||
inprogressTx++
|
inprogressTx++
|
||||||
} else {
|
} else {
|
||||||
s.Fail("tx failed with unexpected error: ", err.Error())
|
s.Fail("tx failed with unexpected error: ", err.Error())
|
||||||
|
@ -241,7 +239,7 @@ func (s *TxQueueTestSuite) TestAccountMismatch() {
|
||||||
Address: account.FromAddress(TestConfig.Account2.Address),
|
Address: account.FromAddress(TestConfig.Account2.Address),
|
||||||
}
|
}
|
||||||
|
|
||||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{
|
tx := Create(context.Background(), SendTxArgs{
|
||||||
From: account.FromAddress(TestConfig.Account1.Address),
|
From: account.FromAddress(TestConfig.Account1.Address),
|
||||||
To: account.ToAddress(TestConfig.Account2.Address),
|
To: account.ToAddress(TestConfig.Account2.Address),
|
||||||
})
|
})
|
||||||
|
@ -249,7 +247,7 @@ func (s *TxQueueTestSuite) TestAccountMismatch() {
|
||||||
s.NoError(s.manager.QueueTransaction(tx))
|
s.NoError(s.manager.QueueTransaction(tx))
|
||||||
|
|
||||||
_, err := s.manager.CompleteTransaction(tx.ID, selectedAccount)
|
_, err := s.manager.CompleteTransaction(tx.ID, selectedAccount)
|
||||||
s.Equal(err, queue.ErrInvalidCompleteTxSender)
|
s.Equal(err, ErrInvalidCompleteTxSender)
|
||||||
|
|
||||||
// Transaction should stay in the queue as mismatched accounts
|
// Transaction should stay in the queue as mismatched accounts
|
||||||
// is a recoverable error.
|
// is a recoverable error.
|
||||||
|
@ -257,7 +255,7 @@ func (s *TxQueueTestSuite) TestAccountMismatch() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TxQueueTestSuite) TestDiscardTransaction() {
|
func (s *TxQueueTestSuite) TestDiscardTransaction() {
|
||||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{
|
tx := Create(context.Background(), SendTxArgs{
|
||||||
From: account.FromAddress(TestConfig.Account1.Address),
|
From: account.FromAddress(TestConfig.Account1.Address),
|
||||||
To: account.ToAddress(TestConfig.Account2.Address),
|
To: account.ToAddress(TestConfig.Account2.Address),
|
||||||
})
|
})
|
||||||
|
@ -276,56 +274,8 @@ func (s *TxQueueTestSuite) TestDiscardTransaction() {
|
||||||
s.NoError(WaitClosed(w, time.Second))
|
s.NoError(WaitClosed(w, time.Second))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TxQueueTestSuite) TestDiscardTransactions() {
|
|
||||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{
|
|
||||||
From: account.FromAddress(TestConfig.Account1.Address),
|
|
||||||
To: account.ToAddress(TestConfig.Account2.Address),
|
|
||||||
})
|
|
||||||
var ids []common.QueuedTxID
|
|
||||||
ids = append(ids, tx.ID)
|
|
||||||
|
|
||||||
s.NoError(s.manager.QueueTransaction(tx))
|
|
||||||
w := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
result := s.manager.DiscardTransactions(ids)
|
|
||||||
s.Equal(0, len(result))
|
|
||||||
close(w)
|
|
||||||
}()
|
|
||||||
|
|
||||||
rst := s.manager.WaitForTransaction(tx)
|
|
||||||
s.Equal(ErrQueuedTxDiscarded, rst.Error)
|
|
||||||
// Transaction should be already removed from the queue.
|
|
||||||
s.False(s.manager.TransactionQueue().Has(tx.ID))
|
|
||||||
s.NoError(WaitClosed(w, time.Second))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *TxQueueTestSuite) TestDiscardTransactionsOnError() {
|
|
||||||
fakeTxID := common.QueuedTxID("7ab94f26-a866-4aba-1234-b4bbe98737a9")
|
|
||||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{
|
|
||||||
From: account.FromAddress(TestConfig.Account1.Address),
|
|
||||||
To: account.ToAddress(TestConfig.Account2.Address),
|
|
||||||
})
|
|
||||||
var ids []common.QueuedTxID
|
|
||||||
ids = append(ids, fakeTxID)
|
|
||||||
|
|
||||||
s.NoError(s.manager.QueueTransaction(tx))
|
|
||||||
w := make(chan struct{})
|
|
||||||
go func() {
|
|
||||||
result := s.manager.DiscardTransactions(ids)
|
|
||||||
s.Equal(1, len(result))
|
|
||||||
s.Equal(queue.ErrQueuedTxIDNotFound, result[fakeTxID].Error)
|
|
||||||
close(w)
|
|
||||||
}()
|
|
||||||
|
|
||||||
rst := s.manager.WaitForTransaction(tx)
|
|
||||||
s.Equal(ErrQueuedTxTimedOut, rst.Error)
|
|
||||||
// Transaction should be already removed from the queue.
|
|
||||||
s.False(s.manager.TransactionQueue().Has(tx.ID))
|
|
||||||
s.NoError(WaitClosed(w, time.Second))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *TxQueueTestSuite) TestCompletionTimedOut() {
|
func (s *TxQueueTestSuite) TestCompletionTimedOut() {
|
||||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{
|
tx := Create(context.Background(), SendTxArgs{
|
||||||
From: account.FromAddress(TestConfig.Account1.Address),
|
From: account.FromAddress(TestConfig.Account1.Address),
|
||||||
To: account.ToAddress(TestConfig.Account2.Address),
|
To: account.ToAddress(TestConfig.Account2.Address),
|
||||||
})
|
})
|
||||||
|
@ -351,7 +301,7 @@ func (s *TxQueueTestSuite) TestLocalNonce() {
|
||||||
}
|
}
|
||||||
nonce := hexutil.Uint64(0)
|
nonce := hexutil.Uint64(0)
|
||||||
for i := 0; i < txCount; i++ {
|
for i := 0; i < txCount; i++ {
|
||||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{
|
tx := Create(context.Background(), SendTxArgs{
|
||||||
From: account.FromAddress(TestConfig.Account1.Address),
|
From: account.FromAddress(TestConfig.Account1.Address),
|
||||||
To: account.ToAddress(TestConfig.Account2.Address),
|
To: account.ToAddress(TestConfig.Account2.Address),
|
||||||
})
|
})
|
||||||
|
@ -367,7 +317,7 @@ func (s *TxQueueTestSuite) TestLocalNonce() {
|
||||||
s.Equal(uint64(i)+1, resultNonce.(uint64))
|
s.Equal(uint64(i)+1, resultNonce.(uint64))
|
||||||
}
|
}
|
||||||
nonce = hexutil.Uint64(5)
|
nonce = hexutil.Uint64(5)
|
||||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{
|
tx := Create(context.Background(), SendTxArgs{
|
||||||
From: account.FromAddress(TestConfig.Account1.Address),
|
From: account.FromAddress(TestConfig.Account1.Address),
|
||||||
To: account.ToAddress(TestConfig.Account2.Address),
|
To: account.ToAddress(TestConfig.Account2.Address),
|
||||||
})
|
})
|
||||||
|
@ -383,7 +333,7 @@ func (s *TxQueueTestSuite) TestLocalNonce() {
|
||||||
|
|
||||||
testErr := errors.New("test")
|
testErr := errors.New("test")
|
||||||
s.txServiceMock.EXPECT().GetTransactionCount(gomock.Any(), selectedAccount.Address, gethrpc.PendingBlockNumber).Return(nil, testErr)
|
s.txServiceMock.EXPECT().GetTransactionCount(gomock.Any(), selectedAccount.Address, gethrpc.PendingBlockNumber).Return(nil, testErr)
|
||||||
tx = common.CreateTransaction(context.Background(), common.SendTxArgs{
|
tx = Create(context.Background(), SendTxArgs{
|
||||||
From: account.FromAddress(TestConfig.Account1.Address),
|
From: account.FromAddress(TestConfig.Account1.Address),
|
||||||
To: account.ToAddress(TestConfig.Account2.Address),
|
To: account.ToAddress(TestConfig.Account2.Address),
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
package transactions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
// errors
|
||||||
|
var (
|
||||||
|
ErrInvalidSendTxArgs = errors.New("Transaction arguments are invalid (are both 'input' and 'data' fields used?)")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Result is a JSON returned from transaction complete function (used internally)
|
||||||
|
type Result struct {
|
||||||
|
Hash common.Hash
|
||||||
|
Error error
|
||||||
|
}
|
||||||
|
|
||||||
|
// QueuedTx holds enough information to complete the queued transaction.
|
||||||
|
type QueuedTx struct {
|
||||||
|
ID string
|
||||||
|
Context context.Context
|
||||||
|
Args SendTxArgs
|
||||||
|
Result chan Result
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendTxArgs represents the arguments to submit a new transaction into the transaction pool.
|
||||||
|
// This struct is based on go-ethereum's type in internal/ethapi/api.go, but we have freedom
|
||||||
|
// over the exact layout of this struct.
|
||||||
|
type SendTxArgs struct {
|
||||||
|
From common.Address `json:"from"`
|
||||||
|
To *common.Address `json:"to"`
|
||||||
|
Gas *hexutil.Uint64 `json:"gas"`
|
||||||
|
GasPrice *hexutil.Big `json:"gasPrice"`
|
||||||
|
Value *hexutil.Big `json:"value"`
|
||||||
|
Nonce *hexutil.Uint64 `json:"nonce"`
|
||||||
|
// We keep both "input" and "data" for backward compatibility.
|
||||||
|
// "input" is a preferred field.
|
||||||
|
// see `vendor/github.com/ethereum/go-ethereum/internal/ethapi/api.go:1107`
|
||||||
|
Input hexutil.Bytes `json:"input"`
|
||||||
|
Data hexutil.Bytes `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid checks whether this structure is filled in correctly.
|
||||||
|
func (args SendTxArgs) Valid() bool {
|
||||||
|
// if at least one of the fields is empty, it is a valid struct
|
||||||
|
if isNilOrEmpty(args.Input) || isNilOrEmpty(args.Data) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// we only allow both fields to present if they have the same data
|
||||||
|
return bytes.Equal(args.Input, args.Data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInput returns either Input or Data field's value dependent on what is filled.
|
||||||
|
func (args SendTxArgs) GetInput() hexutil.Bytes {
|
||||||
|
if !isNilOrEmpty(args.Input) {
|
||||||
|
return args.Input
|
||||||
|
}
|
||||||
|
|
||||||
|
return args.Data
|
||||||
|
}
|
||||||
|
|
||||||
|
func isNilOrEmpty(bytes hexutil.Bytes) bool {
|
||||||
|
return bytes == nil || len(bytes) == 0
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package common
|
package transactions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
|
@ -1,18 +1,16 @@
|
||||||
package common
|
package transactions
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"github.com/pborman/uuid"
|
"github.com/pborman/uuid"
|
||||||
"github.com/status-im/status-go/static"
|
"github.com/status-im/status-go/geth/signal"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -23,27 +21,28 @@ const (
|
||||||
|
|
||||||
type contextKey string // in order to make sure that our context key does not collide with keys from other packages
|
type contextKey string // in order to make sure that our context key does not collide with keys from other packages
|
||||||
|
|
||||||
// All general log messages in this package should be routed through this logger.
|
//ErrTxQueueRunFailure - error running transaction queue
|
||||||
var logger = log.New("package", "status-go/geth/common")
|
var ErrTxQueueRunFailure = errors.New("error running transaction queue")
|
||||||
|
|
||||||
// ImportTestAccount imports keystore from static resources, see "static/keys" folder
|
// haltOnPanic recovers from panic, logs issue, sends upward notification, and exits
|
||||||
func ImportTestAccount(keystoreDir, accountFile string) error {
|
func haltOnPanic() {
|
||||||
// make sure that keystore folder exists
|
if r := recover(); r != nil {
|
||||||
if _, err := os.Stat(keystoreDir); os.IsNotExist(err) {
|
err := fmt.Errorf("%v: %v", ErrTxQueueRunFailure, r)
|
||||||
os.MkdirAll(keystoreDir, os.ModePerm) // nolint: errcheck, gas
|
|
||||||
|
// send signal up to native app
|
||||||
|
signal.Send(signal.Envelope{
|
||||||
|
Type: signal.EventNodeCrashed,
|
||||||
|
Event: signal.NodeCrashEvent{
|
||||||
|
Error: err,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
fatalf(err) // os.exit(1) is called internally
|
||||||
}
|
}
|
||||||
|
|
||||||
dst := filepath.Join(keystoreDir, accountFile)
|
|
||||||
err := ioutil.WriteFile(dst, static.MustAsset("keys/"+accountFile), 0644)
|
|
||||||
if err != nil {
|
|
||||||
logger.Warn("cannot copy test account PK", "error", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MessageIDFromContext returns message id from context (if exists)
|
// messageIDFromContext returns message id from context (if exists)
|
||||||
func MessageIDFromContext(ctx context.Context) string {
|
func messageIDFromContext(ctx context.Context) string {
|
||||||
if ctx == nil {
|
if ctx == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@ -54,10 +53,10 @@ func MessageIDFromContext(ctx context.Context) string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fatalf is used to halt the execution.
|
// fatalf is used to halt the execution.
|
||||||
// When called the function prints stack end exits.
|
// When called the function prints stack end exits.
|
||||||
// Failure is logged into both StdErr and StdOut.
|
// Failure is logged into both StdErr and StdOut.
|
||||||
func Fatalf(reason interface{}, args ...interface{}) {
|
func fatalf(reason interface{}, args ...interface{}) {
|
||||||
// decide on output stream
|
// decide on output stream
|
||||||
w := io.MultiWriter(os.Stdout, os.Stderr)
|
w := io.MultiWriter(os.Stdout, os.Stderr)
|
||||||
outf, _ := os.Stdout.Stat() // nolint: gas
|
outf, _ := os.Stdout.Stat() // nolint: gas
|
||||||
|
@ -79,12 +78,12 @@ func Fatalf(reason interface{}, args ...interface{}) {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateTransaction returns a transaction object.
|
// Create returns a transaction object.
|
||||||
func CreateTransaction(ctx context.Context, args SendTxArgs) *QueuedTx {
|
func Create(ctx context.Context, args SendTxArgs) *QueuedTx {
|
||||||
return &QueuedTx{
|
return &QueuedTx{
|
||||||
ID: QueuedTxID(uuid.New()),
|
ID: uuid.New(),
|
||||||
Context: ctx,
|
Context: ctx,
|
||||||
Args: args,
|
Args: args,
|
||||||
Result: make(chan TransactionResult, 1),
|
Result: make(chan Result, 1),
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,7 +8,6 @@ import (
|
||||||
|
|
||||||
"github.com/NaySoftware/go-fcm"
|
"github.com/NaySoftware/go-fcm"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/status-im/status-go/geth/common"
|
|
||||||
"github.com/status-im/status-go/geth/params"
|
"github.com/status-im/status-go/geth/params"
|
||||||
"github.com/status-im/status-go/profiling"
|
"github.com/status-im/status-go/profiling"
|
||||||
"gopkg.in/go-playground/validator.v9"
|
"gopkg.in/go-playground/validator.v9"
|
||||||
|
@ -197,7 +196,7 @@ func Logout() *C.char {
|
||||||
//CompleteTransaction instructs backend to complete sending of a given transaction
|
//CompleteTransaction instructs backend to complete sending of a given transaction
|
||||||
//export CompleteTransaction
|
//export CompleteTransaction
|
||||||
func CompleteTransaction(id, password *C.char) *C.char {
|
func CompleteTransaction(id, password *C.char) *C.char {
|
||||||
txHash, err := statusAPI.CompleteTransaction(common.QueuedTxID(C.GoString(id)), C.GoString(password))
|
txHash, err := statusAPI.CompleteTransaction(C.GoString(id), C.GoString(password))
|
||||||
|
|
||||||
errString := ""
|
errString := ""
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -205,7 +204,7 @@ func CompleteTransaction(id, password *C.char) *C.char {
|
||||||
errString = err.Error()
|
errString = err.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
out := common.CompleteTransactionResult{
|
out := CompleteTransactionResult{
|
||||||
ID: C.GoString(id),
|
ID: C.GoString(id),
|
||||||
Hash: txHash.Hex(),
|
Hash: txHash.Hex(),
|
||||||
Error: errString,
|
Error: errString,
|
||||||
|
@ -222,30 +221,30 @@ func CompleteTransaction(id, password *C.char) *C.char {
|
||||||
//CompleteTransactions instructs backend to complete sending of multiple transactions
|
//CompleteTransactions instructs backend to complete sending of multiple transactions
|
||||||
//export CompleteTransactions
|
//export CompleteTransactions
|
||||||
func CompleteTransactions(ids, password *C.char) *C.char {
|
func CompleteTransactions(ids, password *C.char) *C.char {
|
||||||
out := common.CompleteTransactionsResult{}
|
out := CompleteTransactionsResult{}
|
||||||
out.Results = make(map[string]common.CompleteTransactionResult)
|
out.Results = make(map[string]CompleteTransactionResult)
|
||||||
|
|
||||||
parsedIDs, err := ParseJSONArray(C.GoString(ids))
|
parsedIDs, err := ParseJSONArray(C.GoString(ids))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
out.Results["none"] = common.CompleteTransactionResult{
|
out.Results["none"] = CompleteTransactionResult{
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
txIDs := make([]common.QueuedTxID, len(parsedIDs))
|
txIDs := make([]string, len(parsedIDs))
|
||||||
for i, id := range parsedIDs {
|
for i, id := range parsedIDs {
|
||||||
txIDs[i] = common.QueuedTxID(id)
|
txIDs[i] = id
|
||||||
}
|
}
|
||||||
|
|
||||||
results := statusAPI.CompleteTransactions(txIDs, C.GoString(password))
|
results := statusAPI.CompleteTransactions(txIDs, C.GoString(password))
|
||||||
for txID, result := range results {
|
for txID, result := range results {
|
||||||
txResult := common.CompleteTransactionResult{
|
txResult := CompleteTransactionResult{
|
||||||
ID: string(txID),
|
ID: txID,
|
||||||
Hash: result.Hash.Hex(),
|
Hash: result.Hash.Hex(),
|
||||||
}
|
}
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
txResult.Error = result.Error.Error()
|
txResult.Error = result.Error.Error()
|
||||||
}
|
}
|
||||||
out.Results[string(txID)] = txResult
|
out.Results[txID] = txResult
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +260,7 @@ func CompleteTransactions(ids, password *C.char) *C.char {
|
||||||
//DiscardTransaction discards a given transaction from transaction queue
|
//DiscardTransaction discards a given transaction from transaction queue
|
||||||
//export DiscardTransaction
|
//export DiscardTransaction
|
||||||
func DiscardTransaction(id *C.char) *C.char {
|
func DiscardTransaction(id *C.char) *C.char {
|
||||||
err := statusAPI.DiscardTransaction(common.QueuedTxID(C.GoString(id)))
|
err := statusAPI.DiscardTransaction(C.GoString(id))
|
||||||
|
|
||||||
errString := ""
|
errString := ""
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -269,7 +268,7 @@ func DiscardTransaction(id *C.char) *C.char {
|
||||||
errString = err.Error()
|
errString = err.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
out := common.DiscardTransactionResult{
|
out := DiscardTransactionResult{
|
||||||
ID: C.GoString(id),
|
ID: C.GoString(id),
|
||||||
Error: errString,
|
Error: errString,
|
||||||
}
|
}
|
||||||
|
@ -285,29 +284,26 @@ func DiscardTransaction(id *C.char) *C.char {
|
||||||
//DiscardTransactions discards given multiple transactions from transaction queue
|
//DiscardTransactions discards given multiple transactions from transaction queue
|
||||||
//export DiscardTransactions
|
//export DiscardTransactions
|
||||||
func DiscardTransactions(ids *C.char) *C.char {
|
func DiscardTransactions(ids *C.char) *C.char {
|
||||||
out := common.DiscardTransactionsResult{}
|
out := DiscardTransactionsResult{}
|
||||||
out.Results = make(map[string]common.DiscardTransactionResult)
|
out.Results = make(map[string]DiscardTransactionResult)
|
||||||
|
|
||||||
parsedIDs, err := ParseJSONArray(C.GoString(ids))
|
parsedIDs, err := ParseJSONArray(C.GoString(ids))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
out.Results["none"] = common.DiscardTransactionResult{
|
out.Results["none"] = DiscardTransactionResult{
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
txIDs := make([]common.QueuedTxID, len(parsedIDs))
|
txIDs := make([]string, len(parsedIDs))
|
||||||
for i, id := range parsedIDs {
|
for i, id := range parsedIDs {
|
||||||
txIDs[i] = common.QueuedTxID(id)
|
txIDs[i] = id
|
||||||
}
|
}
|
||||||
|
|
||||||
results := statusAPI.DiscardTransactions(txIDs)
|
results := statusAPI.DiscardTransactions(txIDs)
|
||||||
for txID, result := range results {
|
for txID, err := range results {
|
||||||
txResult := common.DiscardTransactionResult{
|
out.Results[txID] = DiscardTransactionResult{
|
||||||
ID: string(txID),
|
ID: txID,
|
||||||
|
Error: err.Error(),
|
||||||
}
|
}
|
||||||
if result.Error != nil {
|
|
||||||
txResult.Error = result.Error.Error()
|
|
||||||
}
|
|
||||||
out.Results[string(txID)] = txResult
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,11 +31,9 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/status-im/status-go/geth/account"
|
"github.com/status-im/status-go/geth/account"
|
||||||
"github.com/status-im/status-go/geth/common"
|
|
||||||
"github.com/status-im/status-go/geth/params"
|
"github.com/status-im/status-go/geth/params"
|
||||||
"github.com/status-im/status-go/geth/signal"
|
"github.com/status-im/status-go/geth/signal"
|
||||||
"github.com/status-im/status-go/geth/transactions"
|
"github.com/status-im/status-go/geth/transactions"
|
||||||
"github.com/status-im/status-go/geth/transactions/queue"
|
|
||||||
"github.com/status-im/status-go/static"
|
"github.com/status-im/status-go/static"
|
||||||
. "github.com/status-im/status-go/t/utils" //nolint: golint
|
. "github.com/status-im/status-go/t/utils" //nolint: golint
|
||||||
)
|
)
|
||||||
|
@ -70,10 +68,10 @@ func testExportedAPI(t *testing.T, done chan struct{}) {
|
||||||
|
|
||||||
// prepare accounts
|
// prepare accounts
|
||||||
testKeyDir := filepath.Join(testChainDir, "keystore")
|
testKeyDir := filepath.Join(testChainDir, "keystore")
|
||||||
if err := common.ImportTestAccount(testKeyDir, GetAccount1PKFile()); err != nil {
|
if err := ImportTestAccount(testKeyDir, GetAccount1PKFile()); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
if err := common.ImportTestAccount(testKeyDir, GetAccount2PKFile()); err != nil {
|
if err := ImportTestAccount(testKeyDir, GetAccount2PKFile()); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,10 +173,10 @@ func testVerifyAccountPassword(t *testing.T) bool {
|
||||||
}
|
}
|
||||||
defer os.RemoveAll(tmpDir) // nolint: errcheck
|
defer os.RemoveAll(tmpDir) // nolint: errcheck
|
||||||
|
|
||||||
if err = common.ImportTestAccount(tmpDir, GetAccount1PKFile()); err != nil {
|
if err = ImportTestAccount(tmpDir, GetAccount1PKFile()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if err = common.ImportTestAccount(tmpDir, GetAccount2PKFile()); err != nil {
|
if err = ImportTestAccount(tmpDir, GetAccount2PKFile()); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -798,7 +796,7 @@ func testCompleteTransaction(t *testing.T) bool {
|
||||||
event := envelope.Event.(map[string]interface{})
|
event := envelope.Event.(map[string]interface{})
|
||||||
t.Logf("transaction queued (will be completed shortly): {id: %s}\n", event["id"].(string))
|
t.Logf("transaction queued (will be completed shortly): {id: %s}\n", event["id"].(string))
|
||||||
|
|
||||||
completeTxResponse := common.CompleteTransactionResult{}
|
completeTxResponse := CompleteTransactionResult{}
|
||||||
rawResponse := CompleteTransaction(C.CString(event["id"].(string)), C.CString(TestConfig.Account1.Password))
|
rawResponse := CompleteTransaction(C.CString(event["id"].(string)), C.CString(TestConfig.Account1.Password))
|
||||||
|
|
||||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &completeTxResponse); err != nil {
|
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &completeTxResponse); err != nil {
|
||||||
|
@ -818,7 +816,7 @@ func testCompleteTransaction(t *testing.T) bool {
|
||||||
})
|
})
|
||||||
|
|
||||||
// this call blocks, up until Complete Transaction is called
|
// this call blocks, up until Complete Transaction is called
|
||||||
txCheckHash, err := statusAPI.SendTransaction(context.TODO(), common.SendTxArgs{
|
txCheckHash, err := statusAPI.SendTransaction(context.TODO(), transactions.SendTxArgs{
|
||||||
From: account.FromAddress(TestConfig.Account1.Address),
|
From: account.FromAddress(TestConfig.Account1.Address),
|
||||||
To: account.ToAddress(TestConfig.Account2.Address),
|
To: account.ToAddress(TestConfig.Account2.Address),
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||||
|
@ -883,7 +881,7 @@ func testCompleteMultipleQueuedTransactions(t *testing.T) bool { //nolint: gocyc
|
||||||
|
|
||||||
// this call blocks, and should return when DiscardQueuedTransaction() for a given tx id is called
|
// this call blocks, and should return when DiscardQueuedTransaction() for a given tx id is called
|
||||||
sendTx := func() {
|
sendTx := func() {
|
||||||
txHashCheck, err := statusAPI.SendTransaction(context.TODO(), common.SendTxArgs{
|
txHashCheck, err := statusAPI.SendTransaction(context.TODO(), transactions.SendTxArgs{
|
||||||
From: account.FromAddress(TestConfig.Account1.Address),
|
From: account.FromAddress(TestConfig.Account1.Address),
|
||||||
To: account.ToAddress(TestConfig.Account2.Address),
|
To: account.ToAddress(TestConfig.Account2.Address),
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||||
|
@ -912,14 +910,14 @@ func testCompleteMultipleQueuedTransactions(t *testing.T) bool { //nolint: gocyc
|
||||||
|
|
||||||
// complete
|
// complete
|
||||||
resultsString := CompleteTransactions(C.CString(string(updatedTxIDStrings)), C.CString(TestConfig.Account1.Password))
|
resultsString := CompleteTransactions(C.CString(string(updatedTxIDStrings)), C.CString(TestConfig.Account1.Password))
|
||||||
resultsStruct := common.CompleteTransactionsResult{}
|
resultsStruct := CompleteTransactionsResult{}
|
||||||
if err := json.Unmarshal([]byte(C.GoString(resultsString)), &resultsStruct); err != nil {
|
if err := json.Unmarshal([]byte(C.GoString(resultsString)), &resultsStruct); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
results := resultsStruct.Results
|
results := resultsStruct.Results
|
||||||
|
|
||||||
if len(results) != (testTxCount+1) || results["invalid-tx-id"].Error != queue.ErrQueuedTxIDNotFound.Error() {
|
if len(results) != (testTxCount+1) || results["invalid-tx-id"].Error != transactions.ErrQueuedTxIDNotFound.Error() {
|
||||||
t.Errorf("cannot complete txs: %v", results)
|
t.Errorf("cannot complete txs: %v", results)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -944,7 +942,7 @@ func testCompleteMultipleQueuedTransactions(t *testing.T) bool { //nolint: gocyc
|
||||||
|
|
||||||
time.Sleep(1 * time.Second) // make sure that tx complete signal propagates
|
time.Sleep(1 * time.Second) // make sure that tx complete signal propagates
|
||||||
for _, txID := range parsedIDs {
|
for _, txID := range parsedIDs {
|
||||||
if txQueue.Has(common.QueuedTxID(txID)) {
|
if txQueue.Has(string(txID)) {
|
||||||
t.Errorf("txqueue should not have test tx at this point (it should be completed): %s", txID)
|
t.Errorf("txqueue should not have test tx at this point (it should be completed): %s", txID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1010,13 +1008,13 @@ func testDiscardTransaction(t *testing.T) bool { //nolint: gocyclo
|
||||||
txID = event["id"].(string)
|
txID = event["id"].(string)
|
||||||
t.Logf("transaction queued (will be discarded soon): {id: %s}\n", txID)
|
t.Logf("transaction queued (will be discarded soon): {id: %s}\n", txID)
|
||||||
|
|
||||||
if !txQueue.Has(common.QueuedTxID(txID)) {
|
if !txQueue.Has(string(txID)) {
|
||||||
t.Errorf("txqueue should still have test tx: %s", txID)
|
t.Errorf("txqueue should still have test tx: %s", txID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// discard
|
// discard
|
||||||
discardResponse := common.DiscardTransactionResult{}
|
discardResponse := DiscardTransactionResult{}
|
||||||
rawResponse := DiscardTransaction(C.CString(txID))
|
rawResponse := DiscardTransaction(C.CString(txID))
|
||||||
|
|
||||||
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &discardResponse); err != nil {
|
if err := json.Unmarshal([]byte(C.GoString(rawResponse)), &discardResponse); err != nil {
|
||||||
|
@ -1029,14 +1027,14 @@ func testDiscardTransaction(t *testing.T) bool { //nolint: gocyclo
|
||||||
}
|
}
|
||||||
|
|
||||||
// try completing discarded transaction
|
// try completing discarded transaction
|
||||||
_, err := statusAPI.CompleteTransaction(common.QueuedTxID(txID), TestConfig.Account1.Password)
|
_, err := statusAPI.CompleteTransaction(string(txID), TestConfig.Account1.Password)
|
||||||
if err != queue.ErrQueuedTxIDNotFound {
|
if err != transactions.ErrQueuedTxIDNotFound {
|
||||||
t.Error("expects tx not found, but call to CompleteTransaction succeeded")
|
t.Error("expects tx not found, but call to CompleteTransaction succeeded")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(1 * time.Second) // make sure that tx complete signal propagates
|
time.Sleep(1 * time.Second) // make sure that tx complete signal propagates
|
||||||
if txQueue.Has(common.QueuedTxID(txID)) {
|
if txQueue.Has(string(txID)) {
|
||||||
t.Errorf("txqueue should not have test tx at this point (it should be discarded): %s", txID)
|
t.Errorf("txqueue should not have test tx at this point (it should be discarded): %s", txID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1066,7 +1064,7 @@ func testDiscardTransaction(t *testing.T) bool { //nolint: gocyclo
|
||||||
})
|
})
|
||||||
|
|
||||||
// this call blocks, and should return when DiscardQueuedTransaction() is called
|
// this call blocks, and should return when DiscardQueuedTransaction() is called
|
||||||
txHashCheck, err := statusAPI.SendTransaction(context.TODO(), common.SendTxArgs{
|
txHashCheck, err := statusAPI.SendTransaction(context.TODO(), transactions.SendTxArgs{
|
||||||
From: account.FromAddress(TestConfig.Account1.Address),
|
From: account.FromAddress(TestConfig.Account1.Address),
|
||||||
To: account.ToAddress(TestConfig.Account2.Address),
|
To: account.ToAddress(TestConfig.Account2.Address),
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||||
|
@ -1123,7 +1121,7 @@ func testDiscardMultipleQueuedTransactions(t *testing.T) bool { //nolint: gocycl
|
||||||
txID = event["id"].(string)
|
txID = event["id"].(string)
|
||||||
t.Logf("transaction queued (will be discarded soon): {id: %s}\n", txID)
|
t.Logf("transaction queued (will be discarded soon): {id: %s}\n", txID)
|
||||||
|
|
||||||
if !txQueue.Has(common.QueuedTxID(txID)) {
|
if !txQueue.Has(string(txID)) {
|
||||||
t.Errorf("txqueue should still have test tx: %s", txID)
|
t.Errorf("txqueue should still have test tx: %s", txID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1157,7 +1155,7 @@ func testDiscardMultipleQueuedTransactions(t *testing.T) bool { //nolint: gocycl
|
||||||
|
|
||||||
// this call blocks, and should return when DiscardQueuedTransaction() for a given tx id is called
|
// this call blocks, and should return when DiscardQueuedTransaction() for a given tx id is called
|
||||||
sendTx := func() {
|
sendTx := func() {
|
||||||
txHashCheck, err := statusAPI.SendTransaction(context.TODO(), common.SendTxArgs{
|
txHashCheck, err := statusAPI.SendTransaction(context.TODO(), transactions.SendTxArgs{
|
||||||
From: account.FromAddress(TestConfig.Account1.Address),
|
From: account.FromAddress(TestConfig.Account1.Address),
|
||||||
To: account.ToAddress(TestConfig.Account2.Address),
|
To: account.ToAddress(TestConfig.Account2.Address),
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||||
|
@ -1186,21 +1184,21 @@ func testDiscardMultipleQueuedTransactions(t *testing.T) bool { //nolint: gocycl
|
||||||
|
|
||||||
// discard
|
// discard
|
||||||
discardResultsString := DiscardTransactions(C.CString(string(updatedTxIDStrings)))
|
discardResultsString := DiscardTransactions(C.CString(string(updatedTxIDStrings)))
|
||||||
discardResultsStruct := common.DiscardTransactionsResult{}
|
discardResultsStruct := DiscardTransactionsResult{}
|
||||||
if err := json.Unmarshal([]byte(C.GoString(discardResultsString)), &discardResultsStruct); err != nil {
|
if err := json.Unmarshal([]byte(C.GoString(discardResultsString)), &discardResultsStruct); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
discardResults := discardResultsStruct.Results
|
discardResults := discardResultsStruct.Results
|
||||||
|
|
||||||
if len(discardResults) != 1 || discardResults["invalid-tx-id"].Error != queue.ErrQueuedTxIDNotFound.Error() {
|
if len(discardResults) != 1 || discardResults["invalid-tx-id"].Error != transactions.ErrQueuedTxIDNotFound.Error() {
|
||||||
t.Errorf("cannot discard txs: %v", discardResults)
|
t.Errorf("cannot discard txs: %v", discardResults)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// try completing discarded transaction
|
// try completing discarded transaction
|
||||||
completeResultsString := CompleteTransactions(C.CString(string(updatedTxIDStrings)), C.CString(TestConfig.Account1.Password))
|
completeResultsString := CompleteTransactions(C.CString(string(updatedTxIDStrings)), C.CString(TestConfig.Account1.Password))
|
||||||
completeResultsStruct := common.CompleteTransactionsResult{}
|
completeResultsStruct := CompleteTransactionsResult{}
|
||||||
if err := json.Unmarshal([]byte(C.GoString(completeResultsString)), &completeResultsStruct); err != nil {
|
if err := json.Unmarshal([]byte(C.GoString(completeResultsString)), &completeResultsStruct); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
return
|
return
|
||||||
|
@ -1215,7 +1213,7 @@ func testDiscardMultipleQueuedTransactions(t *testing.T) bool { //nolint: gocycl
|
||||||
t.Errorf("tx id not set in result: expected id is %s", txID)
|
t.Errorf("tx id not set in result: expected id is %s", txID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if txResult.Error != queue.ErrQueuedTxIDNotFound.Error() {
|
if txResult.Error != transactions.ErrQueuedTxIDNotFound.Error() {
|
||||||
t.Errorf("invalid error for %s", txResult.Hash)
|
t.Errorf("invalid error for %s", txResult.Hash)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1227,7 +1225,7 @@ func testDiscardMultipleQueuedTransactions(t *testing.T) bool { //nolint: gocycl
|
||||||
|
|
||||||
time.Sleep(1 * time.Second) // make sure that tx complete signal propagates
|
time.Sleep(1 * time.Second) // make sure that tx complete signal propagates
|
||||||
for _, txID := range parsedIDs {
|
for _, txID := range parsedIDs {
|
||||||
if txQueue.Has(common.QueuedTxID(txID)) {
|
if txQueue.Has(string(txID)) {
|
||||||
t.Errorf("txqueue should not have test tx at this point (it should be discarded): %s", txID)
|
t.Errorf("txqueue should not have test tx at this point (it should be discarded): %s", txID)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1412,10 +1410,10 @@ func startTestNode(t *testing.T) <-chan struct{} {
|
||||||
|
|
||||||
// inject test accounts
|
// inject test accounts
|
||||||
testKeyDir := filepath.Join(testDir, "keystore")
|
testKeyDir := filepath.Join(testDir, "keystore")
|
||||||
if err := common.ImportTestAccount(testKeyDir, GetAccount1PKFile()); err != nil {
|
if err := ImportTestAccount(testKeyDir, GetAccount1PKFile()); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
if err := common.ImportTestAccount(testKeyDir, GetAccount2PKFile()); err != nil {
|
if err := ImportTestAccount(testKeyDir, GetAccount2PKFile()); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
23
lib/types.go
23
lib/types.go
|
@ -75,3 +75,26 @@ type NotifyResult struct {
|
||||||
Status bool `json:"status"`
|
Status bool `json:"status"`
|
||||||
Error string `json:"error,omitempty"`
|
Error string `json:"error,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CompleteTransactionResult is a JSON returned from transaction complete function (used in exposed method)
|
||||||
|
type CompleteTransactionResult struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Hash string `json:"hash"`
|
||||||
|
Error string `json:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CompleteTransactionsResult is list of results from CompleteTransactions() (used in exposed method)
|
||||||
|
type CompleteTransactionsResult struct {
|
||||||
|
Results map[string]CompleteTransactionResult `json:"results"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DiscardTransactionResult is a JSON returned from transaction discard function
|
||||||
|
type DiscardTransactionResult struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Error string `json:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// DiscardTransactionsResult is a list of results from DiscardTransactions()
|
||||||
|
type DiscardTransactionsResult struct {
|
||||||
|
Results map[string]DiscardTransactionResult `json:"results"`
|
||||||
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/status-im/status-go/geth/account"
|
"github.com/status-im/status-go/geth/account"
|
||||||
"github.com/status-im/status-go/geth/common"
|
|
||||||
"github.com/status-im/status-go/geth/jail"
|
"github.com/status-im/status-go/geth/jail"
|
||||||
"github.com/status-im/status-go/geth/node"
|
"github.com/status-im/status-go/geth/node"
|
||||||
"github.com/status-im/status-go/geth/params"
|
"github.com/status-im/status-go/geth/params"
|
||||||
|
@ -148,13 +147,13 @@ func (s *APIBackendTestSuite) TestRaceConditions() {
|
||||||
},
|
},
|
||||||
func(config *params.NodeConfig) {
|
func(config *params.NodeConfig) {
|
||||||
log.Info("CompleteTransactions()")
|
log.Info("CompleteTransactions()")
|
||||||
ids := []common.QueuedTxID{"id1", "id2"}
|
ids := []string{"id1", "id2"}
|
||||||
s.T().Logf("CompleteTransactions(), result: %v", s.Backend.CompleteTransactions(ids, "password"))
|
s.T().Logf("CompleteTransactions(), result: %v", s.Backend.CompleteTransactions(ids, "password"))
|
||||||
progress <- struct{}{}
|
progress <- struct{}{}
|
||||||
},
|
},
|
||||||
func(config *params.NodeConfig) {
|
func(config *params.NodeConfig) {
|
||||||
log.Info("DiscardTransactions()")
|
log.Info("DiscardTransactions()")
|
||||||
ids := []common.QueuedTxID{"id1", "id2"}
|
ids := []string{"id1", "id2"}
|
||||||
s.T().Logf("DiscardTransactions(), result: %v", s.Backend.DiscardTransactions(ids))
|
s.T().Logf("DiscardTransactions(), result: %v", s.Backend.DiscardTransactions(ids))
|
||||||
progress <- struct{}{}
|
progress <- struct{}{}
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,7 +10,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
gethcommon "github.com/ethereum/go-ethereum/common"
|
gethcommon "github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/status-im/status-go/geth/common"
|
|
||||||
"github.com/status-im/status-go/geth/jail"
|
"github.com/status-im/status-go/geth/jail"
|
||||||
"github.com/status-im/status-go/geth/params"
|
"github.com/status-im/status-go/geth/params"
|
||||||
"github.com/status-im/status-go/geth/signal"
|
"github.com/status-im/status-go/geth/signal"
|
||||||
|
@ -135,7 +134,7 @@ func (s *JailRPCTestSuite) TestContractDeployment() {
|
||||||
|
|
||||||
txID := event["id"].(string)
|
txID := event["id"].(string)
|
||||||
var txErr error
|
var txErr error
|
||||||
txHash, txErr = s.Backend.CompleteTransaction(common.QueuedTxID(txID), TestConfig.Account1.Password)
|
txHash, txErr = s.Backend.CompleteTransaction(txID, TestConfig.Account1.Password)
|
||||||
if s.NoError(txErr, event["id"]) {
|
if s.NoError(txErr, event["id"]) {
|
||||||
s.T().Logf("contract transaction complete, URL: %s", "https://ropsten.etherscan.io/tx/"+txHash.Hex())
|
s.T().Logf("contract transaction complete, URL: %s", "https://ropsten.etherscan.io/tx/"+txHash.Hex())
|
||||||
}
|
}
|
||||||
|
@ -291,7 +290,7 @@ func (s *JailRPCTestSuite) TestJailVMPersistence() {
|
||||||
|
|
||||||
//var txHash common.Hash
|
//var txHash common.Hash
|
||||||
txID := event["id"].(string)
|
txID := event["id"].(string)
|
||||||
txHash, e := s.Backend.CompleteTransaction(common.QueuedTxID(txID), TestConfig.Account1.Password)
|
txHash, e := s.Backend.CompleteTransaction(txID, TestConfig.Account1.Password)
|
||||||
s.NoError(e, "cannot complete queued transaction[%v]: %v", event["id"], e)
|
s.NoError(e, "cannot complete queued transaction[%v]: %v", event["id"], e)
|
||||||
|
|
||||||
s.T().Logf("Transaction complete: https://ropsten.etherscan.io/tx/%s", txHash.Hex())
|
s.T().Logf("Transaction complete: https://ropsten.etherscan.io/tx/%s", txHash.Hex())
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/les"
|
"github.com/ethereum/go-ethereum/les"
|
||||||
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
|
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
|
||||||
"github.com/status-im/status-go/geth/api"
|
"github.com/status-im/status-go/geth/api"
|
||||||
"github.com/status-im/status-go/geth/common"
|
|
||||||
|
|
||||||
"github.com/status-im/status-go/geth/node"
|
"github.com/status-im/status-go/geth/node"
|
||||||
"github.com/status-im/status-go/geth/signal"
|
"github.com/status-im/status-go/geth/signal"
|
||||||
|
@ -142,10 +141,10 @@ func (s *BackendTestSuite) TxQueueManager() *transactions.Manager {
|
||||||
func importTestAccounts(keyStoreDir string) (err error) {
|
func importTestAccounts(keyStoreDir string) (err error) {
|
||||||
logger.Debug("Import accounts to", "dir", keyStoreDir)
|
logger.Debug("Import accounts to", "dir", keyStoreDir)
|
||||||
|
|
||||||
err = common.ImportTestAccount(keyStoreDir, GetAccount1PKFile())
|
err = ImportTestAccount(keyStoreDir, GetAccount1PKFile())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return common.ImportTestAccount(keyStoreDir, GetAccount2PKFile())
|
return ImportTestAccount(keyStoreDir, GetAccount2PKFile())
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,17 +15,15 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/status-im/status-go/geth/account"
|
"github.com/status-im/status-go/geth/account"
|
||||||
"github.com/status-im/status-go/geth/common"
|
|
||||||
"github.com/status-im/status-go/geth/params"
|
"github.com/status-im/status-go/geth/params"
|
||||||
"github.com/status-im/status-go/geth/signal"
|
"github.com/status-im/status-go/geth/signal"
|
||||||
"github.com/status-im/status-go/geth/transactions"
|
"github.com/status-im/status-go/geth/transactions"
|
||||||
"github.com/status-im/status-go/geth/transactions/queue"
|
|
||||||
e2e "github.com/status-im/status-go/t/e2e"
|
e2e "github.com/status-im/status-go/t/e2e"
|
||||||
. "github.com/status-im/status-go/t/utils"
|
. "github.com/status-im/status-go/t/utils"
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
)
|
)
|
||||||
|
|
||||||
type initFunc func([]byte, *common.SendTxArgs)
|
type initFunc func([]byte, *transactions.SendTxArgs)
|
||||||
|
|
||||||
func TestTransactionsTestSuite(t *testing.T) {
|
func TestTransactionsTestSuite(t *testing.T) {
|
||||||
suite.Run(t, new(TransactionsTestSuite))
|
suite.Run(t, new(TransactionsTestSuite))
|
||||||
|
@ -55,7 +53,7 @@ func (s *TransactionsTestSuite) TestCallRPCSendTransaction() {
|
||||||
if sg.Type == transactions.EventTransactionQueued {
|
if sg.Type == transactions.EventTransactionQueued {
|
||||||
event := sg.Event.(map[string]interface{})
|
event := sg.Event.(map[string]interface{})
|
||||||
txID := event["id"].(string)
|
txID := event["id"].(string)
|
||||||
txHash, err = s.Backend.CompleteTransaction(common.QueuedTxID(txID), TestConfig.Account1.Password)
|
txHash, err = s.Backend.CompleteTransaction(string(txID), TestConfig.Account1.Password)
|
||||||
s.NoError(err, "cannot complete queued transaction %s", txID)
|
s.NoError(err, "cannot complete queued transaction %s", txID)
|
||||||
|
|
||||||
close(transactionCompleted)
|
close(transactionCompleted)
|
||||||
|
@ -109,11 +107,11 @@ func (s *TransactionsTestSuite) TestCallRPCSendTransactionUpstream() {
|
||||||
txID := event["id"].(string)
|
txID := event["id"].(string)
|
||||||
|
|
||||||
// Complete with a wrong passphrase.
|
// Complete with a wrong passphrase.
|
||||||
txHash, err = s.Backend.CompleteTransaction(common.QueuedTxID(txID), "some-invalid-passphrase")
|
txHash, err = s.Backend.CompleteTransaction(string(txID), "some-invalid-passphrase")
|
||||||
s.EqualError(err, keystore.ErrDecrypt.Error(), "should return an error as the passphrase was invalid")
|
s.EqualError(err, keystore.ErrDecrypt.Error(), "should return an error as the passphrase was invalid")
|
||||||
|
|
||||||
// Complete with a correct passphrase.
|
// Complete with a correct passphrase.
|
||||||
txHash, err = s.Backend.CompleteTransaction(common.QueuedTxID(txID), TestConfig.Account2.Password)
|
txHash, err = s.Backend.CompleteTransaction(string(txID), TestConfig.Account2.Password)
|
||||||
s.NoError(err, "cannot complete queued transaction %s", txID)
|
s.NoError(err, "cannot complete queued transaction %s", txID)
|
||||||
|
|
||||||
close(transactionCompleted)
|
close(transactionCompleted)
|
||||||
|
@ -144,7 +142,7 @@ func (s *TransactionsTestSuite) TestCallRPCSendTransactionUpstream() {
|
||||||
// TestSendContractCompat tries to send transaction using the legacy "Data"
|
// TestSendContractCompat tries to send transaction using the legacy "Data"
|
||||||
// field, which is supported for backward compatibility reasons.
|
// field, which is supported for backward compatibility reasons.
|
||||||
func (s *TransactionsTestSuite) TestSendContractTxCompat() {
|
func (s *TransactionsTestSuite) TestSendContractTxCompat() {
|
||||||
initFunc := func(byteCode []byte, args *common.SendTxArgs) {
|
initFunc := func(byteCode []byte, args *transactions.SendTxArgs) {
|
||||||
args.Data = (hexutil.Bytes)(byteCode)
|
args.Data = (hexutil.Bytes)(byteCode)
|
||||||
}
|
}
|
||||||
s.testSendContractTx(initFunc, nil, "")
|
s.testSendContractTx(initFunc, nil, "")
|
||||||
|
@ -155,7 +153,7 @@ func (s *TransactionsTestSuite) TestSendContractTxCompat() {
|
||||||
// they have different values.
|
// they have different values.
|
||||||
func (s *TransactionsTestSuite) TestSendContractTxCollision() {
|
func (s *TransactionsTestSuite) TestSendContractTxCollision() {
|
||||||
// Scenario 1: Both fields are filled and have the same value, expect success
|
// Scenario 1: Both fields are filled and have the same value, expect success
|
||||||
initFunc := func(byteCode []byte, args *common.SendTxArgs) {
|
initFunc := func(byteCode []byte, args *transactions.SendTxArgs) {
|
||||||
args.Input = (hexutil.Bytes)(byteCode)
|
args.Input = (hexutil.Bytes)(byteCode)
|
||||||
args.Data = (hexutil.Bytes)(byteCode)
|
args.Data = (hexutil.Bytes)(byteCode)
|
||||||
}
|
}
|
||||||
|
@ -171,15 +169,15 @@ func (s *TransactionsTestSuite) TestSendContractTxCollision() {
|
||||||
return inverse
|
return inverse
|
||||||
}
|
}
|
||||||
|
|
||||||
initFunc2 := func(byteCode []byte, args *common.SendTxArgs) {
|
initFunc2 := func(byteCode []byte, args *transactions.SendTxArgs) {
|
||||||
args.Input = (hexutil.Bytes)(byteCode)
|
args.Input = (hexutil.Bytes)(byteCode)
|
||||||
args.Data = (hexutil.Bytes)(inverted(byteCode))
|
args.Data = (hexutil.Bytes)(inverted(byteCode))
|
||||||
}
|
}
|
||||||
s.testSendContractTx(initFunc2, common.ErrInvalidSendTxArgs, "expected error when invalid tx args are sent")
|
s.testSendContractTx(initFunc2, transactions.ErrInvalidSendTxArgs, "expected error when invalid tx args are sent")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TransactionsTestSuite) TestSendContractTx() {
|
func (s *TransactionsTestSuite) TestSendContractTx() {
|
||||||
initFunc := func(byteCode []byte, args *common.SendTxArgs) {
|
initFunc := func(byteCode []byte, args *transactions.SendTxArgs) {
|
||||||
args.Input = (hexutil.Bytes)(byteCode)
|
args.Input = (hexutil.Bytes)(byteCode)
|
||||||
}
|
}
|
||||||
s.testSendContractTx(initFunc, nil, "")
|
s.testSendContractTx(initFunc, nil, "")
|
||||||
|
@ -210,7 +208,7 @@ func (s *TransactionsTestSuite) testSendContractTx(setInputAndDataValue initFunc
|
||||||
// the first call will fail (we are not logged in, but trying to complete tx)
|
// the first call will fail (we are not logged in, but trying to complete tx)
|
||||||
log.Info("trying to complete with no user logged in")
|
log.Info("trying to complete with no user logged in")
|
||||||
txHash, err = s.Backend.CompleteTransaction(
|
txHash, err = s.Backend.CompleteTransaction(
|
||||||
common.QueuedTxID(event["id"].(string)),
|
string(event["id"].(string)),
|
||||||
TestConfig.Account1.Password,
|
TestConfig.Account1.Password,
|
||||||
)
|
)
|
||||||
s.EqualError(
|
s.EqualError(
|
||||||
|
@ -224,12 +222,12 @@ func (s *TransactionsTestSuite) testSendContractTx(setInputAndDataValue initFunc
|
||||||
err = s.Backend.SelectAccount(sampleAddress, TestConfig.Account1.Password)
|
err = s.Backend.SelectAccount(sampleAddress, TestConfig.Account1.Password)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
txHash, err = s.Backend.CompleteTransaction(
|
txHash, err = s.Backend.CompleteTransaction(
|
||||||
common.QueuedTxID(event["id"].(string)),
|
string(event["id"].(string)),
|
||||||
TestConfig.Account1.Password,
|
TestConfig.Account1.Password,
|
||||||
)
|
)
|
||||||
s.EqualError(
|
s.EqualError(
|
||||||
err,
|
err,
|
||||||
queue.ErrInvalidCompleteTxSender.Error(),
|
transactions.ErrInvalidCompleteTxSender.Error(),
|
||||||
fmt.Sprintf("expected error on queued transaction[%v] not thrown", event["id"]),
|
fmt.Sprintf("expected error on queued transaction[%v] not thrown", event["id"]),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -237,7 +235,7 @@ func (s *TransactionsTestSuite) testSendContractTx(setInputAndDataValue initFunc
|
||||||
log.Info("trying to complete with correct user, this should succeed")
|
log.Info("trying to complete with correct user, this should succeed")
|
||||||
s.NoError(s.Backend.SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password))
|
s.NoError(s.Backend.SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password))
|
||||||
txHash, err = s.Backend.CompleteTransaction(
|
txHash, err = s.Backend.CompleteTransaction(
|
||||||
common.QueuedTxID(event["id"].(string)),
|
string(event["id"].(string)),
|
||||||
TestConfig.Account1.Password,
|
TestConfig.Account1.Password,
|
||||||
)
|
)
|
||||||
s.NoError(err, fmt.Sprintf("cannot complete queued transaction[%v]", event["id"]))
|
s.NoError(err, fmt.Sprintf("cannot complete queued transaction[%v]", event["id"]))
|
||||||
|
@ -253,7 +251,7 @@ func (s *TransactionsTestSuite) testSendContractTx(setInputAndDataValue initFunc
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
|
|
||||||
gas := uint64(params.DefaultGas)
|
gas := uint64(params.DefaultGas)
|
||||||
args := common.SendTxArgs{
|
args := transactions.SendTxArgs{
|
||||||
From: account.FromAddress(TestConfig.Account1.Address),
|
From: account.FromAddress(TestConfig.Account1.Address),
|
||||||
To: nil, // marker, contract creation is expected
|
To: nil, // marker, contract creation is expected
|
||||||
//Value: (*hexutil.Big)(new(big.Int).Mul(big.NewInt(1), gethcommon.Ether)),
|
//Value: (*hexutil.Big)(new(big.Int).Mul(big.NewInt(1), gethcommon.Ether)),
|
||||||
|
@ -306,7 +304,7 @@ func (s *TransactionsTestSuite) TestSendEther() {
|
||||||
// the first call will fail (we are not logged in, but trying to complete tx)
|
// the first call will fail (we are not logged in, but trying to complete tx)
|
||||||
log.Info("trying to complete with no user logged in")
|
log.Info("trying to complete with no user logged in")
|
||||||
txHash, err = s.Backend.CompleteTransaction(
|
txHash, err = s.Backend.CompleteTransaction(
|
||||||
common.QueuedTxID(event["id"].(string)),
|
string(event["id"].(string)),
|
||||||
TestConfig.Account1.Password,
|
TestConfig.Account1.Password,
|
||||||
)
|
)
|
||||||
s.EqualError(
|
s.EqualError(
|
||||||
|
@ -320,10 +318,10 @@ func (s *TransactionsTestSuite) TestSendEther() {
|
||||||
err = s.Backend.SelectAccount(sampleAddress, TestConfig.Account1.Password)
|
err = s.Backend.SelectAccount(sampleAddress, TestConfig.Account1.Password)
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
txHash, err = s.Backend.CompleteTransaction(
|
txHash, err = s.Backend.CompleteTransaction(
|
||||||
common.QueuedTxID(event["id"].(string)), TestConfig.Account1.Password)
|
string(event["id"].(string)), TestConfig.Account1.Password)
|
||||||
s.EqualError(
|
s.EqualError(
|
||||||
err,
|
err,
|
||||||
queue.ErrInvalidCompleteTxSender.Error(),
|
transactions.ErrInvalidCompleteTxSender.Error(),
|
||||||
fmt.Sprintf("expected error on queued transaction[%v] not thrown", event["id"]),
|
fmt.Sprintf("expected error on queued transaction[%v] not thrown", event["id"]),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -331,7 +329,7 @@ func (s *TransactionsTestSuite) TestSendEther() {
|
||||||
log.Info("trying to complete with correct user, this should succeed")
|
log.Info("trying to complete with correct user, this should succeed")
|
||||||
s.NoError(s.Backend.SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password))
|
s.NoError(s.Backend.SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password))
|
||||||
txHash, err = s.Backend.CompleteTransaction(
|
txHash, err = s.Backend.CompleteTransaction(
|
||||||
common.QueuedTxID(event["id"].(string)),
|
string(event["id"].(string)),
|
||||||
TestConfig.Account1.Password,
|
TestConfig.Account1.Password,
|
||||||
)
|
)
|
||||||
s.NoError(err, fmt.Sprintf("cannot complete queued transaction[%v]", event["id"]))
|
s.NoError(err, fmt.Sprintf("cannot complete queued transaction[%v]", event["id"]))
|
||||||
|
@ -342,7 +340,7 @@ func (s *TransactionsTestSuite) TestSendEther() {
|
||||||
})
|
})
|
||||||
|
|
||||||
// this call blocks, up until Complete Transaction is called
|
// this call blocks, up until Complete Transaction is called
|
||||||
txHashCheck, err := s.Backend.SendTransaction(context.TODO(), common.SendTxArgs{
|
txHashCheck, err := s.Backend.SendTransaction(context.TODO(), transactions.SendTxArgs{
|
||||||
From: account.FromAddress(TestConfig.Account1.Address),
|
From: account.FromAddress(TestConfig.Account1.Address),
|
||||||
To: account.ToAddress(TestConfig.Account2.Address),
|
To: account.ToAddress(TestConfig.Account2.Address),
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||||
|
@ -387,7 +385,7 @@ func (s *TransactionsTestSuite) TestSendEtherTxUpstream() {
|
||||||
log.Info("transaction queued (will be completed shortly)", "id", event["id"].(string))
|
log.Info("transaction queued (will be completed shortly)", "id", event["id"].(string))
|
||||||
|
|
||||||
txHash, err = s.Backend.CompleteTransaction(
|
txHash, err = s.Backend.CompleteTransaction(
|
||||||
common.QueuedTxID(event["id"].(string)),
|
string(event["id"].(string)),
|
||||||
TestConfig.Account1.Password,
|
TestConfig.Account1.Password,
|
||||||
)
|
)
|
||||||
s.NoError(err, "cannot complete queued transaction[%v]", event["id"])
|
s.NoError(err, "cannot complete queued transaction[%v]", event["id"])
|
||||||
|
@ -399,7 +397,7 @@ func (s *TransactionsTestSuite) TestSendEtherTxUpstream() {
|
||||||
|
|
||||||
// This call blocks, up until Complete Transaction is called.
|
// This call blocks, up until Complete Transaction is called.
|
||||||
// Explicitly not setting Gas to get it estimated.
|
// Explicitly not setting Gas to get it estimated.
|
||||||
txHashCheck, err := s.Backend.SendTransaction(context.TODO(), common.SendTxArgs{
|
txHashCheck, err := s.Backend.SendTransaction(context.TODO(), transactions.SendTxArgs{
|
||||||
From: account.FromAddress(TestConfig.Account1.Address),
|
From: account.FromAddress(TestConfig.Account1.Address),
|
||||||
To: account.ToAddress(TestConfig.Account2.Address),
|
To: account.ToAddress(TestConfig.Account2.Address),
|
||||||
GasPrice: (*hexutil.Big)(big.NewInt(28000000000)),
|
GasPrice: (*hexutil.Big)(big.NewInt(28000000000)),
|
||||||
|
@ -438,7 +436,7 @@ func (s *TransactionsTestSuite) TestDoubleCompleteQueuedTransactions() {
|
||||||
|
|
||||||
if envelope.Type == transactions.EventTransactionQueued {
|
if envelope.Type == transactions.EventTransactionQueued {
|
||||||
event := envelope.Event.(map[string]interface{})
|
event := envelope.Event.(map[string]interface{})
|
||||||
txID := common.QueuedTxID(event["id"].(string))
|
txID := string(event["id"].(string))
|
||||||
log.Info("transaction queued (will be failed and completed on the second call)", "id", txID)
|
log.Info("transaction queued (will be failed and completed on the second call)", "id", txID)
|
||||||
|
|
||||||
// try with wrong password
|
// try with wrong password
|
||||||
|
@ -472,7 +470,7 @@ func (s *TransactionsTestSuite) TestDoubleCompleteQueuedTransactions() {
|
||||||
})
|
})
|
||||||
|
|
||||||
// this call blocks, and should return on *second* attempt to CompleteTransaction (w/ the correct password)
|
// this call blocks, and should return on *second* attempt to CompleteTransaction (w/ the correct password)
|
||||||
txHashCheck, err := s.Backend.SendTransaction(context.TODO(), common.SendTxArgs{
|
txHashCheck, err := s.Backend.SendTransaction(context.TODO(), transactions.SendTxArgs{
|
||||||
From: account.FromAddress(TestConfig.Account1.Address),
|
From: account.FromAddress(TestConfig.Account1.Address),
|
||||||
To: account.ToAddress(TestConfig.Account2.Address),
|
To: account.ToAddress(TestConfig.Account2.Address),
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||||
|
@ -514,7 +512,7 @@ func (s *TransactionsTestSuite) TestDiscardQueuedTransaction() {
|
||||||
|
|
||||||
if envelope.Type == transactions.EventTransactionQueued {
|
if envelope.Type == transactions.EventTransactionQueued {
|
||||||
event := envelope.Event.(map[string]interface{})
|
event := envelope.Event.(map[string]interface{})
|
||||||
txID := common.QueuedTxID(event["id"].(string))
|
txID := string(event["id"].(string))
|
||||||
log.Info("transaction queued (will be discarded soon)", "id", txID)
|
log.Info("transaction queued (will be discarded soon)", "id", txID)
|
||||||
|
|
||||||
s.True(s.Backend.TxQueueManager().TransactionQueue().Has(txID), "txqueue should still have test tx")
|
s.True(s.Backend.TxQueueManager().TransactionQueue().Has(txID), "txqueue should still have test tx")
|
||||||
|
@ -550,7 +548,7 @@ func (s *TransactionsTestSuite) TestDiscardQueuedTransaction() {
|
||||||
})
|
})
|
||||||
|
|
||||||
// this call blocks, and should return when DiscardQueuedTransaction() is called
|
// this call blocks, and should return when DiscardQueuedTransaction() is called
|
||||||
txHashCheck, err := s.Backend.SendTransaction(context.TODO(), common.SendTxArgs{
|
txHashCheck, err := s.Backend.SendTransaction(context.TODO(), transactions.SendTxArgs{
|
||||||
From: account.FromAddress(TestConfig.Account1.Address),
|
From: account.FromAddress(TestConfig.Account1.Address),
|
||||||
To: account.ToAddress(TestConfig.Account2.Address),
|
To: account.ToAddress(TestConfig.Account2.Address),
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||||
|
@ -594,7 +592,7 @@ func (s *TransactionsTestSuite) TestDiscardMultipleQueuedTransactions() {
|
||||||
s.NoError(s.Backend.SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password))
|
s.NoError(s.Backend.SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password))
|
||||||
|
|
||||||
testTxCount := 3
|
testTxCount := 3
|
||||||
txIDs := make(chan common.QueuedTxID, testTxCount)
|
txIDs := make(chan string, testTxCount)
|
||||||
allTestTxDiscarded := make(chan struct{})
|
allTestTxDiscarded := make(chan struct{})
|
||||||
|
|
||||||
// replace transaction notification handler
|
// replace transaction notification handler
|
||||||
|
@ -605,7 +603,7 @@ func (s *TransactionsTestSuite) TestDiscardMultipleQueuedTransactions() {
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
if envelope.Type == transactions.EventTransactionQueued {
|
if envelope.Type == transactions.EventTransactionQueued {
|
||||||
event := envelope.Event.(map[string]interface{})
|
event := envelope.Event.(map[string]interface{})
|
||||||
txID := common.QueuedTxID(event["id"].(string))
|
txID := string(event["id"].(string))
|
||||||
log.Info("transaction queued (will be discarded soon)", "id", txID)
|
log.Info("transaction queued (will be discarded soon)", "id", txID)
|
||||||
|
|
||||||
s.True(s.Backend.TxQueueManager().TransactionQueue().Has(txID),
|
s.True(s.Backend.TxQueueManager().TransactionQueue().Has(txID),
|
||||||
|
@ -635,7 +633,7 @@ func (s *TransactionsTestSuite) TestDiscardMultipleQueuedTransactions() {
|
||||||
|
|
||||||
// this call blocks, and should return when DiscardQueuedTransaction() for a given tx id is called
|
// this call blocks, and should return when DiscardQueuedTransaction() for a given tx id is called
|
||||||
sendTx := func() {
|
sendTx := func() {
|
||||||
txHashCheck, err := s.Backend.SendTransaction(context.TODO(), common.SendTxArgs{
|
txHashCheck, err := s.Backend.SendTransaction(context.TODO(), transactions.SendTxArgs{
|
||||||
From: account.FromAddress(TestConfig.Account1.Address),
|
From: account.FromAddress(TestConfig.Account1.Address),
|
||||||
To: account.ToAddress(TestConfig.Account2.Address),
|
To: account.ToAddress(TestConfig.Account2.Address),
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||||
|
@ -647,13 +645,13 @@ func (s *TransactionsTestSuite) TestDiscardMultipleQueuedTransactions() {
|
||||||
txQueueManager := s.Backend.TxQueueManager()
|
txQueueManager := s.Backend.TxQueueManager()
|
||||||
|
|
||||||
// wait for transactions, and discard immediately
|
// wait for transactions, and discard immediately
|
||||||
discardTxs := func(txIDs []common.QueuedTxID) {
|
discardTxs := func(txIDs []string) {
|
||||||
txIDs = append(txIDs, "invalid-tx-id")
|
txIDs = append(txIDs, "invalid-tx-id")
|
||||||
|
|
||||||
// discard
|
// discard
|
||||||
discardResults := s.Backend.DiscardTransactions(txIDs)
|
discardResults := s.Backend.DiscardTransactions(txIDs)
|
||||||
require.Len(discardResults, 1, "cannot discard txs: %v", discardResults)
|
require.Len(discardResults, 1, "cannot discard txs: %v", discardResults)
|
||||||
require.Error(discardResults["invalid-tx-id"].Error, "transaction hash not found", "cannot discard txs: %v", discardResults)
|
require.Error(discardResults["invalid-tx-id"], "transaction hash not found", "cannot discard txs: %v", discardResults)
|
||||||
|
|
||||||
// try completing discarded transaction
|
// try completing discarded transaction
|
||||||
completeResults := s.Backend.CompleteTransactions(txIDs, TestConfig.Account1.Password)
|
completeResults := s.Backend.CompleteTransactions(txIDs, TestConfig.Account1.Password)
|
||||||
|
@ -675,7 +673,7 @@ func (s *TransactionsTestSuite) TestDiscardMultipleQueuedTransactions() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
ids := make([]common.QueuedTxID, testTxCount)
|
ids := make([]string, testTxCount)
|
||||||
for i := 0; i < testTxCount; i++ {
|
for i := 0; i < testTxCount; i++ {
|
||||||
ids[i] = <-txIDs
|
ids[i] = <-txIDs
|
||||||
}
|
}
|
||||||
|
@ -710,7 +708,7 @@ func (s *TransactionsTestSuite) TestNonExistentQueuedTransactions() {
|
||||||
// try completing non-existing transaction
|
// try completing non-existing transaction
|
||||||
_, err := s.Backend.CompleteTransaction("some-bad-transaction-id", TestConfig.Account1.Password)
|
_, err := s.Backend.CompleteTransaction("some-bad-transaction-id", TestConfig.Account1.Password)
|
||||||
s.Error(err, "error expected and not received")
|
s.Error(err, "error expected and not received")
|
||||||
s.EqualError(err, queue.ErrQueuedTxIDNotFound.Error())
|
s.EqualError(err, transactions.ErrQueuedTxIDNotFound.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TransactionsTestSuite) TestEvictionOfQueuedTransactions() {
|
func (s *TransactionsTestSuite) TestEvictionOfQueuedTransactions() {
|
||||||
|
@ -719,7 +717,7 @@ func (s *TransactionsTestSuite) TestEvictionOfQueuedTransactions() {
|
||||||
|
|
||||||
var m sync.Mutex
|
var m sync.Mutex
|
||||||
txCount := 0
|
txCount := 0
|
||||||
txIDs := [queue.DefaultTxQueueCap + 5 + 10]common.QueuedTxID{}
|
txIDs := [transactions.DefaultTxQueueCap + 5 + 10]string{}
|
||||||
|
|
||||||
signal.SetDefaultNodeNotificationHandler(func(rawSignal string) {
|
signal.SetDefaultNodeNotificationHandler(func(rawSignal string) {
|
||||||
var sg signal.Envelope
|
var sg signal.Envelope
|
||||||
|
@ -730,7 +728,7 @@ func (s *TransactionsTestSuite) TestEvictionOfQueuedTransactions() {
|
||||||
event := sg.Event.(map[string]interface{})
|
event := sg.Event.(map[string]interface{})
|
||||||
txID := event["id"].(string)
|
txID := event["id"].(string)
|
||||||
m.Lock()
|
m.Lock()
|
||||||
txIDs[txCount] = common.QueuedTxID(txID)
|
txIDs[txCount] = string(txID)
|
||||||
txCount++
|
txCount++
|
||||||
m.Unlock()
|
m.Unlock()
|
||||||
}
|
}
|
||||||
|
@ -746,17 +744,17 @@ func (s *TransactionsTestSuite) TestEvictionOfQueuedTransactions() {
|
||||||
s.Zero(txQueue.Count(), "transaction count should be zero")
|
s.Zero(txQueue.Count(), "transaction count should be zero")
|
||||||
|
|
||||||
for j := 0; j < 10; j++ {
|
for j := 0; j < 10; j++ {
|
||||||
go s.Backend.SendTransaction(context.TODO(), common.SendTxArgs{}) // nolint: errcheck
|
go s.Backend.SendTransaction(context.TODO(), transactions.SendTxArgs{}) // nolint: errcheck
|
||||||
}
|
}
|
||||||
time.Sleep(2 * time.Second)
|
time.Sleep(2 * time.Second)
|
||||||
s.Equal(10, txQueue.Count(), "transaction count should be 10")
|
s.Equal(10, txQueue.Count(), "transaction count should be 10")
|
||||||
|
|
||||||
for i := 0; i < queue.DefaultTxQueueCap+5; i++ { // stress test by hitting with lots of goroutines
|
for i := 0; i < transactions.DefaultTxQueueCap+5; i++ { // stress test by hitting with lots of goroutines
|
||||||
go s.Backend.SendTransaction(context.TODO(), common.SendTxArgs{}) // nolint: errcheck
|
go s.Backend.SendTransaction(context.TODO(), transactions.SendTxArgs{}) // nolint: errcheck
|
||||||
}
|
}
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(5 * time.Second)
|
||||||
|
|
||||||
s.True(txQueue.Count() <= queue.DefaultTxQueueCap, "transaction count should be %d (or %d): got %d", queue.DefaultTxQueueCap, queue.DefaultTxQueueCap-1, txQueue.Count())
|
s.True(txQueue.Count() <= transactions.DefaultTxQueueCap, "transaction count should be %d (or %d): got %d", transactions.DefaultTxQueueCap, transactions.DefaultTxQueueCap-1, txQueue.Count())
|
||||||
|
|
||||||
m.Lock()
|
m.Lock()
|
||||||
for _, txID := range txIDs {
|
for _, txID := range txIDs {
|
||||||
|
@ -796,7 +794,7 @@ func (s *TransactionsTestSuite) setupUpstreamNode() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TransactionsTestSuite) sendConcurrentTransactions(testTxCount int) {
|
func (s *TransactionsTestSuite) sendConcurrentTransactions(testTxCount int) {
|
||||||
txIDs := make(chan common.QueuedTxID, testTxCount)
|
txIDs := make(chan string, testTxCount)
|
||||||
allTestTxCompleted := make(chan struct{})
|
allTestTxCompleted := make(chan struct{})
|
||||||
|
|
||||||
require := s.Require()
|
require := s.Require()
|
||||||
|
@ -809,7 +807,7 @@ func (s *TransactionsTestSuite) sendConcurrentTransactions(testTxCount int) {
|
||||||
|
|
||||||
if envelope.Type == transactions.EventTransactionQueued {
|
if envelope.Type == transactions.EventTransactionQueued {
|
||||||
event := envelope.Event.(map[string]interface{})
|
event := envelope.Event.(map[string]interface{})
|
||||||
txID := common.QueuedTxID(event["id"].(string))
|
txID := string(event["id"].(string))
|
||||||
log.Info("transaction queued (will be completed in a single call, once aggregated)", "id", txID)
|
log.Info("transaction queued (will be completed in a single call, once aggregated)", "id", txID)
|
||||||
|
|
||||||
txIDs <- txID
|
txIDs <- txID
|
||||||
|
@ -818,7 +816,7 @@ func (s *TransactionsTestSuite) sendConcurrentTransactions(testTxCount int) {
|
||||||
|
|
||||||
// this call blocks, and should return when DiscardQueuedTransaction() for a given tx id is called
|
// this call blocks, and should return when DiscardQueuedTransaction() for a given tx id is called
|
||||||
sendTx := func() {
|
sendTx := func() {
|
||||||
txHashCheck, err := s.Backend.SendTransaction(context.TODO(), common.SendTxArgs{
|
txHashCheck, err := s.Backend.SendTransaction(context.TODO(), transactions.SendTxArgs{
|
||||||
From: account.FromAddress(TestConfig.Account1.Address),
|
From: account.FromAddress(TestConfig.Account1.Address),
|
||||||
To: account.ToAddress(TestConfig.Account2.Address),
|
To: account.ToAddress(TestConfig.Account2.Address),
|
||||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||||
|
@ -828,7 +826,7 @@ func (s *TransactionsTestSuite) sendConcurrentTransactions(testTxCount int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for transactions, and complete them in a single call
|
// wait for transactions, and complete them in a single call
|
||||||
completeTxs := func(txIDs []common.QueuedTxID) {
|
completeTxs := func(txIDs []string) {
|
||||||
txIDs = append(txIDs, "invalid-tx-id")
|
txIDs = append(txIDs, "invalid-tx-id")
|
||||||
results := s.Backend.CompleteTransactions(txIDs, TestConfig.Account1.Password)
|
results := s.Backend.CompleteTransactions(txIDs, TestConfig.Account1.Password)
|
||||||
s.Len(results, testTxCount+1)
|
s.Len(results, testTxCount+1)
|
||||||
|
@ -856,7 +854,7 @@ func (s *TransactionsTestSuite) sendConcurrentTransactions(testTxCount int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
ids := make([]common.QueuedTxID, testTxCount)
|
ids := make([]string, testTxCount)
|
||||||
for i := 0; i < testTxCount; i++ {
|
for i := 0; i < testTxCount; i++ {
|
||||||
ids[i] = <-txIDs
|
ids[i] = <-txIDs
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,12 @@ package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
@ -16,8 +18,8 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/les"
|
"github.com/ethereum/go-ethereum/les"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/status-im/status-go/geth/common"
|
|
||||||
"github.com/status-im/status-go/geth/params"
|
"github.com/status-im/status-go/geth/params"
|
||||||
|
"github.com/status-im/status-go/static"
|
||||||
|
|
||||||
_ "github.com/stretchr/testify/suite" // required to register testify flags
|
_ "github.com/stretchr/testify/suite" // required to register testify flags
|
||||||
)
|
)
|
||||||
|
@ -32,7 +34,7 @@ var (
|
||||||
ErrTimeout = errors.New("timeout")
|
ErrTimeout = errors.New("timeout")
|
||||||
|
|
||||||
// TestConfig defines the default config usable at package-level.
|
// TestConfig defines the default config usable at package-level.
|
||||||
TestConfig *common.TestConfig
|
TestConfig *testConfig
|
||||||
|
|
||||||
// RootDir is the main application directory
|
// RootDir is the main application directory
|
||||||
RootDir string
|
RootDir string
|
||||||
|
@ -75,7 +77,7 @@ func init() {
|
||||||
// setup auxiliary directories
|
// setup auxiliary directories
|
||||||
TestDataDir = filepath.Join(RootDir, ".ethereumtest")
|
TestDataDir = filepath.Join(RootDir, ".ethereumtest")
|
||||||
|
|
||||||
TestConfig, err = common.LoadTestConfig(GetNetworkID())
|
TestConfig, err = loadTestConfig(GetNetworkID())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -282,3 +284,66 @@ func MakeTestNodeConfig(networkID int) (*params.NodeConfig, error) {
|
||||||
}
|
}
|
||||||
return nodeConfig, nil
|
return nodeConfig, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type account struct {
|
||||||
|
Address string
|
||||||
|
Password string
|
||||||
|
}
|
||||||
|
|
||||||
|
// testConfig contains shared (among different test packages) parameters
|
||||||
|
type testConfig struct {
|
||||||
|
Node struct {
|
||||||
|
SyncSeconds time.Duration
|
||||||
|
HTTPPort int
|
||||||
|
WSPort int
|
||||||
|
}
|
||||||
|
Account1 account
|
||||||
|
Account2 account
|
||||||
|
Account3 account
|
||||||
|
}
|
||||||
|
|
||||||
|
const passphraseEnvName = "ACCOUNT_PASSWORD"
|
||||||
|
|
||||||
|
// loadTestConfig loads test configuration values from disk
|
||||||
|
func loadTestConfig(networkID int) (*testConfig, error) {
|
||||||
|
var config testConfig
|
||||||
|
|
||||||
|
configData := static.MustAsset("config/test-data.json")
|
||||||
|
if err := json.Unmarshal(configData, &config); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if networkID == params.StatusChainNetworkID {
|
||||||
|
accountsData := static.MustAsset("config/status-chain-accounts.json")
|
||||||
|
if err := json.Unmarshal(accountsData, &config); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
accountsData := static.MustAsset("config/public-chain-accounts.json")
|
||||||
|
if err := json.Unmarshal(accountsData, &config); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pass := os.Getenv(passphraseEnvName)
|
||||||
|
config.Account1.Password = pass
|
||||||
|
config.Account2.Password = pass
|
||||||
|
}
|
||||||
|
|
||||||
|
return &config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImportTestAccount imports keystore from static resources, see "static/keys" folder
|
||||||
|
func ImportTestAccount(keystoreDir, accountFile string) error {
|
||||||
|
// make sure that keystore folder exists
|
||||||
|
if _, err := os.Stat(keystoreDir); os.IsNotExist(err) {
|
||||||
|
os.MkdirAll(keystoreDir, os.ModePerm) // nolint: errcheck, gas
|
||||||
|
}
|
||||||
|
|
||||||
|
dst := filepath.Join(keystoreDir, accountFile)
|
||||||
|
err := ioutil.WriteFile(dst, static.MustAsset("keys/"+accountFile), 0644)
|
||||||
|
if err != nil {
|
||||||
|
logger.Warn("cannot copy test account PK", "error", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue