[#795] : Remove geth/common package (#796)

This commit is contained in:
Adrià Cidre 2018-04-04 19:39:38 +02:00 committed by GitHub
parent 4d51f937c4
commit aa0f2ede6d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 419 additions and 540 deletions

View File

@ -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
}

View File

@ -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)

View File

@ -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.

View File

@ -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

View File

@ -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
}

View File

@ -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(),
}
}

View File

@ -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),
},

View File

@ -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]

View File

@ -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
}
}

View File

@ -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))

View File

@ -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(),
}
}

View File

@ -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),
})

View File

@ -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
}

View File

@ -1,4 +1,4 @@
package common
package transactions
import (
"testing"

View File

@ -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),
}
}

View File

@ -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
}
}

View File

@ -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)
}

View File

@ -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"`
}

View File

@ -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{}{}
},

View File

@ -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())

View File

@ -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())
}

View File

@ -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
}

View File

@ -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
}