parent
4d51f937c4
commit
aa0f2ede6d
|
@ -10,7 +10,6 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/status-im/status-go/geth/api"
|
||||
"github.com/status-im/status-go/geth/common"
|
||||
"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.
|
||||
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 {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||
gethcommon "github.com/ethereum/go-ethereum/common"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/status-im/status-go/geth/common"
|
||||
. "github.com/status-im/status-go/t/utils"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
@ -30,8 +29,8 @@ func TestVerifyAccountPassword(t *testing.T) {
|
|||
defer os.RemoveAll(emptyKeyStoreDir) //nolint: errcheck
|
||||
|
||||
// import account keys
|
||||
require.NoError(t, common.ImportTestAccount(keyStoreDir, GetAccount1PKFile()))
|
||||
require.NoError(t, common.ImportTestAccount(keyStoreDir, GetAccount2PKFile()))
|
||||
require.NoError(t, ImportTestAccount(keyStoreDir, GetAccount1PKFile()))
|
||||
require.NoError(t, ImportTestAccount(keyStoreDir, GetAccount2PKFile()))
|
||||
|
||||
account1Address := gethcommon.BytesToAddress(gethcommon.FromHex(TestConfig.Account1.Address))
|
||||
|
||||
|
@ -103,7 +102,7 @@ func TestVerifyAccountPasswordWithAccountBeforeEIP55(t *testing.T) {
|
|||
defer os.RemoveAll(keyStoreDir) //nolint: errcheck
|
||||
|
||||
// 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)
|
||||
|
||||
accManager := NewManager(nil)
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
gethcommon "github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"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/node"
|
||||
"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.
|
||||
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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// DiscardTransaction discards a given transaction from transaction queue
|
||||
func (api *StatusAPI) DiscardTransaction(id common.QueuedTxID) error {
|
||||
return api.b.txQueueManager.DiscardTransaction(id)
|
||||
func (api *StatusAPI) DiscardTransaction(id string) error {
|
||||
return api.b.DiscardTransaction(id)
|
||||
}
|
||||
|
||||
// DiscardTransactions discards given multiple transactions from transaction queue
|
||||
func (api *StatusAPI) DiscardTransactions(ids []common.QueuedTxID) map[common.QueuedTxID]common.RawDiscardTransactionResult {
|
||||
return api.b.txQueueManager.DiscardTransactions(ids)
|
||||
func (api *StatusAPI) DiscardTransactions(ids []string) map[string]error {
|
||||
return api.b.DiscardTransactions(ids)
|
||||
}
|
||||
|
||||
// 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/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/node"
|
||||
"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.
|
||||
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 {
|
||||
ctx = context.Background()
|
||||
}
|
||||
tx := common.CreateTransaction(ctx, args)
|
||||
tx := transactions.Create(ctx, args)
|
||||
if err = b.txQueueManager.QueueTransaction(tx); err != nil {
|
||||
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
|
||||
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)
|
||||
if err != nil {
|
||||
_ = 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
|
||||
func (b *StatusBackend) CompleteTransactions(ids []common.QueuedTxID, password string) map[common.QueuedTxID]common.TransactionResult {
|
||||
results := make(map[common.QueuedTxID]common.TransactionResult)
|
||||
func (b *StatusBackend) CompleteTransactions(ids []string, password string) map[string]transactions.Result {
|
||||
results := make(map[string]transactions.Result)
|
||||
for _, txID := range ids {
|
||||
txHash, txErr := b.CompleteTransaction(txID, password)
|
||||
results[txID] = common.TransactionResult{
|
||||
results[txID] = transactions.Result{
|
||||
Hash: txHash,
|
||||
Error: txErr,
|
||||
}
|
||||
|
@ -251,13 +250,21 @@ func (b *StatusBackend) CompleteTransactions(ids []common.QueuedTxID, password s
|
|||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// DiscardTransactions discards given multiple transactions from transaction queue
|
||||
func (b *StatusBackend) DiscardTransactions(ids []common.QueuedTxID) map[common.QueuedTxID]common.RawDiscardTransactionResult {
|
||||
return b.txQueueManager.DiscardTransactions(ids)
|
||||
func (b *StatusBackend) DiscardTransactions(ids []string) map[string]error {
|
||||
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
|
||||
|
|
|
@ -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"
|
||||
"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.
|
||||
|
@ -144,31 +143,3 @@ func (c Call) ParseGasPrice() *hexutil.Big {
|
|||
|
||||
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 (
|
||||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||
"github.com/status-im/status-go/geth/common"
|
||||
"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
|
||||
type SendTransactionEvent struct {
|
||||
ID string `json:"id"`
|
||||
Args common.SendTxArgs `json:"args"`
|
||||
MessageID string `json:"message_id"`
|
||||
ID string `json:"id"`
|
||||
Args SendTxArgs `json:"args"`
|
||||
MessageID string `json:"message_id"`
|
||||
}
|
||||
|
||||
// NotifyOnEnqueue returns handler that processes incoming tx queue requests
|
||||
func NotifyOnEnqueue(queuedTx *common.QueuedTx) {
|
||||
func NotifyOnEnqueue(queuedTx *QueuedTx) {
|
||||
signal.Send(signal.Envelope{
|
||||
Type: EventTransactionQueued,
|
||||
Event: SendTransactionEvent{
|
||||
ID: string(queuedTx.ID),
|
||||
ID: queuedTx.ID,
|
||||
Args: queuedTx.Args,
|
||||
MessageID: common.MessageIDFromContext(queuedTx.Context),
|
||||
MessageID: messageIDFromContext(queuedTx.Context),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// ReturnSendTransactionEvent is a JSON returned whenever transaction send is returned
|
||||
type ReturnSendTransactionEvent struct {
|
||||
ID string `json:"id"`
|
||||
Args common.SendTxArgs `json:"args"`
|
||||
MessageID string `json:"message_id"`
|
||||
ErrorMessage string `json:"error_message"`
|
||||
ErrorCode int `json:"error_code,string"`
|
||||
ID string `json:"id"`
|
||||
Args SendTxArgs `json:"args"`
|
||||
MessageID string `json:"message_id"`
|
||||
ErrorMessage string `json:"error_message"`
|
||||
ErrorCode int `json:"error_code,string"`
|
||||
}
|
||||
|
||||
// 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
|
||||
if err == nil {
|
||||
return
|
||||
|
@ -74,9 +73,9 @@ func NotifyOnReturn(queuedTx *common.QueuedTx, err error) {
|
|||
signal.Send(signal.Envelope{
|
||||
Type: EventTransactionFailed,
|
||||
Event: ReturnSendTransactionEvent{
|
||||
ID: string(queuedTx.ID),
|
||||
ID: queuedTx.ID,
|
||||
Args: queuedTx.Args,
|
||||
MessageID: common.MessageIDFromContext(queuedTx.Context),
|
||||
MessageID: messageIDFromContext(queuedTx.Context),
|
||||
ErrorMessage: err.Error(),
|
||||
ErrorCode: sendTransactionErrorCode(err),
|
||||
},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package queue
|
||||
package transactions
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
@ -9,7 +9,6 @@ import (
|
|||
gethcommon "github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/status-im/status-go/geth/account"
|
||||
"github.com/status-im/status-go/geth/common"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -41,11 +40,11 @@ type empty struct{}
|
|||
// TxQueue is capped container that holds pending transactions
|
||||
type TxQueue struct {
|
||||
mu sync.RWMutex // to guard transactions map
|
||||
transactions map[common.QueuedTxID]*common.QueuedTx
|
||||
inprogress map[common.QueuedTxID]empty
|
||||
transactions map[string]*QueuedTx
|
||||
inprogress map[string]empty
|
||||
|
||||
// TODO(dshulyak) research why eviction is done in separate goroutine
|
||||
evictableIDs chan common.QueuedTxID
|
||||
evictableIDs chan string
|
||||
enqueueTicker chan struct{}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// New creates a transaction queue.
|
||||
func New() *TxQueue {
|
||||
// newQueue creates a transaction queue.
|
||||
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")
|
||||
return &TxQueue{
|
||||
transactions: make(map[common.QueuedTxID]*common.QueuedTx),
|
||||
inprogress: make(map[common.QueuedTxID]empty),
|
||||
evictableIDs: make(chan common.QueuedTxID, DefaultTxQueueCap), // will be used to evict in FIFO
|
||||
transactions: make(map[string]*QueuedTx),
|
||||
inprogress: make(map[string]empty),
|
||||
evictableIDs: make(chan string, DefaultTxQueueCap), // will be used to evict in FIFO
|
||||
enqueueTicker: make(chan struct{}),
|
||||
log: logger,
|
||||
}
|
||||
|
@ -99,7 +98,7 @@ func (q *TxQueue) Stop() {
|
|||
|
||||
// evictionLoop frees up queue to accommodate another transaction item
|
||||
func (q *TxQueue) evictionLoop() {
|
||||
defer HaltOnPanic()
|
||||
defer haltOnPanic()
|
||||
evict := func() {
|
||||
if q.Count() >= DefaultTxQueueCap { // eviction is required to accommodate another/last item
|
||||
q.Remove(<-q.evictableIDs)
|
||||
|
@ -125,13 +124,13 @@ func (q *TxQueue) Reset() {
|
|||
q.mu.Lock()
|
||||
defer q.mu.Unlock()
|
||||
|
||||
q.transactions = make(map[common.QueuedTxID]*common.QueuedTx)
|
||||
q.evictableIDs = make(chan common.QueuedTxID, DefaultTxQueueCap)
|
||||
q.inprogress = make(map[common.QueuedTxID]empty)
|
||||
q.transactions = make(map[string]*QueuedTx)
|
||||
q.evictableIDs = make(chan string, DefaultTxQueueCap)
|
||||
q.inprogress = make(map[string]empty)
|
||||
}
|
||||
|
||||
// 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.mu.RLock()
|
||||
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
|
||||
func (q *TxQueue) Get(id common.QueuedTxID) (*common.QueuedTx, error) {
|
||||
func (q *TxQueue) Get(id string) (*QueuedTx, error) {
|
||||
q.mu.RLock()
|
||||
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.
|
||||
func (q *TxQueue) LockInprogress(id common.QueuedTxID) error {
|
||||
func (q *TxQueue) LockInprogress(id string) error {
|
||||
q.mu.Lock()
|
||||
defer q.mu.Unlock()
|
||||
if _, ok := q.transactions[id]; ok {
|
||||
|
@ -181,20 +180,20 @@ func (q *TxQueue) LockInprogress(id common.QueuedTxID) error {
|
|||
}
|
||||
|
||||
// Remove removes transaction by transaction identifier
|
||||
func (q *TxQueue) Remove(id common.QueuedTxID) {
|
||||
func (q *TxQueue) Remove(id string) {
|
||||
q.mu.Lock()
|
||||
defer q.mu.Unlock()
|
||||
q.remove(id)
|
||||
}
|
||||
|
||||
func (q *TxQueue) remove(id common.QueuedTxID) {
|
||||
func (q *TxQueue) remove(id string) {
|
||||
delete(q.transactions, id)
|
||||
delete(q.inprogress, id)
|
||||
}
|
||||
|
||||
// Done removes transaction from queue if no error or error is not transient
|
||||
// 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()
|
||||
defer q.mu.Unlock()
|
||||
tx, ok := q.transactions[id]
|
||||
|
@ -205,16 +204,16 @@ func (q *TxQueue) Done(id common.QueuedTxID, hash gethcommon.Hash, err error) er
|
|||
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)
|
||||
// hash is updated only if err is nil, but transaction is not removed from a queue
|
||||
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)
|
||||
return
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -227,7 +226,7 @@ func (q *TxQueue) Count() int {
|
|||
}
|
||||
|
||||
// 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()
|
||||
defer q.mu.RUnlock()
|
||||
_, 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 (
|
||||
"context"
|
||||
|
@ -8,7 +8,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||||
gethcommon "github.com/ethereum/go-ethereum/common"
|
||||
|
||||
"github.com/status-im/status-go/geth/common"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
|
@ -22,7 +21,7 @@ type QueueTestSuite struct {
|
|||
}
|
||||
|
||||
func (s *QueueTestSuite) SetupTest() {
|
||||
s.queue = New()
|
||||
s.queue = newQueue()
|
||||
s.queue.Start()
|
||||
}
|
||||
|
||||
|
@ -31,7 +30,7 @@ func (s *QueueTestSuite) TearDownTest() {
|
|||
}
|
||||
|
||||
func (s *QueueTestSuite) TestLockInprogressTransaction() {
|
||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{})
|
||||
tx := Create(context.Background(), SendTxArgs{})
|
||||
s.NoError(s.queue.Enqueue(tx))
|
||||
enquedTx, err := s.queue.Get(tx.ID)
|
||||
s.NoError(err)
|
||||
|
@ -43,7 +42,7 @@ func (s *QueueTestSuite) TestLockInprogressTransaction() {
|
|||
}
|
||||
|
||||
func (s *QueueTestSuite) TestGetTransaction() {
|
||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{})
|
||||
tx := Create(context.Background(), SendTxArgs{})
|
||||
s.NoError(s.queue.Enqueue(tx))
|
||||
for i := 2; i > 0; i-- {
|
||||
enquedTx, err := s.queue.Get(tx.ID)
|
||||
|
@ -53,16 +52,16 @@ func (s *QueueTestSuite) TestGetTransaction() {
|
|||
}
|
||||
|
||||
func (s *QueueTestSuite) TestAlreadyEnqueued() {
|
||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{})
|
||||
tx := Create(context.Background(), SendTxArgs{})
|
||||
s.NoError(s.queue.Enqueue(tx))
|
||||
s.Equal(ErrQueuedTxExist, s.queue.Enqueue(tx))
|
||||
// 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))
|
||||
}
|
||||
|
||||
func (s *QueueTestSuite) testDone(hash gethcommon.Hash, err error) *common.QueuedTx {
|
||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{})
|
||||
func (s *QueueTestSuite) testDone(hash gethcommon.Hash, err error) *QueuedTx {
|
||||
tx := Create(context.Background(), SendTxArgs{})
|
||||
s.NoError(s.queue.Enqueue(tx))
|
||||
s.NoError(s.queue.Done(tx.ID, hash, err))
|
||||
return tx
|
||||
|
@ -116,16 +115,16 @@ func (s QueueTestSuite) TestMultipleDone() {
|
|||
}
|
||||
|
||||
func (s *QueueTestSuite) TestEviction() {
|
||||
var first *common.QueuedTx
|
||||
var first *QueuedTx
|
||||
for i := 0; i < DefaultTxQueueCap; i++ {
|
||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{})
|
||||
tx := Create(context.Background(), SendTxArgs{})
|
||||
if first == nil {
|
||||
first = tx
|
||||
}
|
||||
s.NoError(s.queue.Enqueue(tx))
|
||||
}
|
||||
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.Equal(DefaultTxQueueCap, s.queue.Count())
|
||||
s.False(s.queue.Has(first.ID))
|
|
@ -12,9 +12,8 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"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/transactions/queue"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -36,7 +35,7 @@ type RPCClientProvider interface {
|
|||
// Manager provides means to manage internal Status Backend (injected into LES)
|
||||
type Manager struct {
|
||||
rpcClientProvider RPCClientProvider
|
||||
txQueue *queue.TxQueue
|
||||
txQueue *TxQueue
|
||||
ethTxClient EthTransactor
|
||||
notify bool
|
||||
completionTimeout time.Duration
|
||||
|
@ -52,7 +51,7 @@ type Manager struct {
|
|||
func NewManager(rpcClientProvider RPCClientProvider) *Manager {
|
||||
return &Manager{
|
||||
rpcClientProvider: rpcClientProvider,
|
||||
txQueue: queue.New(),
|
||||
txQueue: newQueue(),
|
||||
addrLock: &AddrLocker{},
|
||||
notify: true,
|
||||
completionTimeout: DefaultTxSendCompletionTimeout,
|
||||
|
@ -83,14 +82,14 @@ func (m *Manager) Stop() {
|
|||
}
|
||||
|
||||
// TransactionQueue returns a reference to the queue.
|
||||
func (m *Manager) TransactionQueue() *queue.TxQueue {
|
||||
func (m *Manager) TransactionQueue() *TxQueue {
|
||||
return m.txQueue
|
||||
}
|
||||
|
||||
// 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() {
|
||||
return common.ErrInvalidSendTxArgs
|
||||
return ErrInvalidSendTxArgs
|
||||
}
|
||||
to := "<nil>"
|
||||
if tx.Args.To != nil {
|
||||
|
@ -106,8 +105,8 @@ func (m *Manager) QueueTransaction(tx *common.QueuedTx) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) txDone(tx *common.QueuedTx, hash gethcommon.Hash, err error) {
|
||||
if err := m.txQueue.Done(tx.ID, hash, err); err == queue.ErrQueuedTxIDNotFound {
|
||||
func (m *Manager) txDone(tx *QueuedTx, hash gethcommon.Hash, err error) {
|
||||
if err := m.txQueue.Done(tx.ID, hash, err); err == ErrQueuedTxIDNotFound {
|
||||
m.log.Warn("transaction is already removed from a queue", "ID", tx.ID)
|
||||
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
|
||||
// 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)
|
||||
// now wait up until transaction is:
|
||||
// - completed (via CompleteQueuedTransaction),
|
||||
|
@ -135,7 +134,7 @@ func (m *Manager) WaitForTransaction(tx *common.QueuedTx) common.TransactionResu
|
|||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
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.
|
||||
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)
|
||||
tx, err := m.txQueue.Get(id)
|
||||
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
|
||||
func (m *Manager) validateAccount(tx *common.QueuedTx, selectedAccount *account.SelectedExtKey) error {
|
||||
func (m *Manager) validateAccount(tx *QueuedTx, selectedAccount *account.SelectedExtKey) error {
|
||||
if selectedAccount == nil {
|
||||
return account.ErrNoAccountSelected
|
||||
}
|
||||
|
||||
// make sure that only account which created the tx can complete it
|
||||
if tx.Args.From.Hex() != selectedAccount.Address.Hex() {
|
||||
m.log.Warn("queued transaction does not belong to the selected account", "err", queue.ErrInvalidCompleteTxSender)
|
||||
return queue.ErrInvalidCompleteTxSender
|
||||
m.log.Warn("queued transaction does not belong to the selected account", "err", ErrInvalidCompleteTxSender)
|
||||
return ErrInvalidCompleteTxSender
|
||||
}
|
||||
|
||||
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.addrLock.LockAddr(queuedTx.Args.From)
|
||||
var localNonce uint64
|
||||
|
@ -217,7 +216,7 @@ func (m *Manager) completeTransaction(selectedAccount *account.SelectedExtKey, q
|
|||
}
|
||||
args := queuedTx.Args
|
||||
if !args.Valid() {
|
||||
return hash, common.ErrInvalidSendTxArgs
|
||||
return hash, ErrInvalidSendTxArgs
|
||||
}
|
||||
gasPrice := (*big.Int)(args.GasPrice)
|
||||
if args.GasPrice == nil {
|
||||
|
@ -280,7 +279,7 @@ func (m *Manager) completeTransaction(selectedAccount *account.SelectedExtKey, q
|
|||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -292,28 +291,11 @@ func (m *Manager) DiscardTransaction(id common.QueuedTxID) error {
|
|||
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.
|
||||
// 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) {
|
||||
m.log.Info("SendTransactionRPCHandler called")
|
||||
rpcCall := rpc.Call{Params: args}
|
||||
tx := common.CreateTransaction(ctx, rpcCall.ToSendTxArgs())
|
||||
tx := Create(ctx, m.rpcCalltoSendTxArgs(args...))
|
||||
if err := m.QueueTransaction(tx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -323,3 +305,31 @@ func (m *Manager) SendTransactionRPCHandler(ctx context.Context, args ...interfa
|
|||
}
|
||||
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/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/rpc"
|
||||
"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"
|
||||
)
|
||||
|
||||
|
@ -75,7 +73,7 @@ var (
|
|||
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.
|
||||
// And also set the expected gas and gas price for RLP encoding the expected tx.
|
||||
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)
|
||||
}
|
||||
|
||||
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(
|
||||
uint64(*nonce),
|
||||
gethcommon.Address(*tx.Args.To),
|
||||
|
@ -152,7 +150,7 @@ func (s *TxQueueTestSuite) TestCompleteTransaction() {
|
|||
for _, testCase := range testCases {
|
||||
s.T().Run(testCase.name, func(t *testing.T) {
|
||||
s.SetupTest()
|
||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{
|
||||
tx := Create(context.Background(), SendTxArgs{
|
||||
From: account.FromAddress(TestConfig.Account1.Address),
|
||||
To: account.ToAddress(TestConfig.Account2.Address),
|
||||
Gas: testCase.gas,
|
||||
|
@ -190,7 +188,7 @@ func (s *TxQueueTestSuite) TestCompleteTransactionMultipleTimes() {
|
|||
AccountKey: &keystore.Key{PrivateKey: key},
|
||||
}
|
||||
|
||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{
|
||||
tx := Create(context.Background(), SendTxArgs{
|
||||
From: account.FromAddress(TestConfig.Account1.Address),
|
||||
To: account.ToAddress(TestConfig.Account2.Address),
|
||||
})
|
||||
|
@ -216,7 +214,7 @@ func (s *TxQueueTestSuite) TestCompleteTransactionMultipleTimes() {
|
|||
defer mu.Unlock()
|
||||
if err == nil {
|
||||
completedTx++
|
||||
} else if err == queue.ErrQueuedTxInProgress {
|
||||
} else if err == ErrQueuedTxInProgress {
|
||||
inprogressTx++
|
||||
} else {
|
||||
s.Fail("tx failed with unexpected error: ", err.Error())
|
||||
|
@ -241,7 +239,7 @@ func (s *TxQueueTestSuite) TestAccountMismatch() {
|
|||
Address: account.FromAddress(TestConfig.Account2.Address),
|
||||
}
|
||||
|
||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{
|
||||
tx := Create(context.Background(), SendTxArgs{
|
||||
From: account.FromAddress(TestConfig.Account1.Address),
|
||||
To: account.ToAddress(TestConfig.Account2.Address),
|
||||
})
|
||||
|
@ -249,7 +247,7 @@ func (s *TxQueueTestSuite) TestAccountMismatch() {
|
|||
s.NoError(s.manager.QueueTransaction(tx))
|
||||
|
||||
_, 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
|
||||
// is a recoverable error.
|
||||
|
@ -257,7 +255,7 @@ func (s *TxQueueTestSuite) TestAccountMismatch() {
|
|||
}
|
||||
|
||||
func (s *TxQueueTestSuite) TestDiscardTransaction() {
|
||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{
|
||||
tx := Create(context.Background(), SendTxArgs{
|
||||
From: account.FromAddress(TestConfig.Account1.Address),
|
||||
To: account.ToAddress(TestConfig.Account2.Address),
|
||||
})
|
||||
|
@ -276,56 +274,8 @@ func (s *TxQueueTestSuite) TestDiscardTransaction() {
|
|||
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() {
|
||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{
|
||||
tx := Create(context.Background(), SendTxArgs{
|
||||
From: account.FromAddress(TestConfig.Account1.Address),
|
||||
To: account.ToAddress(TestConfig.Account2.Address),
|
||||
})
|
||||
|
@ -351,7 +301,7 @@ func (s *TxQueueTestSuite) TestLocalNonce() {
|
|||
}
|
||||
nonce := hexutil.Uint64(0)
|
||||
for i := 0; i < txCount; i++ {
|
||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{
|
||||
tx := Create(context.Background(), SendTxArgs{
|
||||
From: account.FromAddress(TestConfig.Account1.Address),
|
||||
To: account.ToAddress(TestConfig.Account2.Address),
|
||||
})
|
||||
|
@ -367,7 +317,7 @@ func (s *TxQueueTestSuite) TestLocalNonce() {
|
|||
s.Equal(uint64(i)+1, resultNonce.(uint64))
|
||||
}
|
||||
nonce = hexutil.Uint64(5)
|
||||
tx := common.CreateTransaction(context.Background(), common.SendTxArgs{
|
||||
tx := Create(context.Background(), SendTxArgs{
|
||||
From: account.FromAddress(TestConfig.Account1.Address),
|
||||
To: account.ToAddress(TestConfig.Account2.Address),
|
||||
})
|
||||
|
@ -383,7 +333,7 @@ func (s *TxQueueTestSuite) TestLocalNonce() {
|
|||
|
||||
testErr := errors.New("test")
|
||||
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),
|
||||
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 (
|
||||
"testing"
|
|
@ -1,18 +1,16 @@
|
|||
package common
|
||||
package transactions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/ethereum/go-ethereum/log"
|
||||
"github.com/pborman/uuid"
|
||||
"github.com/status-im/status-go/static"
|
||||
"github.com/status-im/status-go/geth/signal"
|
||||
)
|
||||
|
||||
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
|
||||
|
||||
// All general log messages in this package should be routed through this logger.
|
||||
var logger = log.New("package", "status-go/geth/common")
|
||||
//ErrTxQueueRunFailure - error running transaction queue
|
||||
var ErrTxQueueRunFailure = errors.New("error running transaction queue")
|
||||
|
||||
// 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
|
||||
// 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,
|
||||
},
|
||||
})
|
||||
|
||||
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)
|
||||
func MessageIDFromContext(ctx context.Context) string {
|
||||
// messageIDFromContext returns message id from context (if exists)
|
||||
func messageIDFromContext(ctx context.Context) string {
|
||||
if ctx == nil {
|
||||
return ""
|
||||
}
|
||||
|
@ -54,10 +53,10 @@ func MessageIDFromContext(ctx context.Context) string {
|
|||
return ""
|
||||
}
|
||||
|
||||
// Fatalf is used to halt the execution.
|
||||
// fatalf is used to halt the execution.
|
||||
// When called the function prints stack end exits.
|
||||
// Failure is logged into both StdErr and StdOut.
|
||||
func Fatalf(reason interface{}, args ...interface{}) {
|
||||
func fatalf(reason interface{}, args ...interface{}) {
|
||||
// decide on output stream
|
||||
w := io.MultiWriter(os.Stdout, os.Stderr)
|
||||
outf, _ := os.Stdout.Stat() // nolint: gas
|
||||
|
@ -79,12 +78,12 @@ func Fatalf(reason interface{}, args ...interface{}) {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
// CreateTransaction returns a transaction object.
|
||||
func CreateTransaction(ctx context.Context, args SendTxArgs) *QueuedTx {
|
||||
// Create returns a transaction object.
|
||||
func Create(ctx context.Context, args SendTxArgs) *QueuedTx {
|
||||
return &QueuedTx{
|
||||
ID: QueuedTxID(uuid.New()),
|
||||
ID: uuid.New(),
|
||||
Context: ctx,
|
||||
Args: args,
|
||||
Result: make(chan TransactionResult, 1),
|
||||
Result: make(chan Result, 1),
|
||||
}
|
||||
}
|
|
@ -8,7 +8,6 @@ import (
|
|||
|
||||
"github.com/NaySoftware/go-fcm"
|
||||
"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/profiling"
|
||||
"gopkg.in/go-playground/validator.v9"
|
||||
|
@ -197,7 +196,7 @@ func Logout() *C.char {
|
|||
//CompleteTransaction instructs backend to complete sending of a given transaction
|
||||
//export CompleteTransaction
|
||||
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 := ""
|
||||
if err != nil {
|
||||
|
@ -205,7 +204,7 @@ func CompleteTransaction(id, password *C.char) *C.char {
|
|||
errString = err.Error()
|
||||
}
|
||||
|
||||
out := common.CompleteTransactionResult{
|
||||
out := CompleteTransactionResult{
|
||||
ID: C.GoString(id),
|
||||
Hash: txHash.Hex(),
|
||||
Error: errString,
|
||||
|
@ -222,30 +221,30 @@ func CompleteTransaction(id, password *C.char) *C.char {
|
|||
//CompleteTransactions instructs backend to complete sending of multiple transactions
|
||||
//export CompleteTransactions
|
||||
func CompleteTransactions(ids, password *C.char) *C.char {
|
||||
out := common.CompleteTransactionsResult{}
|
||||
out.Results = make(map[string]common.CompleteTransactionResult)
|
||||
out := CompleteTransactionsResult{}
|
||||
out.Results = make(map[string]CompleteTransactionResult)
|
||||
|
||||
parsedIDs, err := ParseJSONArray(C.GoString(ids))
|
||||
if err != nil {
|
||||
out.Results["none"] = common.CompleteTransactionResult{
|
||||
out.Results["none"] = CompleteTransactionResult{
|
||||
Error: err.Error(),
|
||||
}
|
||||
} else {
|
||||
txIDs := make([]common.QueuedTxID, len(parsedIDs))
|
||||
txIDs := make([]string, len(parsedIDs))
|
||||
for i, id := range parsedIDs {
|
||||
txIDs[i] = common.QueuedTxID(id)
|
||||
txIDs[i] = id
|
||||
}
|
||||
|
||||
results := statusAPI.CompleteTransactions(txIDs, C.GoString(password))
|
||||
for txID, result := range results {
|
||||
txResult := common.CompleteTransactionResult{
|
||||
ID: string(txID),
|
||||
txResult := CompleteTransactionResult{
|
||||
ID: txID,
|
||||
Hash: result.Hash.Hex(),
|
||||
}
|
||||
if result.Error != nil {
|
||||
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
|
||||
//export DiscardTransaction
|
||||
func DiscardTransaction(id *C.char) *C.char {
|
||||
err := statusAPI.DiscardTransaction(common.QueuedTxID(C.GoString(id)))
|
||||
err := statusAPI.DiscardTransaction(C.GoString(id))
|
||||
|
||||
errString := ""
|
||||
if err != nil {
|
||||
|
@ -269,7 +268,7 @@ func DiscardTransaction(id *C.char) *C.char {
|
|||
errString = err.Error()
|
||||
}
|
||||
|
||||
out := common.DiscardTransactionResult{
|
||||
out := DiscardTransactionResult{
|
||||
ID: C.GoString(id),
|
||||
Error: errString,
|
||||
}
|
||||
|
@ -285,29 +284,26 @@ func DiscardTransaction(id *C.char) *C.char {
|
|||
//DiscardTransactions discards given multiple transactions from transaction queue
|
||||
//export DiscardTransactions
|
||||
func DiscardTransactions(ids *C.char) *C.char {
|
||||
out := common.DiscardTransactionsResult{}
|
||||
out.Results = make(map[string]common.DiscardTransactionResult)
|
||||
out := DiscardTransactionsResult{}
|
||||
out.Results = make(map[string]DiscardTransactionResult)
|
||||
|
||||
parsedIDs, err := ParseJSONArray(C.GoString(ids))
|
||||
if err != nil {
|
||||
out.Results["none"] = common.DiscardTransactionResult{
|
||||
out.Results["none"] = DiscardTransactionResult{
|
||||
Error: err.Error(),
|
||||
}
|
||||
} else {
|
||||
txIDs := make([]common.QueuedTxID, len(parsedIDs))
|
||||
txIDs := make([]string, len(parsedIDs))
|
||||
for i, id := range parsedIDs {
|
||||
txIDs[i] = common.QueuedTxID(id)
|
||||
txIDs[i] = id
|
||||
}
|
||||
|
||||
results := statusAPI.DiscardTransactions(txIDs)
|
||||
for txID, result := range results {
|
||||
txResult := common.DiscardTransactionResult{
|
||||
ID: string(txID),
|
||||
for txID, err := range results {
|
||||
out.Results[txID] = DiscardTransactionResult{
|
||||
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/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/signal"
|
||||
"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/t/utils" //nolint: golint
|
||||
)
|
||||
|
@ -70,10 +68,10 @@ func testExportedAPI(t *testing.T, done chan struct{}) {
|
|||
|
||||
// prepare accounts
|
||||
testKeyDir := filepath.Join(testChainDir, "keystore")
|
||||
if err := common.ImportTestAccount(testKeyDir, GetAccount1PKFile()); err != nil {
|
||||
if err := ImportTestAccount(testKeyDir, GetAccount1PKFile()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := common.ImportTestAccount(testKeyDir, GetAccount2PKFile()); err != nil {
|
||||
if err := ImportTestAccount(testKeyDir, GetAccount2PKFile()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
|
@ -175,10 +173,10 @@ func testVerifyAccountPassword(t *testing.T) bool {
|
|||
}
|
||||
defer os.RemoveAll(tmpDir) // nolint: errcheck
|
||||
|
||||
if err = common.ImportTestAccount(tmpDir, GetAccount1PKFile()); err != nil {
|
||||
if err = ImportTestAccount(tmpDir, GetAccount1PKFile()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = common.ImportTestAccount(tmpDir, GetAccount2PKFile()); err != nil {
|
||||
if err = ImportTestAccount(tmpDir, GetAccount2PKFile()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
@ -798,7 +796,7 @@ func testCompleteTransaction(t *testing.T) bool {
|
|||
event := envelope.Event.(map[string]interface{})
|
||||
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))
|
||||
|
||||
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
|
||||
txCheckHash, err := statusAPI.SendTransaction(context.TODO(), common.SendTxArgs{
|
||||
txCheckHash, err := statusAPI.SendTransaction(context.TODO(), transactions.SendTxArgs{
|
||||
From: account.FromAddress(TestConfig.Account1.Address),
|
||||
To: account.ToAddress(TestConfig.Account2.Address),
|
||||
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
|
||||
sendTx := func() {
|
||||
txHashCheck, err := statusAPI.SendTransaction(context.TODO(), common.SendTxArgs{
|
||||
txHashCheck, err := statusAPI.SendTransaction(context.TODO(), transactions.SendTxArgs{
|
||||
From: account.FromAddress(TestConfig.Account1.Address),
|
||||
To: account.ToAddress(TestConfig.Account2.Address),
|
||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||
|
@ -912,14 +910,14 @@ func testCompleteMultipleQueuedTransactions(t *testing.T) bool { //nolint: gocyc
|
|||
|
||||
// complete
|
||||
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 {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
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)
|
||||
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
|
||||
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)
|
||||
return
|
||||
}
|
||||
|
@ -1010,13 +1008,13 @@ func testDiscardTransaction(t *testing.T) bool { //nolint: gocyclo
|
|||
txID = event["id"].(string)
|
||||
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)
|
||||
return
|
||||
}
|
||||
|
||||
// discard
|
||||
discardResponse := common.DiscardTransactionResult{}
|
||||
discardResponse := DiscardTransactionResult{}
|
||||
rawResponse := DiscardTransaction(C.CString(txID))
|
||||
|
||||
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
|
||||
_, err := statusAPI.CompleteTransaction(common.QueuedTxID(txID), TestConfig.Account1.Password)
|
||||
if err != queue.ErrQueuedTxIDNotFound {
|
||||
_, err := statusAPI.CompleteTransaction(string(txID), TestConfig.Account1.Password)
|
||||
if err != transactions.ErrQueuedTxIDNotFound {
|
||||
t.Error("expects tx not found, but call to CompleteTransaction succeeded")
|
||||
return
|
||||
}
|
||||
|
||||
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)
|
||||
return
|
||||
}
|
||||
|
@ -1066,7 +1064,7 @@ func testDiscardTransaction(t *testing.T) bool { //nolint: gocyclo
|
|||
})
|
||||
|
||||
// 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),
|
||||
To: account.ToAddress(TestConfig.Account2.Address),
|
||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||
|
@ -1123,7 +1121,7 @@ func testDiscardMultipleQueuedTransactions(t *testing.T) bool { //nolint: gocycl
|
|||
txID = event["id"].(string)
|
||||
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)
|
||||
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
|
||||
sendTx := func() {
|
||||
txHashCheck, err := statusAPI.SendTransaction(context.TODO(), common.SendTxArgs{
|
||||
txHashCheck, err := statusAPI.SendTransaction(context.TODO(), transactions.SendTxArgs{
|
||||
From: account.FromAddress(TestConfig.Account1.Address),
|
||||
To: account.ToAddress(TestConfig.Account2.Address),
|
||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||
|
@ -1186,21 +1184,21 @@ func testDiscardMultipleQueuedTransactions(t *testing.T) bool { //nolint: gocycl
|
|||
|
||||
// discard
|
||||
discardResultsString := DiscardTransactions(C.CString(string(updatedTxIDStrings)))
|
||||
discardResultsStruct := common.DiscardTransactionsResult{}
|
||||
discardResultsStruct := DiscardTransactionsResult{}
|
||||
if err := json.Unmarshal([]byte(C.GoString(discardResultsString)), &discardResultsStruct); err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
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)
|
||||
return
|
||||
}
|
||||
|
||||
// try completing discarded transaction
|
||||
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 {
|
||||
t.Error(err)
|
||||
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)
|
||||
return
|
||||
}
|
||||
if txResult.Error != queue.ErrQueuedTxIDNotFound.Error() {
|
||||
if txResult.Error != transactions.ErrQueuedTxIDNotFound.Error() {
|
||||
t.Errorf("invalid error for %s", txResult.Hash)
|
||||
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
|
||||
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)
|
||||
return
|
||||
}
|
||||
|
@ -1412,10 +1410,10 @@ func startTestNode(t *testing.T) <-chan struct{} {
|
|||
|
||||
// inject test accounts
|
||||
testKeyDir := filepath.Join(testDir, "keystore")
|
||||
if err := common.ImportTestAccount(testKeyDir, GetAccount1PKFile()); err != nil {
|
||||
if err := ImportTestAccount(testKeyDir, GetAccount1PKFile()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := common.ImportTestAccount(testKeyDir, GetAccount2PKFile()); err != nil {
|
||||
if err := ImportTestAccount(testKeyDir, GetAccount2PKFile()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
|
|
23
lib/types.go
23
lib/types.go
|
@ -75,3 +75,26 @@ type NotifyResult struct {
|
|||
Status bool `json:"status"`
|
||||
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/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/node"
|
||||
"github.com/status-im/status-go/geth/params"
|
||||
|
@ -148,13 +147,13 @@ func (s *APIBackendTestSuite) TestRaceConditions() {
|
|||
},
|
||||
func(config *params.NodeConfig) {
|
||||
log.Info("CompleteTransactions()")
|
||||
ids := []common.QueuedTxID{"id1", "id2"}
|
||||
ids := []string{"id1", "id2"}
|
||||
s.T().Logf("CompleteTransactions(), result: %v", s.Backend.CompleteTransactions(ids, "password"))
|
||||
progress <- struct{}{}
|
||||
},
|
||||
func(config *params.NodeConfig) {
|
||||
log.Info("DiscardTransactions()")
|
||||
ids := []common.QueuedTxID{"id1", "id2"}
|
||||
ids := []string{"id1", "id2"}
|
||||
s.T().Logf("DiscardTransactions(), result: %v", s.Backend.DiscardTransactions(ids))
|
||||
progress <- struct{}{}
|
||||
},
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"time"
|
||||
|
||||
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/params"
|
||||
"github.com/status-im/status-go/geth/signal"
|
||||
|
@ -135,7 +134,7 @@ func (s *JailRPCTestSuite) TestContractDeployment() {
|
|||
|
||||
txID := event["id"].(string)
|
||||
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"]) {
|
||||
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
|
||||
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.T().Logf("Transaction complete: https://ropsten.etherscan.io/tx/%s", txHash.Hex())
|
||||
|
|
|
@ -6,7 +6,6 @@ import (
|
|||
"github.com/ethereum/go-ethereum/les"
|
||||
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
|
||||
"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/signal"
|
||||
|
@ -142,10 +141,10 @@ func (s *BackendTestSuite) TxQueueManager() *transactions.Manager {
|
|||
func importTestAccounts(keyStoreDir string) (err error) {
|
||||
logger.Debug("Import accounts to", "dir", keyStoreDir)
|
||||
|
||||
err = common.ImportTestAccount(keyStoreDir, GetAccount1PKFile())
|
||||
err = ImportTestAccount(keyStoreDir, GetAccount1PKFile())
|
||||
if err != nil {
|
||||
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/log"
|
||||
"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/signal"
|
||||
"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"
|
||||
. "github.com/status-im/status-go/t/utils"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type initFunc func([]byte, *common.SendTxArgs)
|
||||
type initFunc func([]byte, *transactions.SendTxArgs)
|
||||
|
||||
func TestTransactionsTestSuite(t *testing.T) {
|
||||
suite.Run(t, new(TransactionsTestSuite))
|
||||
|
@ -55,7 +53,7 @@ func (s *TransactionsTestSuite) TestCallRPCSendTransaction() {
|
|||
if sg.Type == transactions.EventTransactionQueued {
|
||||
event := sg.Event.(map[string]interface{})
|
||||
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)
|
||||
|
||||
close(transactionCompleted)
|
||||
|
@ -109,11 +107,11 @@ func (s *TransactionsTestSuite) TestCallRPCSendTransactionUpstream() {
|
|||
txID := event["id"].(string)
|
||||
|
||||
// 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")
|
||||
|
||||
// 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)
|
||||
|
||||
close(transactionCompleted)
|
||||
|
@ -144,7 +142,7 @@ func (s *TransactionsTestSuite) TestCallRPCSendTransactionUpstream() {
|
|||
// TestSendContractCompat tries to send transaction using the legacy "Data"
|
||||
// field, which is supported for backward compatibility reasons.
|
||||
func (s *TransactionsTestSuite) TestSendContractTxCompat() {
|
||||
initFunc := func(byteCode []byte, args *common.SendTxArgs) {
|
||||
initFunc := func(byteCode []byte, args *transactions.SendTxArgs) {
|
||||
args.Data = (hexutil.Bytes)(byteCode)
|
||||
}
|
||||
s.testSendContractTx(initFunc, nil, "")
|
||||
|
@ -155,7 +153,7 @@ func (s *TransactionsTestSuite) TestSendContractTxCompat() {
|
|||
// they have different values.
|
||||
func (s *TransactionsTestSuite) TestSendContractTxCollision() {
|
||||
// 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.Data = (hexutil.Bytes)(byteCode)
|
||||
}
|
||||
|
@ -171,15 +169,15 @@ func (s *TransactionsTestSuite) TestSendContractTxCollision() {
|
|||
return inverse
|
||||
}
|
||||
|
||||
initFunc2 := func(byteCode []byte, args *common.SendTxArgs) {
|
||||
initFunc2 := func(byteCode []byte, args *transactions.SendTxArgs) {
|
||||
args.Input = (hexutil.Bytes)(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() {
|
||||
initFunc := func(byteCode []byte, args *common.SendTxArgs) {
|
||||
initFunc := func(byteCode []byte, args *transactions.SendTxArgs) {
|
||||
args.Input = (hexutil.Bytes)(byteCode)
|
||||
}
|
||||
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)
|
||||
log.Info("trying to complete with no user logged in")
|
||||
txHash, err = s.Backend.CompleteTransaction(
|
||||
common.QueuedTxID(event["id"].(string)),
|
||||
string(event["id"].(string)),
|
||||
TestConfig.Account1.Password,
|
||||
)
|
||||
s.EqualError(
|
||||
|
@ -224,12 +222,12 @@ func (s *TransactionsTestSuite) testSendContractTx(setInputAndDataValue initFunc
|
|||
err = s.Backend.SelectAccount(sampleAddress, TestConfig.Account1.Password)
|
||||
s.NoError(err)
|
||||
txHash, err = s.Backend.CompleteTransaction(
|
||||
common.QueuedTxID(event["id"].(string)),
|
||||
string(event["id"].(string)),
|
||||
TestConfig.Account1.Password,
|
||||
)
|
||||
s.EqualError(
|
||||
err,
|
||||
queue.ErrInvalidCompleteTxSender.Error(),
|
||||
transactions.ErrInvalidCompleteTxSender.Error(),
|
||||
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")
|
||||
s.NoError(s.Backend.SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password))
|
||||
txHash, err = s.Backend.CompleteTransaction(
|
||||
common.QueuedTxID(event["id"].(string)),
|
||||
string(event["id"].(string)),
|
||||
TestConfig.Account1.Password,
|
||||
)
|
||||
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)
|
||||
|
||||
gas := uint64(params.DefaultGas)
|
||||
args := common.SendTxArgs{
|
||||
args := transactions.SendTxArgs{
|
||||
From: account.FromAddress(TestConfig.Account1.Address),
|
||||
To: nil, // marker, contract creation is expected
|
||||
//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)
|
||||
log.Info("trying to complete with no user logged in")
|
||||
txHash, err = s.Backend.CompleteTransaction(
|
||||
common.QueuedTxID(event["id"].(string)),
|
||||
string(event["id"].(string)),
|
||||
TestConfig.Account1.Password,
|
||||
)
|
||||
s.EqualError(
|
||||
|
@ -320,10 +318,10 @@ func (s *TransactionsTestSuite) TestSendEther() {
|
|||
err = s.Backend.SelectAccount(sampleAddress, TestConfig.Account1.Password)
|
||||
s.NoError(err)
|
||||
txHash, err = s.Backend.CompleteTransaction(
|
||||
common.QueuedTxID(event["id"].(string)), TestConfig.Account1.Password)
|
||||
string(event["id"].(string)), TestConfig.Account1.Password)
|
||||
s.EqualError(
|
||||
err,
|
||||
queue.ErrInvalidCompleteTxSender.Error(),
|
||||
transactions.ErrInvalidCompleteTxSender.Error(),
|
||||
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")
|
||||
s.NoError(s.Backend.SelectAccount(TestConfig.Account1.Address, TestConfig.Account1.Password))
|
||||
txHash, err = s.Backend.CompleteTransaction(
|
||||
common.QueuedTxID(event["id"].(string)),
|
||||
string(event["id"].(string)),
|
||||
TestConfig.Account1.Password,
|
||||
)
|
||||
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
|
||||
txHashCheck, err := s.Backend.SendTransaction(context.TODO(), common.SendTxArgs{
|
||||
txHashCheck, err := s.Backend.SendTransaction(context.TODO(), transactions.SendTxArgs{
|
||||
From: account.FromAddress(TestConfig.Account1.Address),
|
||||
To: account.ToAddress(TestConfig.Account2.Address),
|
||||
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))
|
||||
|
||||
txHash, err = s.Backend.CompleteTransaction(
|
||||
common.QueuedTxID(event["id"].(string)),
|
||||
string(event["id"].(string)),
|
||||
TestConfig.Account1.Password,
|
||||
)
|
||||
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.
|
||||
// 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),
|
||||
To: account.ToAddress(TestConfig.Account2.Address),
|
||||
GasPrice: (*hexutil.Big)(big.NewInt(28000000000)),
|
||||
|
@ -438,7 +436,7 @@ func (s *TransactionsTestSuite) TestDoubleCompleteQueuedTransactions() {
|
|||
|
||||
if envelope.Type == transactions.EventTransactionQueued {
|
||||
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)
|
||||
|
||||
// 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)
|
||||
txHashCheck, err := s.Backend.SendTransaction(context.TODO(), common.SendTxArgs{
|
||||
txHashCheck, err := s.Backend.SendTransaction(context.TODO(), transactions.SendTxArgs{
|
||||
From: account.FromAddress(TestConfig.Account1.Address),
|
||||
To: account.ToAddress(TestConfig.Account2.Address),
|
||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||
|
@ -514,7 +512,7 @@ func (s *TransactionsTestSuite) TestDiscardQueuedTransaction() {
|
|||
|
||||
if envelope.Type == transactions.EventTransactionQueued {
|
||||
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)
|
||||
|
||||
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
|
||||
txHashCheck, err := s.Backend.SendTransaction(context.TODO(), common.SendTxArgs{
|
||||
txHashCheck, err := s.Backend.SendTransaction(context.TODO(), transactions.SendTxArgs{
|
||||
From: account.FromAddress(TestConfig.Account1.Address),
|
||||
To: account.ToAddress(TestConfig.Account2.Address),
|
||||
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))
|
||||
|
||||
testTxCount := 3
|
||||
txIDs := make(chan common.QueuedTxID, testTxCount)
|
||||
txIDs := make(chan string, testTxCount)
|
||||
allTestTxDiscarded := make(chan struct{})
|
||||
|
||||
// replace transaction notification handler
|
||||
|
@ -605,7 +603,7 @@ func (s *TransactionsTestSuite) TestDiscardMultipleQueuedTransactions() {
|
|||
s.NoError(err)
|
||||
if envelope.Type == transactions.EventTransactionQueued {
|
||||
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)
|
||||
|
||||
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
|
||||
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),
|
||||
To: account.ToAddress(TestConfig.Account2.Address),
|
||||
Value: (*hexutil.Big)(big.NewInt(1000000000000)),
|
||||
|
@ -647,13 +645,13 @@ func (s *TransactionsTestSuite) TestDiscardMultipleQueuedTransactions() {
|
|||
txQueueManager := s.Backend.TxQueueManager()
|
||||
|
||||
// wait for transactions, and discard immediately
|
||||
discardTxs := func(txIDs []common.QueuedTxID) {
|
||||
discardTxs := func(txIDs []string) {
|
||||
txIDs = append(txIDs, "invalid-tx-id")
|
||||
|
||||
// discard
|
||||
discardResults := s.Backend.DiscardTransactions(txIDs)
|
||||
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
|
||||
completeResults := s.Backend.CompleteTransactions(txIDs, TestConfig.Account1.Password)
|
||||
|
@ -675,7 +673,7 @@ func (s *TransactionsTestSuite) TestDiscardMultipleQueuedTransactions() {
|
|||
}
|
||||
}
|
||||
go func() {
|
||||
ids := make([]common.QueuedTxID, testTxCount)
|
||||
ids := make([]string, testTxCount)
|
||||
for i := 0; i < testTxCount; i++ {
|
||||
ids[i] = <-txIDs
|
||||
}
|
||||
|
@ -710,7 +708,7 @@ func (s *TransactionsTestSuite) TestNonExistentQueuedTransactions() {
|
|||
// try completing non-existing transaction
|
||||
_, err := s.Backend.CompleteTransaction("some-bad-transaction-id", TestConfig.Account1.Password)
|
||||
s.Error(err, "error expected and not received")
|
||||
s.EqualError(err, queue.ErrQueuedTxIDNotFound.Error())
|
||||
s.EqualError(err, transactions.ErrQueuedTxIDNotFound.Error())
|
||||
}
|
||||
|
||||
func (s *TransactionsTestSuite) TestEvictionOfQueuedTransactions() {
|
||||
|
@ -719,7 +717,7 @@ func (s *TransactionsTestSuite) TestEvictionOfQueuedTransactions() {
|
|||
|
||||
var m sync.Mutex
|
||||
txCount := 0
|
||||
txIDs := [queue.DefaultTxQueueCap + 5 + 10]common.QueuedTxID{}
|
||||
txIDs := [transactions.DefaultTxQueueCap + 5 + 10]string{}
|
||||
|
||||
signal.SetDefaultNodeNotificationHandler(func(rawSignal string) {
|
||||
var sg signal.Envelope
|
||||
|
@ -730,7 +728,7 @@ func (s *TransactionsTestSuite) TestEvictionOfQueuedTransactions() {
|
|||
event := sg.Event.(map[string]interface{})
|
||||
txID := event["id"].(string)
|
||||
m.Lock()
|
||||
txIDs[txCount] = common.QueuedTxID(txID)
|
||||
txIDs[txCount] = string(txID)
|
||||
txCount++
|
||||
m.Unlock()
|
||||
}
|
||||
|
@ -746,17 +744,17 @@ func (s *TransactionsTestSuite) TestEvictionOfQueuedTransactions() {
|
|||
s.Zero(txQueue.Count(), "transaction count should be zero")
|
||||
|
||||
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)
|
||||
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
|
||||
go s.Backend.SendTransaction(context.TODO(), common.SendTxArgs{}) // nolint: errcheck
|
||||
for i := 0; i < transactions.DefaultTxQueueCap+5; i++ { // stress test by hitting with lots of goroutines
|
||||
go s.Backend.SendTransaction(context.TODO(), transactions.SendTxArgs{}) // nolint: errcheck
|
||||
}
|
||||
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()
|
||||
for _, txID := range txIDs {
|
||||
|
@ -796,7 +794,7 @@ func (s *TransactionsTestSuite) setupUpstreamNode() {
|
|||
}
|
||||
|
||||
func (s *TransactionsTestSuite) sendConcurrentTransactions(testTxCount int) {
|
||||
txIDs := make(chan common.QueuedTxID, testTxCount)
|
||||
txIDs := make(chan string, testTxCount)
|
||||
allTestTxCompleted := make(chan struct{})
|
||||
|
||||
require := s.Require()
|
||||
|
@ -809,7 +807,7 @@ func (s *TransactionsTestSuite) sendConcurrentTransactions(testTxCount int) {
|
|||
|
||||
if envelope.Type == transactions.EventTransactionQueued {
|
||||
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)
|
||||
|
||||
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
|
||||
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),
|
||||
To: account.ToAddress(TestConfig.Account2.Address),
|
||||
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
|
||||
completeTxs := func(txIDs []common.QueuedTxID) {
|
||||
completeTxs := func(txIDs []string) {
|
||||
txIDs = append(txIDs, "invalid-tx-id")
|
||||
results := s.Backend.CompleteTransactions(txIDs, TestConfig.Account1.Password)
|
||||
s.Len(results, testTxCount+1)
|
||||
|
@ -856,7 +854,7 @@ func (s *TransactionsTestSuite) sendConcurrentTransactions(testTxCount int) {
|
|||
}
|
||||
}
|
||||
go func() {
|
||||
ids := make([]common.QueuedTxID, testTxCount)
|
||||
ids := make([]string, testTxCount)
|
||||
for i := 0; i < testTxCount; i++ {
|
||||
ids[i] = <-txIDs
|
||||
}
|
||||
|
|
|
@ -2,10 +2,12 @@ package utils
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
@ -16,8 +18,8 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/les"
|
||||
"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/static"
|
||||
|
||||
_ "github.com/stretchr/testify/suite" // required to register testify flags
|
||||
)
|
||||
|
@ -32,7 +34,7 @@ var (
|
|||
ErrTimeout = errors.New("timeout")
|
||||
|
||||
// TestConfig defines the default config usable at package-level.
|
||||
TestConfig *common.TestConfig
|
||||
TestConfig *testConfig
|
||||
|
||||
// RootDir is the main application directory
|
||||
RootDir string
|
||||
|
@ -75,7 +77,7 @@ func init() {
|
|||
// setup auxiliary directories
|
||||
TestDataDir = filepath.Join(RootDir, ".ethereumtest")
|
||||
|
||||
TestConfig, err = common.LoadTestConfig(GetNetworkID())
|
||||
TestConfig, err = loadTestConfig(GetNetworkID())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -282,3 +284,66 @@ func MakeTestNodeConfig(networkID int) (*params.NodeConfig, error) {
|
|||
}
|
||||
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