195 lines
5.7 KiB
Go
195 lines
5.7 KiB
Go
|
package node
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
|
||
|
"github.com/ethereum/go-ethereum/accounts/keystore"
|
||
|
gethcommon "github.com/ethereum/go-ethereum/common"
|
||
|
"github.com/ethereum/go-ethereum/les/status"
|
||
|
"github.com/status-im/status-go/geth/common"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
// EventTransactionQueued is triggered when send transaction request is queued
|
||
|
EventTransactionQueued = "transaction.queued"
|
||
|
|
||
|
// EventTransactionFailed is triggered when send transaction request fails
|
||
|
EventTransactionFailed = "transaction.failed"
|
||
|
|
||
|
// SendTxDefaultErrorCode is sent by default, when error is not nil, but type is unknown/unexpected.
|
||
|
SendTxDefaultErrorCode = SendTransactionDefaultErrorCode
|
||
|
)
|
||
|
|
||
|
// Send transaction response codes
|
||
|
const (
|
||
|
SendTransactionNoErrorCode = "0"
|
||
|
SendTransactionDefaultErrorCode = "1"
|
||
|
SendTransactionPasswordErrorCode = "2"
|
||
|
SendTransactionTimeoutErrorCode = "3"
|
||
|
SendTransactionDiscardedErrorCode = "4"
|
||
|
)
|
||
|
|
||
|
var txReturnCodes = map[error]string{ // deliberately strings, in case more meaningful codes are to be returned
|
||
|
nil: SendTransactionNoErrorCode,
|
||
|
keystore.ErrDecrypt: SendTransactionPasswordErrorCode,
|
||
|
status.ErrQueuedTxTimedOut: SendTransactionTimeoutErrorCode,
|
||
|
status.ErrQueuedTxDiscarded: SendTransactionDiscardedErrorCode,
|
||
|
}
|
||
|
|
||
|
// TxQueueManager provides means to manage internal Status Backend (injected into LES)
|
||
|
type TxQueueManager struct {
|
||
|
nodeManager common.NodeManager
|
||
|
accountManager common.AccountManager
|
||
|
}
|
||
|
|
||
|
func NewTxQueueManager(nodeManager common.NodeManager, accountManager common.AccountManager) *TxQueueManager {
|
||
|
return &TxQueueManager{
|
||
|
nodeManager: nodeManager,
|
||
|
accountManager: accountManager,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// CompleteTransaction instructs backend to complete sending of a given transaction
|
||
|
func (m *TxQueueManager) CompleteTransaction(id, password string) (gethcommon.Hash, error) {
|
||
|
lightEthereum, err := m.nodeManager.LightEthereumService()
|
||
|
if err != nil {
|
||
|
return gethcommon.Hash{}, err
|
||
|
}
|
||
|
|
||
|
backend := lightEthereum.StatusBackend
|
||
|
|
||
|
selectedAccount, err := m.accountManager.SelectedAccount()
|
||
|
if err != nil {
|
||
|
return gethcommon.Hash{}, err
|
||
|
}
|
||
|
|
||
|
ctx := context.Background()
|
||
|
ctx = context.WithValue(ctx, status.SelectedAccountKey, selectedAccount.Hex())
|
||
|
|
||
|
return backend.CompleteQueuedTransaction(ctx, status.QueuedTxID(id), password)
|
||
|
}
|
||
|
|
||
|
// CompleteTransactions instructs backend to complete sending of multiple transactions
|
||
|
func (m *TxQueueManager) CompleteTransactions(ids, password string) map[string]common.RawCompleteTransactionResult {
|
||
|
results := make(map[string]common.RawCompleteTransactionResult)
|
||
|
|
||
|
parsedIDs, err := common.ParseJSONArray(ids)
|
||
|
if err != nil {
|
||
|
results["none"] = common.RawCompleteTransactionResult{
|
||
|
Error: err,
|
||
|
}
|
||
|
return results
|
||
|
}
|
||
|
|
||
|
for _, txID := range parsedIDs {
|
||
|
txHash, txErr := m.CompleteTransaction(txID, password)
|
||
|
results[txID] = common.RawCompleteTransactionResult{
|
||
|
Hash: txHash,
|
||
|
Error: txErr,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return results
|
||
|
}
|
||
|
|
||
|
// DiscardTransaction discards a given transaction from transaction queue
|
||
|
func (m *TxQueueManager) DiscardTransaction(id string) error {
|
||
|
lightEthereum, err := m.nodeManager.LightEthereumService()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
backend := lightEthereum.StatusBackend
|
||
|
|
||
|
return backend.DiscardQueuedTransaction(status.QueuedTxID(id))
|
||
|
}
|
||
|
|
||
|
// DiscardTransactions discards given multiple transactions from transaction queue
|
||
|
func (m *TxQueueManager) DiscardTransactions(ids string) map[string]common.RawDiscardTransactionResult {
|
||
|
var parsedIDs []string
|
||
|
results := make(map[string]common.RawDiscardTransactionResult)
|
||
|
|
||
|
parsedIDs, err := common.ParseJSONArray(ids)
|
||
|
if err != nil {
|
||
|
results["none"] = common.RawDiscardTransactionResult{
|
||
|
Error: err,
|
||
|
}
|
||
|
return results
|
||
|
}
|
||
|
|
||
|
for _, txID := range parsedIDs {
|
||
|
err := m.DiscardTransaction(txID)
|
||
|
if err != nil {
|
||
|
results[txID] = common.RawDiscardTransactionResult{
|
||
|
Error: err,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return results
|
||
|
}
|
||
|
|
||
|
// SendTransactionEvent is a signal sent on a send transaction request
|
||
|
type SendTransactionEvent struct {
|
||
|
ID string `json:"id"`
|
||
|
Args status.SendTxArgs `json:"args"`
|
||
|
MessageID string `json:"message_id"`
|
||
|
}
|
||
|
|
||
|
// TransactionQueueHandler returns handler that processes incoming tx queue requests
|
||
|
func (m *TxQueueManager) TransactionQueueHandler() func(queuedTx status.QueuedTx) {
|
||
|
return func(queuedTx status.QueuedTx) {
|
||
|
SendSignal(SignalEnvelope{
|
||
|
Type: EventTransactionQueued,
|
||
|
Event: SendTransactionEvent{
|
||
|
ID: string(queuedTx.ID),
|
||
|
Args: queuedTx.Args,
|
||
|
MessageID: common.MessageIDFromContext(queuedTx.Context),
|
||
|
},
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ReturnSendTransactionEvent is a JSON returned whenever transaction send is returned
|
||
|
type ReturnSendTransactionEvent struct {
|
||
|
ID string `json:"id"`
|
||
|
Args status.SendTxArgs `json:"args"`
|
||
|
MessageID string `json:"message_id"`
|
||
|
ErrorMessage string `json:"error_message"`
|
||
|
ErrorCode string `json:"error_code"`
|
||
|
}
|
||
|
|
||
|
// TransactionReturnHandler returns handler that processes responses from internal tx manager
|
||
|
func (m *TxQueueManager) TransactionReturnHandler() func(queuedTx *status.QueuedTx, err error) {
|
||
|
return func(queuedTx *status.QueuedTx, err error) {
|
||
|
if err == nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// discard notifications with empty tx
|
||
|
if queuedTx == nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// error occurred, signal up to application
|
||
|
SendSignal(SignalEnvelope{
|
||
|
Type: EventTransactionFailed,
|
||
|
Event: ReturnSendTransactionEvent{
|
||
|
ID: string(queuedTx.ID),
|
||
|
Args: queuedTx.Args,
|
||
|
MessageID: common.MessageIDFromContext(queuedTx.Context),
|
||
|
ErrorMessage: err.Error(),
|
||
|
ErrorCode: m.sendTransactionErrorCode(err),
|
||
|
},
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (m *TxQueueManager) sendTransactionErrorCode(err error) string {
|
||
|
if code, ok := txReturnCodes[err]; ok {
|
||
|
return code
|
||
|
}
|
||
|
|
||
|
return SendTxDefaultErrorCode
|
||
|
}
|