Add type api.Amount for proper formatting of amounts in json

ethereum
Martin Boehm 2018-12-13 00:41:58 +01:00
parent d01081fd83
commit 9c142663ce
11 changed files with 216 additions and 156 deletions

View File

@ -2,7 +2,6 @@ package api
import (
"blockbook/bchain"
"blockbook/bchain/coins/eth"
"blockbook/common"
"blockbook/db"
"encoding/json"
@ -42,6 +41,17 @@ func NewAPIError(s string, public bool) error {
}
}
// Amount is datatype holding amounts
type Amount big.Int
// MarshalJSON Amount serialization
func (a *Amount) MarshalJSON() (out []byte, err error) {
if a == nil {
return []byte(`"0"`), nil
}
return []byte(`"` + (*big.Int)(a).String() + `"`), nil
}
// ScriptSig contains input script
type ScriptSig struct {
Hex string `json:"hex"`
@ -58,8 +68,7 @@ type Vin struct {
AddrDesc bchain.AddressDescriptor `json:"-"`
Addresses []string `json:"addresses"`
Searchable bool `json:"-"`
Value string `json:"value"`
ValueSat big.Int `json:"-"`
ValueSat *Amount `json:"value,omitempty"`
}
// ScriptPubKey contains output script and addresses derived from it
@ -74,8 +83,7 @@ type ScriptPubKey struct {
// Vout contains information about single transaction output
type Vout struct {
Value string `json:"value"`
ValueSat big.Int `json:"-"`
ValueSat *Amount `json:"value,omitempty"`
N int `json:"n"`
ScriptPubKey ScriptPubKey `json:"scriptPubKey"`
Spent bool `json:"spent"`
@ -86,50 +94,57 @@ type Vout struct {
// Erc20Token contains info about ERC20 token held by an address
type Erc20Token struct {
Contract string `json:"contract"`
Txs int `json:"txs"`
Name string `json:"name"`
Symbol string `json:"symbol"`
Decimals int `json:"decimals"`
Balance string `json:"balance,omitempty"`
BalanceSat string `json:"balanceSat,omitempty"`
ContractIndex string `json:"-"`
Contract string `json:"contract"`
Txs int `json:"txs"`
Name string `json:"name"`
Symbol string `json:"symbol"`
Decimals int `json:"decimals"`
BalanceSat *Amount `json:"balance,omitempty"`
ContractIndex string `json:"-"`
}
// Erc20Transfer contains info about ERC20 transfer done in a transaction
type Erc20Transfer struct {
From string `json:"from"`
To string `json:"to"`
Contract string `json:"contract"`
Name string `json:"name"`
Symbol string `json:"symbol"`
Tokens string `json:"tokens"`
From string `json:"from"`
To string `json:"to"`
Contract string `json:"contract"`
Name string `json:"name"`
Symbol string `json:"symbol"`
Decimals int `json:"decimals"`
Tokens *Amount `json:"tokens"`
}
// EthereumSpecific contains ethereum specific transaction data
type EthereumSpecific struct {
Status int `json:"status"` // 1 OK, 0 Fail, -1 pending
Nonce uint64 `json:"nonce"`
GasLimit *big.Int `json:"gaslimit"`
GasUsed *big.Int `json:"gasused"`
GasPrice *Amount `json:"gasprice"`
}
// Tx holds information about a transaction
type Tx struct {
Txid string `json:"txid"`
Version int32 `json:"version,omitempty"`
Locktime uint32 `json:"locktime,omitempty"`
Vin []Vin `json:"vin"`
Vout []Vout `json:"vout"`
Blockhash string `json:"blockhash,omitempty"`
Blockheight int `json:"blockheight"`
Confirmations uint32 `json:"confirmations"`
Time int64 `json:"time,omitempty"`
Blocktime int64 `json:"blocktime"`
ValueOut string `json:"valueOut"`
ValueOutSat big.Int `json:"-"`
Size int `json:"size,omitempty"`
ValueIn string `json:"valueIn"`
ValueInSat big.Int `json:"-"`
Fees string `json:"fees"`
FeesSat big.Int `json:"-"`
Hex string `json:"hex,omitempty"`
CoinSpecificData interface{} `json:"-"`
CoinSpecificJSON json.RawMessage `json:"-"`
Erc20Transfers []Erc20Transfer `json:"erc20transfers,omitempty"`
EthereumSpecific *eth.EthereumTxData `json:"ethereumspecific,omitempty"`
Txid string `json:"txid"`
Version int32 `json:"version,omitempty"`
Locktime uint32 `json:"locktime,omitempty"`
Vin []Vin `json:"vin"`
Vout []Vout `json:"vout"`
Blockhash string `json:"blockhash,omitempty"`
Blockheight int `json:"blockheight"`
Confirmations uint32 `json:"confirmations"`
Time int64 `json:"time,omitempty"`
Blocktime int64 `json:"blocktime"`
ValueOut string `json:"valueOut"`
ValueOutSat *Amount `json:"-"`
Size int `json:"size,omitempty"`
ValueInSat *Amount `json:"valueIn,omitempty"`
FeesSat *Amount `json:"fees,omitempty"`
Hex string `json:"hex,omitempty"`
CoinSpecificData interface{} `json:"-"`
CoinSpecificJSON json.RawMessage `json:"-"`
Erc20Transfers []Erc20Transfer `json:"erc20transfers,omitempty"`
EthereumSpecific *EthereumSpecific `json:"ethereumspecific,omitempty"`
}
// Paging contains information about paging for address, blocks and block
@ -152,16 +167,14 @@ const AddressFilterOutputs = -3
type Address struct {
Paging
AddrStr string `json:"addrStr"`
Balance string `json:"balance"`
BalanceSat string `json:"balanceSat"`
TotalReceived string `json:"totalReceived,omitempty"`
TotalSent string `json:"totalSent,omitempty"`
UnconfirmedBalance string `json:"unconfirmedBalance"`
UnconfirmedBalanceSat string `json:"unconfirmedBalanceSat"`
BalanceSat *Amount `json:"balance"`
TotalReceivedSat *Amount `json:"totalReceived,omitempty"`
TotalSentSat *Amount `json:"totalSent,omitempty"`
UnconfirmedBalanceSat *Amount `json:"unconfirmedBalance"`
UnconfirmedTxApperances int `json:"unconfirmedTxApperances"`
TxApperances int `json:"txApperances"`
Transactions []*Tx `json:"txs,omitempty"`
Txids []string `json:"transactions,omitempty"`
Transactions []*Tx `json:"transactions,omitempty"`
Txids []string `json:"txids,omitempty"`
Nonce string `json:"nonce,omitempty"`
Erc20Contract *bchain.Erc20Contract `json:"erc20contract,omitempty"`
Erc20Tokens []Erc20Token `json:"erc20tokens,omitempty"`
@ -172,8 +185,7 @@ type Address struct {
type AddressUtxo struct {
Txid string `json:"txid"`
Vout int32 `json:"vout"`
Amount string `json:"amount"`
AmountSat big.Int `json:"satoshis"`
AmountSat *Amount `json:"value"`
Height int `json:"height,omitempty"`
Confirmations int `json:"confirmations"`
}

51
api/types_test.go 100644
View File

@ -0,0 +1,51 @@
// build unittest
package api
import (
"encoding/json"
"math/big"
"reflect"
"testing"
)
func TestAmount_MarshalJSON(t *testing.T) {
type amounts struct {
A1 Amount `json:"a1"`
A2 Amount `json:"a2,omitempty"`
PA1 *Amount `json:"pa1"`
PA2 *Amount `json:"pa2,omitempty"`
}
tests := []struct {
name string
a amounts
want string
}{
{
name: "empty",
want: `{"a1":"0","a2":"0","pa1":null}`,
},
{
name: "1",
a: amounts{
A1: (Amount)(*big.NewInt(123456)),
A2: (Amount)(*big.NewInt(787901)),
PA1: (*Amount)(big.NewInt(234567)),
PA2: (*Amount)(big.NewInt(890123)),
},
want: `{"a1":"123456","a2":"787901","pa1":"234567","pa2":"890123"}`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b, err := json.Marshal(&tt.a)
if err != nil {
t.Errorf("json.Marshal() error = %v", err)
return
}
if !reflect.DeepEqual(string(b), tt.want) {
t.Errorf("json.Marshal() = %v, want %v", string(b), tt.want)
}
})
}
}

View File

@ -59,7 +59,7 @@ func (w *Worker) setSpendingTxToVout(vout *Vout, txid string, height uint32) err
} else if tsp == nil {
glog.Warning("DB inconsistency: tx ", t, ": not found in txAddresses")
} else if len(tsp.Inputs) > int(index) {
if tsp.Inputs[index].ValueSat.Cmp(&vout.ValueSat) == 0 {
if tsp.Inputs[index].ValueSat.Cmp((*big.Int)(vout.ValueSat)) == 0 {
spentTx, spentHeight, err := w.txCache.GetTransaction(t)
if err != nil {
glog.Warning("Tx ", t, ": not found")
@ -113,7 +113,7 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height uint32,
var err error
var ta *db.TxAddresses
var erc20t []Erc20Transfer
var ethSpecific *eth.EthereumTxData
var ethSpecific *EthereumSpecific
var blockhash string
if bchainTx.Confirmations > 0 {
if w.chainType == bchain.ChainBitcoinType {
@ -157,7 +157,7 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height uint32,
}
if len(otx.Vout) > int(vin.Vout) {
vout := &otx.Vout[vin.Vout]
vin.ValueSat = vout.ValueSat
vin.ValueSat = (*Amount)(&vout.ValueSat)
vin.AddrDesc, vin.Addresses, vin.Searchable, err = w.getAddressesFromVout(vout)
if err != nil {
glog.Errorf("getAddressesFromVout error %v, vout %+v", err, vout)
@ -166,8 +166,7 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height uint32,
} else {
if len(tas.Outputs) > int(vin.Vout) {
output := &tas.Outputs[vin.Vout]
vin.ValueSat = output.ValueSat
vin.Value = w.chainParser.AmountToDecimalString(&vin.ValueSat)
vin.ValueSat = (*Amount)(&output.ValueSat)
vin.AddrDesc = output.AddrDesc
vin.Addresses, vin.Searchable, err = output.Addresses(w.chainParser)
if err != nil {
@ -175,8 +174,7 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height uint32,
}
}
}
vin.Value = w.chainParser.AmountToDecimalString(&vin.ValueSat)
valInSat.Add(&valInSat, &vin.ValueSat)
valInSat.Add(&valInSat, (*big.Int)(vin.ValueSat))
}
} else if w.chainType == bchain.ChainEthereumType {
if len(bchainVin.Addresses) > 0 {
@ -194,8 +192,7 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height uint32,
bchainVout := &bchainTx.Vout[i]
vout := &vouts[i]
vout.N = i
vout.ValueSat = bchainVout.ValueSat
vout.Value = w.chainParser.AmountToDecimalString(&bchainVout.ValueSat)
vout.ValueSat = (*Amount)(&bchainVout.ValueSat)
valOutSat.Add(&valOutSat, &bchainVout.ValueSat)
vout.ScriptPubKey.Hex = bchainVout.ScriptPubKey.Hex
vout.ScriptPubKey.AddrDesc, vout.ScriptPubKey.Addresses, vout.ScriptPubKey.Searchable, err = w.getAddressesFromVout(bchainVout)
@ -242,20 +239,28 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height uint32,
Contract: e.Contract,
From: e.From,
To: e.To,
Tokens: bchain.AmountToDecimalString(&e.Tokens, erc20c.Decimals),
Decimals: erc20c.Decimals,
Tokens: (*Amount)(&e.Tokens),
Name: erc20c.Name,
Symbol: erc20c.Symbol,
}
}
ethSpecific = eth.GetEthereumTxData(bchainTx)
ethTxData := eth.GetEthereumTxData(bchainTx)
// mempool txs do not have fees yet
if ethSpecific.GasUsed != nil {
feesSat.Mul(ethSpecific.GasPriceNum, ethSpecific.GasUsed)
if ethTxData.GasUsed != nil {
feesSat.Mul(ethTxData.GasPrice, ethTxData.GasUsed)
}
if len(bchainTx.Vout) > 0 {
valInSat = bchainTx.Vout[0].ValueSat
}
valOutSat = valInSat
ethSpecific = &EthereumSpecific{
GasLimit: ethTxData.GasLimit,
GasPrice: (*Amount)(ethTxData.GasPrice),
GasUsed: ethTxData.GasUsed,
Nonce: ethTxData.Nonce,
Status: ethTxData.Status,
}
}
// for now do not return size, we would have to compute vsize of segwit transactions
// size:=len(bchainTx.Hex) / 2
@ -271,15 +276,12 @@ func (w *Worker) GetTransactionFromBchainTx(bchainTx *bchain.Tx, height uint32,
Blockheight: int(height),
Blocktime: bchainTx.Blocktime,
Confirmations: bchainTx.Confirmations,
Fees: w.chainParser.AmountToDecimalString(&feesSat),
FeesSat: feesSat,
FeesSat: (*Amount)(&feesSat),
Locktime: bchainTx.LockTime,
Time: bchainTx.Time,
Txid: bchainTx.Txid,
ValueIn: w.chainParser.AmountToDecimalString(&valInSat),
ValueInSat: valInSat,
ValueOut: w.chainParser.AmountToDecimalString(&valOutSat),
ValueOutSat: valOutSat,
ValueInSat: (*Amount)(&valInSat),
ValueOutSat: (*Amount)(&valOutSat),
Version: bchainTx.Version,
Hex: bchainTx.Hex,
Vin: vins,
@ -331,7 +333,7 @@ func (t *Tx) getAddrVoutValue(addrDesc bchain.AddressDescriptor) *big.Int {
var val big.Int
for _, vout := range t.Vout {
if bytes.Equal(vout.ScriptPubKey.AddrDesc, addrDesc) {
val.Add(&val, &vout.ValueSat)
val.Add(&val, (*big.Int)(vout.ValueSat))
}
}
return &val
@ -341,7 +343,7 @@ func (t *Tx) getAddrVinValue(addrDesc bchain.AddressDescriptor) *big.Int {
var val big.Int
for _, vin := range t.Vin {
if bytes.Equal(vin.AddrDesc, addrDesc) {
val.Add(&val, &vin.ValueSat)
val.Add(&val, (*big.Int)(vin.ValueSat))
}
}
return &val
@ -371,9 +373,8 @@ func (w *Worker) txFromTxAddress(txid string, ta *db.TxAddresses, bi *db.BlockIn
tai := &ta.Inputs[i]
vin := &vins[i]
vin.N = i
vin.ValueSat = tai.ValueSat
vin.Value = w.chainParser.AmountToDecimalString(&vin.ValueSat)
valInSat.Add(&valInSat, &vin.ValueSat)
vin.ValueSat = (*Amount)(&tai.ValueSat)
valInSat.Add(&valInSat, &tai.ValueSat)
vin.Addresses, vin.Searchable, err = tai.Addresses(w.chainParser)
if err != nil {
glog.Errorf("tai.Addresses error %v, tx %v, input %v, tai %+v", err, txid, i, tai)
@ -384,9 +385,8 @@ func (w *Worker) txFromTxAddress(txid string, ta *db.TxAddresses, bi *db.BlockIn
tao := &ta.Outputs[i]
vout := &vouts[i]
vout.N = i
vout.ValueSat = tao.ValueSat
vout.Value = w.chainParser.AmountToDecimalString(&vout.ValueSat)
valOutSat.Add(&valOutSat, &vout.ValueSat)
vout.ValueSat = (*Amount)(&tao.ValueSat)
valOutSat.Add(&valOutSat, &tao.ValueSat)
vout.ScriptPubKey.Addresses, vout.ScriptPubKey.Searchable, err = tao.Addresses(w.chainParser)
if err != nil {
glog.Errorf("tai.Addresses error %v, tx %v, output %v, tao %+v", err, txid, i, tao)
@ -403,11 +403,11 @@ func (w *Worker) txFromTxAddress(txid string, ta *db.TxAddresses, bi *db.BlockIn
Blockheight: int(ta.Height),
Blocktime: bi.Time,
Confirmations: bestheight - ta.Height + 1,
Fees: w.chainParser.AmountToDecimalString(&feesSat),
FeesSat: (*Amount)(&feesSat),
Time: bi.Time,
Txid: txid,
ValueIn: w.chainParser.AmountToDecimalString(&valInSat),
ValueOut: w.chainParser.AmountToDecimalString(&valOutSat),
ValueInSat: (*Amount)(&valInSat),
ValueOutSat: (*Amount)(&valOutSat),
Vin: vins,
Vout: vouts,
}
@ -486,14 +486,8 @@ func (w *Worker) getEthereumTypeAddressBalances(addrDesc bchain.AddressDescripto
} else {
b = nil
}
var balance, balanceSat string
if b != nil {
balance = bchain.AmountToDecimalString(b, ci.Decimals)
balanceSat = b.String()
}
erc20t[i] = Erc20Token{
Balance: balance,
BalanceSat: balanceSat,
BalanceSat: (*Amount)(b),
Contract: ci.Contract,
Name: ci.Name,
Symbol: ci.Symbol,
@ -522,15 +516,16 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option GetA
return nil, NewAPIError(fmt.Sprintf("Invalid address, %v", err), true)
}
var (
ba *db.AddrBalance
erc20t []Erc20Token
erc20c *bchain.Erc20Contract
txm []string
txs []*Tx
txids []string
pg Paging
uBalSat big.Int
totalReceived, totalSent, nonce string
ba *db.AddrBalance
erc20t []Erc20Token
erc20c *bchain.Erc20Contract
txm []string
txs []*Tx
txids []string
pg Paging
uBalSat big.Int
totalReceived, totalSent *big.Int
nonce string
)
if w.chainType == bchain.ChainEthereumType {
var n uint64
@ -646,19 +641,17 @@ func (w *Worker) GetAddress(address string, page int, txsOnPage int, option GetA
}
}
if w.chainType == bchain.ChainBitcoinType {
totalReceived = w.chainParser.AmountToDecimalString(ba.ReceivedSat())
totalSent = w.chainParser.AmountToDecimalString(&ba.SentSat)
totalReceived = ba.ReceivedSat()
totalSent = &ba.SentSat
}
r := &Address{
Paging: pg,
AddrStr: address,
Balance: w.chainParser.AmountToDecimalString(&ba.BalanceSat),
BalanceSat: ba.BalanceSat.String(),
TotalReceived: totalReceived,
TotalSent: totalSent,
BalanceSat: (*Amount)(&ba.BalanceSat),
TotalReceivedSat: (*Amount)(totalReceived),
TotalSentSat: (*Amount)(totalSent),
TxApperances: int(ba.Txs),
UnconfirmedBalance: w.chainParser.AmountToDecimalString(&uBalSat),
UnconfirmedBalanceSat: uBalSat.String(),
UnconfirmedBalanceSat: (*Amount)(&uBalSat),
UnconfirmedTxApperances: len(txm),
Transactions: txs,
Txids: txids,
@ -714,8 +707,7 @@ func (w *Worker) GetAddressUtxo(address string, onlyConfirmed bool) ([]AddressUt
r = append(r, AddressUtxo{
Txid: bchainTx.Txid,
Vout: int32(i),
AmountSat: vout.ValueSat,
Amount: w.chainParser.AmountToDecimalString(&vout.ValueSat),
AmountSat: (*Amount)(&vout.ValueSat),
})
}
}
@ -734,7 +726,7 @@ func (w *Worker) GetAddressUtxo(address string, onlyConfirmed bool) ([]AddressUt
outpoints := make([]bchain.Outpoint, 0, 8)
err = w.db.GetAddrDescTransactions(addrDesc, 0, ^uint32(0), func(txid string, vout int32, isOutput bool) error {
if isOutput {
outpoints = append(outpoints, bchain.Outpoint{txid, vout})
outpoints = append(outpoints, bchain.Outpoint{Txid: txid, Vout: vout})
}
return nil
})
@ -772,8 +764,7 @@ func (w *Worker) GetAddressUtxo(address string, onlyConfirmed bool) ([]AddressUt
r = append(r, AddressUtxo{
Txid: o.Txid,
Vout: o.Vout,
AmountSat: v,
Amount: w.chainParser.AmountToDecimalString(&v),
AmountSat: (*Amount)(&v),
Height: int(ta.Height),
Confirmations: bestheight - int(ta.Height) + 1,
})

View File

@ -414,12 +414,11 @@ func GetErc20FromTx(tx *bchain.Tx) ([]Erc20Transfer, error) {
// EthereumTxData contains ethereum specific transaction data
type EthereumTxData struct {
Status int `json:"status"` // 1 OK, 0 Fail, -1 pending
Nonce uint64 `json:"nonce"`
GasLimit *big.Int `json:"gaslimit"`
GasUsed *big.Int `json:"gasused"`
GasPrice string `json:"gasprice"`
GasPriceNum *big.Int `json:"-"`
Status int `json:"status"` // 1 OK, 0 Fail, -1 pending
Nonce uint64 `json:"nonce"`
GasLimit *big.Int `json:"gaslimit"`
GasUsed *big.Int `json:"gasused"`
GasPrice *big.Int `json:"gasprice"`
}
// GetEthereumTxData returns EthereumTxData from bchain.Tx
@ -430,8 +429,7 @@ func GetEthereumTxData(tx *bchain.Tx) *EthereumTxData {
if csd.Tx != nil {
etd.Nonce, _ = hexutil.DecodeUint64(csd.Tx.AccountNonce)
etd.GasLimit, _ = hexutil.DecodeBig(csd.Tx.GasLimit)
etd.GasPriceNum, _ = hexutil.DecodeBig(csd.Tx.GasPrice)
etd.GasPrice = bchain.AmountToDecimalString(etd.GasPriceNum, EtherAmountDecimalPoint)
etd.GasPrice, _ = hexutil.DecodeBig(csd.Tx.GasPrice)
}
if csd.Receipt != nil {
if csd.Receipt.Status == "0x1" {

View File

@ -369,11 +369,12 @@ type TemplateData struct {
func (s *PublicServer) parseTemplates() []*template.Template {
templateFuncMap := template.FuncMap{
"formatTime": formatTime,
"formatUnixTime": formatUnixTime,
"formatAmount": formatAmount,
"setTxToTemplateData": setTxToTemplateData,
"stringInSlice": stringInSlice,
"formatTime": formatTime,
"formatUnixTime": formatUnixTime,
"formatAmount": s.formatAmount,
"formatAmountWithDecimals": formatAmountWithDecimals,
"setTxToTemplateData": setTxToTemplateData,
"stringInSlice": stringInSlice,
}
t := make([]*template.Template, tplCount)
t[errorTpl] = template.Must(template.New("error").Funcs(templateFuncMap).ParseFiles("./static/templates/error.html", "./static/templates/base.html"))
@ -403,11 +404,18 @@ func formatTime(t time.Time) string {
// for now return the string as it is
// in future could be used to do coin specific formatting
func formatAmount(a string) string {
if a == "" {
func (s *PublicServer) formatAmount(a *api.Amount) string {
if a == nil {
return "0"
}
return a
return s.chainParser.AmountToDecimalString((*big.Int)(a))
}
func formatAmountWithDecimals(a *api.Amount, d int) string {
if a == nil {
return "0"
}
return bchain.AmountToDecimalString((*big.Int)(a), d)
}
// called from template to support txdetail.html functionality

View File

@ -312,7 +312,7 @@ func txToResTx(tx *api.Tx) resTx {
Script: &script,
Sequence: int64(vin.Sequence),
OutputIndex: int(vin.Vout),
Satoshis: vin.ValueSat.Int64(),
Satoshis: (*big.Int)(vin.ValueSat).Int64(),
}
if len(vin.Addresses) > 0 {
a := vin.Addresses[0]
@ -325,7 +325,7 @@ func txToResTx(tx *api.Tx) resTx {
vout := &tx.Vout[i]
script := vout.ScriptPubKey.Hex
output := txOutputs{
Satoshis: vout.ValueSat.Int64(),
Satoshis: (*big.Int)(vout.ValueSat).Int64(),
Script: &script,
}
if len(vout.ScriptPubKey.Addresses) > 0 {
@ -342,15 +342,15 @@ func txToResTx(tx *api.Tx) resTx {
}
return resTx{
BlockTimestamp: tx.Blocktime,
FeeSatoshis: tx.FeesSat.Int64(),
FeeSatoshis: (*big.Int)(tx.FeesSat).Int64(),
Hash: tx.Txid,
Height: h,
Hex: tx.Hex,
Inputs: inputs,
InputSatoshis: tx.ValueInSat.Int64(),
InputSatoshis: (*big.Int)(tx.ValueInSat).Int64(),
Locktime: int(tx.Locktime),
Outputs: outputs,
OutputSatoshis: tx.ValueOutSat.Int64(),
OutputSatoshis: (*big.Int)(tx.ValueOutSat).Int64(),
Version: int(tx.Version),
}
}
@ -407,7 +407,7 @@ func (s *SocketIoServer) getAddressHistory(addr []string, opts *addrOpts) (res r
ads[a] = hi
}
hi.InputIndexes = append(hi.InputIndexes, int(vin.N))
totalSat.Sub(&totalSat, &vin.ValueSat)
totalSat.Sub(&totalSat, (*big.Int)(vin.ValueSat))
}
}
for i := range tx.Vout {
@ -420,7 +420,7 @@ func (s *SocketIoServer) getAddressHistory(addr []string, opts *addrOpts) (res r
ads[a] = hi
}
hi.OutputIndexes = append(hi.OutputIndexes, int(vout.N))
totalSat.Add(&totalSat, &vout.ValueSat)
totalSat.Add(&totalSat, (*big.Int)(vout.ValueSat))
}
}
ahi := addressHistoryItem{}

View File

@ -91,7 +91,7 @@ func NewWebsocketServer(db *db.RocksDB, chain bchain.BlockChain, txCache *db.TxC
return s, nil
}
// allow all origins, at least for now
// allow all origins
func checkOrigin(r *http.Request) bool {
return true
}

View File

@ -1,6 +1,6 @@
{{define "specific"}}{{$cs := .CoinShortcut}}{{$addr := .Address}}{{$data := .}}
<h1>{{if $addr.Erc20Contract}}Contract {{$addr.Erc20Contract.Name}} ({{$addr.Erc20Contract.Symbol}}){{else}}Address{{end}}
<small class="text-muted">{{formatAmount $addr.Balance}} {{$cs}}</small>
<small class="text-muted">{{formatAmount $addr.BalanceSat}} {{$cs}}</small>
</h1>
<div class="alert alert-data ellipsis">
<span class="data">{{$addr.AddrStr}}</span>
@ -13,7 +13,7 @@
{{- if eq .ChainType 1 -}}
<tr>
<td style="width: 25%;">Balance</td>
<td class="data">{{formatAmount $addr.Balance}} {{$cs}}</td>
<td class="data">{{formatAmount $addr.BalanceSat}} {{$cs}}</td>
</tr>
<tr>
<td>Non-contract Transactions</td>
@ -37,7 +37,7 @@
{{- range $et := $addr.Erc20Tokens -}}
<tr>
<td class="data ellipsis"><a href="/address/{{$et.Contract}}">{{$et.Name}}</a></td>
<td class="data">{{formatAmount $et.Balance}} {{$et.Symbol}}</td>
<td class="data">{{formatAmountWithDecimals $et.BalanceSat $et.Decimals}} {{$et.Symbol}}</td>
<td class="data">{{$et.Txs}}</td>
</tr>
{{- end -}}
@ -50,15 +50,15 @@
{{- else -}}
<tr>
<td style="width: 25%;">Total Received</td>
<td class="data">{{formatAmount $addr.TotalReceived}} {{$cs}}</td>
<td class="data">{{formatAmount $addr.TotalReceivedSat}} {{$cs}}</td>
</tr>
<tr>
<td>Total Sent</td>
<td class="data">{{formatAmount $addr.TotalSent}} {{$cs}}</td>
<td class="data">{{formatAmount $addr.TotalSentSat}} {{$cs}}</td>
</tr>
<tr>
<td>Final Balance</td>
<td class="data">{{formatAmount $addr.Balance}} {{$cs}}</td>
<td class="data">{{formatAmount $addr.BalanceSat}} {{$cs}}</td>
</tr>
<tr>
<td>No. Transactions</td>
@ -83,7 +83,7 @@
<tbody>
<tr>
<td style="width: 25%;">Unconfirmed Balance</td>
<td class="data">{{formatAmount $addr.UnconfirmedBalance}} {{$cs}}</td>
<td class="data">{{formatAmount $addr.UnconfirmedBalanceSat}} {{$cs}}</td>
</tr>
<tr>
<td>No. Transactions</td>

View File

@ -36,7 +36,7 @@
</tr>
<tr>
<td>Value</td>
<td class="data">{{formatAmount $tx.ValueOut}} {{$cs}}</td>
<td class="data">{{formatAmount $tx.ValueOutSat}} {{$cs}}</td>
</tr>
<tr>
<td>Gas Used / Limit</td>
@ -49,17 +49,17 @@
{{- else -}}
<tr>
<td>Total Input</td>
<td class="data">{{formatAmount $tx.ValueIn}} {{$cs}}</td>
<td class="data">{{formatAmount $tx.ValueInSat}} {{$cs}}</td>
</tr>
<tr>
<td>Total Output</td>
<td class="data">{{formatAmount $tx.ValueOut}} {{$cs}}</td>
<td class="data">{{formatAmount $tx.ValueOutSat}} {{$cs}}</td>
</tr>
{{- end -}}
{{- if $tx.Fees -}}
{{- if $tx.FeesSat -}}
<tr>
<td>Fees</td>
<td class="data">{{formatAmount $tx.Fees}} {{$cs}}</td>
<td class="data">{{formatAmount $tx.FeesSat}} {{$cs}}</td>
</tr>{{end -}}
</tbody>
</table>

View File

@ -26,7 +26,7 @@
{{- else -}}
<span class="float-left">{{- if $vin.ScriptSig.Hex -}}Unparsed address{{- else -}}No Inputs (Newly Generated Coins){{- end -}}</span>
{{- end -}}{{- if $vin.Addresses -}}
<span class="float-right{{if stringInSlice $addr $vin.Addresses}} text-danger{{end}}">{{formatAmount $vin.Value}} {{$cs}}</span>
<span class="float-right{{if stringInSlice $addr $vin.Addresses}} text-danger{{end}}">{{formatAmount $vin.ValueSat}} {{$cs}}</span>
{{- end -}}
</td>
</tr>
@ -59,7 +59,7 @@
<span class="float-left">Unparsed address</span>
{{- end -}}
<span class="float-right{{if stringInSlice $addr $vout.ScriptPubKey.Addresses}} text-success{{end}}">
{{formatAmount $vout.Value}} {{$cs}} {{if $vout.Spent}}<a class="text-danger" href="{{if $vout.SpentTxID}}/tx/{{$vout.SpentTxID}}{{else}}/spending/{{$tx.Txid}}/{{$vout.N}}{{end}}" title="Spent"></a>{{else -}}
{{formatAmount $vout.ValueSat}} {{$cs}} {{if $vout.Spent}}<a class="text-danger" href="{{if $vout.SpentTxID}}/tx/{{$vout.SpentTxID}}{{else}}/spending/{{$tx.Txid}}/{{$vout.N}}{{end}}" title="Spent"></a>{{else -}}
<span class="text-success" title="Unspent"> <b>×</b></span>
{{- end -}}
</span>
@ -77,8 +77,8 @@
</div>
<div class="row line-top">
<div class="col-xs-6 col-sm-4 col-md-4">
{{- if $tx.Fees -}}
<span class="txvalues txvalues-default">Fee: {{formatAmount $tx.Fees}} {{$cs}}</span>
{{- if $tx.FeesSat -}}
<span class="txvalues txvalues-default">Fee: {{formatAmount $tx.FeesSat}} {{$cs}}</span>
{{- end -}}
</div>
<div class="col-xs-6 col-sm-8 col-md-8 text-right">
@ -87,7 +87,7 @@
{{- else -}}
<span class="txvalues txvalues-danger ng-hide">Unconfirmed Transaction!</span>
{{- end -}}
<span class="txvalues txvalues-primary">{{formatAmount $tx.ValueOut}} {{$cs}}</span>
<span class="txvalues txvalues-primary">{{formatAmount $tx.ValueOutSat}} {{$cs}}</span>
</div>
</div>
</div>

View File

@ -66,7 +66,7 @@
</div>
</div>
<div class="col-md-3 text-right" style="padding: .4rem 0;">
{{formatAmount $tx.ValueOut}} {{$cs}}
{{formatAmount $tx.ValueOutSat}} {{$cs}}
</div>
</div>
{{- if $tx.Erc20Transfers -}}
@ -106,15 +106,15 @@
</table>
</div>
</div>
<div class="col-md-3 text-right" style="padding: .4rem 0;">{{formatAmount $erc20.Tokens}} {{$erc20.Symbol}}</div>
<div class="col-md-3 text-right" style="padding: .4rem 0;">{{formatAmountWithDecimals $erc20.Tokens $erc20.Decimals}} {{$erc20.Symbol}}</div>
</div>
{{- end -}}
<div class="row" style="padding: 6px 15px;"></div>
{{- end -}}
<div class="row line-top">
<div class="col-xs-6 col-sm-4 col-md-4">
{{- if $tx.Fees -}}
<span class="txvalues txvalues-default">Fee: {{formatAmount $tx.Fees}} {{$cs}}</span>
{{- if $tx.FeesSat -}}
<span class="txvalues txvalues-default">Fee: {{formatAmount $tx.FeesSat}} {{$cs}}</span>
{{- end -}}
</div>
<div class="col-xs-6 col-sm-8 col-md-8 text-right">
@ -123,7 +123,7 @@
{{- else -}}
<span class="txvalues txvalues-danger ng-hide">Unconfirmed Transaction!</span>
{{- end -}}
<span class="txvalues txvalues-primary">{{formatAmount $tx.ValueOut}} {{$cs}}</span>
<span class="txvalues txvalues-primary">{{formatAmount $tx.ValueOutSat}} {{$cs}}</span>
</div>
</div>
</div>