Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement dcrlibwallet get tx, improve same function for wallet rpc #127

Merged
merged 10 commits into from
Jan 5, 2019
66 changes: 14 additions & 52 deletions app/walletcore/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,9 @@ package walletcore

import (
"github.com/decred/dcrd/dcrutil"
"github.com/raedahgroup/dcrlibwallet/txhelper"
)

var (
transactionDirectionNames = []string{"Sent", "Received", "Transferred", "Unclear"}
)

const (
// TransactionDirectionSent for transactions sent to external address(es) from wallet
TransactionDirectionSent TransactionDirection = iota

// TransactionDirectionReceived for transactions received from external address(es) into wallet
TransactionDirectionReceived

// TransactionDirectionTransferred for transactions sent from wallet to internal address(es)
TransactionDirectionTransferred

// TransactionDirectionUnclear for unrecognized transaction directions
TransactionDirectionUnclear
)

type TransactionDirection int8

func (direction TransactionDirection) String() string {
if direction <= TransactionDirectionUnclear {
return transactionDirectionNames[direction]
} else {
return transactionDirectionNames[TransactionDirectionUnclear]
}
}

type Balance struct {
Total dcrutil.Amount `json:"total"`
Spendable dcrutil.Amount `json:"spendable"`
Expand All @@ -56,32 +29,21 @@ type UnspentOutput struct {
}

type Transaction struct {
Hash string `json:"hash"`
Type string `json:"type"`
Amount dcrutil.Amount `json:"amount"`
Fee dcrutil.Amount `json:"fee"`
Rate dcrutil.Amount `json:"rate,omitempty"`
Direction TransactionDirection `json:"direction"`
Timestamp int64 `json:"timestamp"`
FormattedTime string `json:"formatted_time"`
Size int `json:"size"`
}

type TxInput struct {
Amount dcrutil.Amount `json:"value"`
PreviousOutpoint string `json:"previousOutpoint"`
}

type TxOutput struct {
Address string `json:"address"`
Internal bool `json:"internal"`
Value dcrutil.Amount `json:"value"`
Hash string `json:"hash"`
Type string `json:"type"`
Amount dcrutil.Amount `json:"amount"`
Fee dcrutil.Amount `json:"fee"`
FeeRate dcrutil.Amount `json:"rate,omitempty"`
Direction txhelper.TransactionDirection `json:"direction"`
Timestamp int64 `json:"timestamp"`
FormattedTime string `json:"formatted_time"`
Size int `json:"size"`
}

type TransactionDetails struct {
BlockHash string `json:"blockHash"`
Confirmations int32 `json:"confirmations"`
Inputs []*TxInput `json:"inputs"`
Outputs []*TxOutput `json:"outputs"`
BlockHeight int32 `json:"blockHeight"`
Confirmations int32 `json:"confirmations"`
Inputs []*txhelper.DecodedInput `json:"inputs"`
Outputs []*txhelper.DecodedOutput `json:"outputs"`
*Transaction
}
10 changes: 8 additions & 2 deletions app/walletcore/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,18 @@ type Wallet interface {
// AccountNumber looks up and returns an account number by the account's unique name
AccountNumber(accountName string) (uint32, error)

// GenerateReceiveAddress generates an address to receive funds into specified account
GenerateReceiveAddress(account uint32) (string, error)
// AccountNumber returns the name for an account with the provided account number
AccountName(accountNumber uint32) (string, error)

// AddressInfo checks if an address belongs to the wallet to retrieve it's account name
AddressInfo(address string) (*txhelper.AddressInfo, error)

// ValidateAddress checks if an address is valid or not
ValidateAddress(address string) (bool, error)

// GenerateReceiveAddress generates an address to receive funds into specified account
GenerateReceiveAddress(account uint32) (string, error)

// UnspentOutputs lists all unspent outputs in the specified account that sum up to `targetAmount`
// If `targetAmount` is 0, all unspent outputs in account are returned
UnspentOutputs(account uint32, targetAmount int64) ([]*UnspentOutput, error)
Expand Down
66 changes: 53 additions & 13 deletions app/walletmediums/dcrlibwallet/walletfunctions.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,22 @@ func (lib *DcrWalletLib) AccountNumber(accountName string) (uint32, error) {
return lib.walletLib.AccountNumber(accountName)
}

func (lib *DcrWalletLib) GenerateReceiveAddress(account uint32) (string, error) {
return lib.walletLib.CurrentAddress(int32(account))
func (lib *DcrWalletLib) AccountName(accountNumber uint32) (string, error) {
return lib.walletLib.AccountName(accountNumber), nil
}

func (lib *DcrWalletLib) AddressInfo(address string) (*txhelper.AddressInfo, error) {
return lib.AddressInfo(address)
}

func (lib *DcrWalletLib) ValidateAddress(address string) (bool, error) {
return lib.walletLib.IsAddressValid(address), nil
}

func (lib *DcrWalletLib) GenerateReceiveAddress(account uint32) (string, error) {
return lib.walletLib.CurrentAddress(int32(account))
}

func (lib *DcrWalletLib) UnspentOutputs(account uint32, targetAmount int64) ([]*walletcore.UnspentOutput, error) {
utxos, err := lib.walletLib.UnspentOutputs(account, requiredConfirmations, targetAmount)
if err != nil {
Expand Down Expand Up @@ -215,22 +223,21 @@ func (lib *DcrWalletLib) TransactionHistory() ([]*walletcore.Transaction, error)
return nil, err
}

txDirection := func(direction int32) walletcore.TransactionDirection {
if direction < int32(walletcore.TransactionDirectionUnclear) {
return walletcore.TransactionDirection(direction)
} else {
return walletcore.TransactionDirectionUnclear
}
}

transactions := make([]*walletcore.Transaction, len(txs))
for i, tx := range txs {
_, txFee, txSize, txFeeRate, err := txhelper.MsgTxFeeSizeRate(tx.Transaction)
if err != nil {
return nil, err
}

transactions[i] = &walletcore.Transaction{
Hash: tx.Hash,
Amount: dcrutil.Amount(tx.Amount),
Fee: dcrutil.Amount(tx.Fee),
Fee: txFee,
FeeRate: txFeeRate,
Size: txSize,
Type: tx.Type,
Direction: txDirection(tx.Direction),
Direction: tx.Direction,
Timestamp: tx.Timestamp,
FormattedTime: time.Unix(tx.Timestamp, 0).Format("Mon Jan 2, 2006 3:04PM"),
}
Expand All @@ -245,5 +252,38 @@ func (lib *DcrWalletLib) TransactionHistory() ([]*walletcore.Transaction, error)
}

func (lib *DcrWalletLib) GetTransaction(transactionHash string) (*walletcore.TransactionDetails, error) {
return nil, fmt.Errorf("not implemented")
hash, err := chainhash.NewHashFromStr(transactionHash)
if err != nil {
return nil, fmt.Errorf("invalid hash: %s\n%s", transactionHash, err.Error())
}

txInfo, err := lib.walletLib.GetTransactionRaw(hash[:])
if err != nil {
return nil, err
}

decodedTx, err := txhelper.DecodeTransaction(hash, txInfo.Transaction, lib.activeNet.Params, lib.walletLib.AddressInfo)
if err != nil {
return nil, err
}

tx := &walletcore.Transaction{
Hash: txInfo.Hash,
Amount: dcrutil.Amount(txInfo.Amount),
FormattedTime: time.Unix(txInfo.Timestamp, 0).Format("Mon Jan 2, 2006 3:04PM"),
Timestamp: txInfo.Timestamp,
Fee: dcrutil.Amount(decodedTx.Fee),
Direction: txInfo.Direction,
Type: txInfo.Type,
FeeRate: dcrutil.Amount(decodedTx.FeeRate),
Size: decodedTx.Size,
}

return &walletcore.TransactionDetails{
BlockHeight: txInfo.BlockHeight,
Confirmations: txInfo.Confirmations,
Transaction: tx,
Inputs: decodedTx.Inputs,
Outputs: decodedTx.Outputs,
}, nil
}
15 changes: 15 additions & 0 deletions app/walletmediums/dcrwalletrpc/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package dcrwalletrpc

import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)

func isRpcErrorCode(err error, code codes.Code) bool {
if err == nil {
return false
}

e, ok := status.FromError(err)
return ok && e.Code() == code
}
55 changes: 14 additions & 41 deletions app/walletmediums/dcrwalletrpc/helpers.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,15 @@
package dcrwalletrpc

import (
"bytes"
"context"
"fmt"
"math"
"time"

"github.com/decred/dcrd/chaincfg"
"github.com/decred/dcrd/chaincfg/chainhash"
"github.com/decred/dcrd/dcrutil"
"github.com/decred/dcrd/txscript"
"github.com/decred/dcrd/wire"
"github.com/decred/dcrwallet/rpc/walletrpc"
"github.com/raedahgroup/dcrlibwallet/txhelper"
"github.com/raedahgroup/godcr/app/walletcore"
)

Expand Down Expand Up @@ -79,21 +76,28 @@ func processTransaction(txDetail *walletrpc.TransactionDetails) (*walletcore.Tra
return nil, err
}

_, txFee, txSize, txFeeRate, err := txhelper.MsgTxFeeSizeRate(txDetail.Transaction)
if err != nil {
return nil, err
}

amount, direction := transactionAmountAndDirection(txDetail)

tx := &walletcore.Transaction{
Hash: hash.String(),
Amount: dcrutil.Amount(amount),
Fee: dcrutil.Amount(txDetail.Fee),
Fee: txFee,
FeeRate: txFeeRate,
Type: txDetail.TransactionType.String(),
Direction: direction,
Timestamp: txDetail.Timestamp,
FormattedTime: time.Unix(txDetail.Timestamp, 0).Format("Mon Jan 2, 2006 3:04PM"),
Size: txSize,
}
return tx, nil
}

func transactionAmountAndDirection(txDetail *walletrpc.TransactionDetails) (int64, walletcore.TransactionDirection) {
func transactionAmountAndDirection(txDetail *walletrpc.TransactionDetails) (int64, txhelper.TransactionDirection) {
var outputAmounts int64
for _, credit := range txDetail.Credits {
outputAmounts += int64(credit.Amount)
Expand All @@ -105,24 +109,24 @@ func transactionAmountAndDirection(txDetail *walletrpc.TransactionDetails) (int6
}

var amount int64
var direction walletcore.TransactionDirection
var direction txhelper.TransactionDirection

if txDetail.TransactionType == walletrpc.TransactionDetails_REGULAR {
amountDifference := outputAmounts - inputAmounts
if amountDifference < 0 && (float64(txDetail.Fee) == math.Abs(float64(amountDifference))) {
// transferred internally, the only real amount spent was transaction fee
direction = walletcore.TransactionDirectionTransferred
direction = txhelper.TransactionDirectionTransferred
amount = int64(txDetail.Fee)
} else if amountDifference > 0 {
// received
direction = walletcore.TransactionDirectionReceived
direction = txhelper.TransactionDirectionReceived

for _, credit := range txDetail.Credits {
amount += int64(credit.Amount)
}
} else {
// sent
direction = walletcore.TransactionDirectionSent
direction = txhelper.TransactionDirectionSent

for _, debit := range txDetail.Debits {
amount += int64(debit.PreviousAmount)
Expand All @@ -136,34 +140,3 @@ func transactionAmountAndDirection(txDetail *walletrpc.TransactionDetails) (int6

return amount, direction
}

func inputsFromMsgTxIn(txIn []*wire.TxIn) []*walletcore.TxInput {
txInputs := make([]*walletcore.TxInput, len(txIn))
for i, input := range txIn {
txInputs[i] = &walletcore.TxInput{
Amount: dcrutil.Amount(input.ValueIn),
PreviousOutpoint: input.PreviousOutPoint.String(),
}
}
return txInputs
}

func outputsFromMsgTxOut(txOut []*wire.TxOut, walletCredits []*walletrpc.TransactionDetails_Output, chainParams *chaincfg.Params) ([]*walletcore.TxOutput, error) {
txOutputs := make([]*walletcore.TxOutput, len(txOut))
for i, output := range txOut {
_, addrs, _, err := txscript.ExtractPkScriptAddrs(output.Version, output.PkScript, chainParams)
if err != nil {
return nil, err
}
txOutputs[i] = &walletcore.TxOutput{
Value: dcrutil.Amount(output.Value),
Address: addrs[0].String(),
}
for _, credit := range walletCredits {
if bytes.Equal(output.PkScript, credit.GetOutputScript()) {
txOutputs[i].Internal = credit.GetInternal()
}
}
}
return txOutputs, nil
}
Loading