mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-12-12 11:10:35 +00:00
Merge pull request #1288 from nspcc-dev/fix/utxo
rpc: adjust `getutxotransfers` RPC
This commit is contained in:
commit
ffbdcb202f
5 changed files with 59 additions and 101 deletions
|
@ -609,13 +609,10 @@ 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
|
||||
|
@ -623,7 +620,7 @@ func (bc *Blockchain) storeBlock(block *block.Block) error {
|
|||
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)
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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:
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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"`
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.Equal(t, "9fbf833320ef6bc52ddee1fe6f5793b42e9b307e", u.Address.StringBE())
|
||||
require.EqualValues(t, int64(util.Fixed8FromInt64(1000)), u.Amount)
|
||||
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.EqualValues(t, int64(util.Fixed8FromInt64(99998000)), u.Amount)
|
||||
} else {
|
||||
require.Nil(t, u)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue