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

rpc: adjust getutxotransfers RPC #1288

Merged
merged 1 commit into from
Aug 7, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 29 additions & 73 deletions pkg/core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -609,21 +609,18 @@ func (bc *Blockchain) storeBlock(block *block.Block) error {
}

// Process TX outputs.
if err := processOutputs(tx, cache); err != nil {
if err := processOutputs(tx, block, cache); err != nil {
return err
}

var pseudoSender util.Uint160
var gasTotal, neoTotal util.Fixed8

// Process TX inputs that are grouped by previous hash.
for _, inputs := range transaction.GroupInputsByPrevHash(tx.Inputs) {
prevHash := inputs[0].PrevHash
unspent, err := cache.GetUnspentCoinState(prevHash)
if err != nil {
return err
}
for i, input := range inputs {
for _, input := range inputs {
if len(unspent.States) <= int(input.PrevIndex) {
return fmt.Errorf("bad input: %s/%d", input.PrevHash.StringLE(), input.PrevIndex)
}
Expand All @@ -633,13 +630,8 @@ func (bc *Blockchain) storeBlock(block *block.Block) error {
unspent.States[input.PrevIndex].State |= state.CoinSpent
unspent.States[input.PrevIndex].SpendHeight = block.Index
prevTXOutput := &unspent.States[input.PrevIndex].Output
if i == 0 {
pseudoSender = prevTXOutput.ScriptHash
}
if prevTXOutput.AssetID.Equals(GoverningTokenID()) {
neoTotal += prevTXOutput.Amount
} else if prevTXOutput.AssetID.Equals(UtilityTokenID()) {
gasTotal += prevTXOutput.Amount
if err := processTransfer(cache, tx, block, prevTXOutput, true); err != nil {
return err
}
account, err := cache.GetAccountStateOrNew(prevTXOutput.ScriptHash)
if err != nil {
Expand Down Expand Up @@ -690,10 +682,6 @@ func (bc *Blockchain) storeBlock(block *block.Block) error {
}
}

if err := bc.processTransfer(cache, pseudoSender, tx, block, neoTotal, gasTotal); err != nil {
return err
}

// Process the underlying type of the TX.
switch t := tx.Data.(type) {
case *transaction.RegisterTX:
Expand Down Expand Up @@ -939,67 +927,32 @@ func appendSingleTransfer(cache *dao.Cached, acc util.Uint160, tr *state.Transfe
}

// processTransfer processes single UTXO transfer. Totals is a slice of neo (0) and gas (1) total transfer amount.
func (bc *Blockchain) processTransfer(cache *dao.Cached, from util.Uint160, tx *transaction.Transaction, b *block.Block,
neoTotal, gasTotal util.Fixed8) error {

fromIndex, err := cache.GetNextTransferBatch(from)
func processTransfer(cache *dao.Cached, tx *transaction.Transaction, b *block.Block, out *transaction.Output,
isSent bool) error {
isGoverning := out.AssetID.Equals(GoverningTokenID())
if !isGoverning && !out.AssetID.Equals(UtilityTokenID()) {
return nil
}
tr := &state.Transfer{
IsGoverning: isGoverning,
IsSent: isSent,
Amount: int64(out.Amount),
Block: b.Index,
Timestamp: b.Timestamp,
Tx: tx.Hash(),
}
index, err := cache.GetNextTransferBatch(out.ScriptHash)
if err != nil {
return err
}
for i := range tx.Outputs {
isGoverning := tx.Outputs[i].AssetID.Equals(GoverningTokenID())
if !isGoverning && !tx.Outputs[i].AssetID.Equals(UtilityTokenID()) {
continue
}
if !from.Equals(tx.Outputs[i].ScriptHash) {
tr := &state.Transfer{
IsGoverning: isGoverning,
From: from,
To: tx.Outputs[i].ScriptHash,
Amount: int64(tx.Outputs[i].Amount),
Block: b.Index,
Timestamp: b.Timestamp,
Tx: tx.Hash(),
}
isBig, err := cache.AppendTransfer(from, fromIndex, tr)
if err != nil {
return err
} else if isBig {
fromIndex++
}
if err := appendSingleTransfer(cache, tx.Outputs[i].ScriptHash, tr); err != nil {
return err
}
}
if isGoverning {
neoTotal -= tx.Outputs[i].Amount
} else {
gasTotal -= tx.Outputs[i].Amount
}

isBig, err := cache.AppendTransfer(out.ScriptHash, index, tr)
if err != nil {
return err
}
for i, amount := range []util.Fixed8{neoTotal, gasTotal} {
if amount > 0 {
tr := &state.Transfer{
IsGoverning: i == 0,
From: from,
Amount: int64(amount),
Block: b.Index,
Timestamp: b.Timestamp,
Tx: tx.Hash(),
}
isBig, err := cache.AppendTransfer(from, fromIndex, tr)
if err != nil {
return err
} else if isBig {
fromIndex++
}
if err := appendSingleTransfer(cache, util.Uint160{}, tr); err != nil {
return err
}
}
if isBig {
return cache.PutNextTransferBatch(out.ScriptHash, index+1)
}
return cache.PutNextTransferBatch(from, fromIndex)
return nil
}

func parseUint160(addr []byte) util.Uint160 {
Expand Down Expand Up @@ -1126,7 +1079,7 @@ func (bc *Blockchain) LastBatch() *storage.MemBatch {
}

// processOutputs processes transaction outputs.
func processOutputs(tx *transaction.Transaction, dao *dao.Cached) error {
func processOutputs(tx *transaction.Transaction, b *block.Block, dao *dao.Cached) error {
for index, output := range tx.Outputs {
account, err := dao.GetAccountStateOrNew(output.ScriptHash)
if err != nil {
Expand All @@ -1143,6 +1096,9 @@ func processOutputs(tx *transaction.Transaction, dao *dao.Cached) error {
if err = processTXWithValidatorsAdd(&output, account, dao); err != nil {
return err
}
if err = processTransfer(dao, tx, b, &output, false); err != nil {
return err
}
}
return nil
}
Expand Down
14 changes: 5 additions & 9 deletions pkg/core/state/transfer_log.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,14 @@ import (
)

// TransferSize is a size of a marshaled Transfer struct in bytes.
const TransferSize = 1 + util.Uint160Size*2 + 8 + 4 + 4 + util.Uint256Size
const TransferSize = 2 + 8 + 4 + 4 + util.Uint256Size

// Transfer represents a single Transfer event.
type Transfer struct {
// IsGoverning is true iff transfer is for neo token.
IsGoverning bool
// Address is the address of the sender.
From util.Uint160
// To is the address of the receiver.
To util.Uint160
// IsSent is true iff UTXO used in the input.
IsSent bool
// Amount is the amount of tokens transferred.
// It is negative when tokens are sent and positive if they are received.
Amount int64
Expand All @@ -31,21 +29,19 @@ type Transfer struct {
// Note: change TransferSize constant when changing this function.
func (t *Transfer) EncodeBinary(w *io.BinWriter) {
w.WriteBytes(t.Tx[:])
w.WriteBytes(t.From[:])
w.WriteBytes(t.To[:])
w.WriteU32LE(t.Block)
w.WriteU32LE(t.Timestamp)
w.WriteU64LE(uint64(t.Amount))
w.WriteBool(t.IsGoverning)
w.WriteBool(t.IsSent)
}

// DecodeBinary implements io.Serializable interface.
func (t *Transfer) DecodeBinary(r *io.BinReader) {
r.ReadBytes(t.Tx[:])
r.ReadBytes(t.From[:])
r.ReadBytes(t.To[:])
t.Block = r.ReadU32LE()
t.Timestamp = r.ReadU32LE()
t.Amount = int64(r.ReadU64LE())
t.IsGoverning = r.ReadBool()
t.IsSent = r.ReadBool()
}
1 change: 0 additions & 1 deletion pkg/rpc/response/result/utxo.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ type UTXO struct {
Index uint32 `json:"block_index"`
Timestamp uint32 `json:"timestamp"`
TxHash util.Uint256 `json:"txid"`
Address util.Uint160 `json:"transfer_address"`
Amount int64 `json:"amount,string"`
}

Expand Down
18 changes: 5 additions & 13 deletions pkg/rpc/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -541,24 +541,16 @@ func (s *Server) getUTXOTransfers(ps request.Params) (interface{}, *response.Err
if !tr.IsGoverning {
assetID = core.UtilityTokenID()
}
a, ok := sent[assetID]
if ok && tr.From.Equals(addr) && !tr.To.Equals(addr) {
a.Transactions = append(a.Transactions, result.UTXO{
Index: tr.Block,
Timestamp: tr.Timestamp,
TxHash: tr.Tx,
Address: tr.To,
Amount: tr.Amount,
})
a.TotalAmount += tr.Amount
m := recv
if tr.IsSent {
m = sent
}
a, ok = recv[assetID]
if ok && tr.To.Equals(addr) && !tr.From.Equals(addr) {
a, ok := m[assetID]
if ok {
a.Transactions = append(a.Transactions, result.UTXO{
Index: tr.Block,
Timestamp: tr.Timestamp,
TxHash: tr.Tx,
Address: tr.From,
Amount: tr.Amount,
})
a.TotalAmount += tr.Amount
Expand Down
25 changes: 20 additions & 5 deletions pkg/rpc/server/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1285,21 +1285,36 @@ func checkTransfers(t *testing.T, e *executor, acc interface{}, asset string, st
require.Equal(t, res.Address, "AKkkumHbBipZ46UMZJoFynJMXzSRnBvKcs")

// transfer from multisig address to us
u := getUTXOForBlock(res, false, asset, 1)
u := getUTXOForBlock(res, false, "neo", 1)
if start <= 1 && (stop == 0 || stop >= 1) && (asset == "neo" || asset == "") {
require.NotNil(t, u)
require.Equal(t, "be48d3a3f5d10013ab9ffee489706078714f1ea2", u.Address.StringBE())
require.EqualValues(t, int64(util.Fixed8FromInt64(99999000)), u.Amount)
} else {
require.Nil(t, u)
}

// gas claim
u = getUTXOForBlock(res, false, "gas", 203)
if start <= 203 && (stop == 0 || stop >= 203) && (asset == "gas" || asset == "") {
require.NotNil(t, u)
require.EqualValues(t, int64(160798392000), u.Amount)
} else {
require.Nil(t, u)
}

// transfer from us to another validator
u = getUTXOForBlock(res, true, asset, 206)
u = getUTXOForBlock(res, true, "neo", 206)
if start <= 206 && (stop == 0 || stop >= 206) && (asset == "neo" || asset == "") {
require.NotNil(t, u)
require.EqualValues(t, int64(util.Fixed8FromInt64(99999000)), u.Amount)
} else {
require.Nil(t, u)
}

u = getUTXOForBlock(res, false, "neo", 206)
if start <= 206 && (stop == 0 || stop >= 206) && (asset == "neo" || asset == "") {
require.NotNil(t, u)
require.Equal(t, "9fbf833320ef6bc52ddee1fe6f5793b42e9b307e", u.Address.StringBE())
require.EqualValues(t, int64(util.Fixed8FromInt64(1000)), u.Amount)
require.EqualValues(t, int64(util.Fixed8FromInt64(99998000)), u.Amount)
} else {
require.Nil(t, u)
}
Expand Down