core, rpc: use Seek to iterate over NEP* transfers
The results are controversial a bit. MemoryPS is a special storage and the new approach doesn't help it to iterate through NEP17 transfers. However, on long distances (if transfers are requested for more than 1000 blocks, which is ~4.1 hours of mainnet chain) both LevelDB and BoltDB perform good enough with the new approach. Taking into account the fact that default value for the query period of `getnep17transfers` RPC handler is a week (~40K mainnet blocks) we can sacrifice MemoryPS performance in favour of BoltDB and LevelDB optimisation. Close #2263. Benchmark results: name old time/op new time/op delta Blockchain_ForEachNEP17Transfer/MemPS_StartFromBlockN-1_Take100Blocks-8 783µs ±13% 1762µs ± 4% +125.12% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/MemPS_StartFromBlockN-1_Take1000Blocks-8 6.91ms ± 2% 9.00ms ± 2% +30.28% (p=0.000 n=10+9) Blockchain_ForEachNEP17Transfer/MemPS_StartFromBlockN-100_Take100Blocks-8 1.43ms ± 8% 1.79ms ± 4% +24.93% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/MemPS_StartFromBlockN-100_Take1000Blocks-8 7.78ms ± 3% 8.93ms ± 2% +14.78% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/MemPS_StartFromBlockN-1000_Take100Blocks-8 7.69ms ± 3% 1.73ms ±10% -77.50% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/MemPS_StartFromBlockN-1000_Take1000Blocks-8 14.1ms ± 2% 9.0ms ± 2% -36.53% (p=0.000 n=9+10) Blockchain_ForEachNEP17Transfer/BoltPS_StartFromBlockN-1_Take100Blocks-8 768µs ± 3% 801µs ± 2% +4.24% (p=0.000 n=10+9) Blockchain_ForEachNEP17Transfer/BoltPS_StartFromBlockN-1_Take1000Blocks-8 8.03ms ± 2% 8.05ms ± 8% ~ (p=0.436 n=10+10) Blockchain_ForEachNEP17Transfer/BoltPS_StartFromBlockN-100_Take100Blocks-8 1.70ms ±16% 0.85ms ± 7% -49.85% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/BoltPS_StartFromBlockN-100_Take1000Blocks-8 10.8ms ± 2% 8.1ms ± 2% -25.21% (p=0.000 n=10+8) Blockchain_ForEachNEP17Transfer/BoltPS_StartFromBlockN-1000_Take100Blocks-8 10.8ms ± 2% 0.9ms ± 7% -92.12% (p=0.000 n=9+10) Blockchain_ForEachNEP17Transfer/BoltPS_StartFromBlockN-1000_Take1000Blocks-8 18.2ms ±13% 8.2ms ± 6% -54.95% (p=0.000 n=10+9) Blockchain_ForEachNEP17Transfer/LevelPS_StartFromBlockN-1_Take100Blocks-8 874µs ± 6% 823µs ± 2% -5.81% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/LevelPS_StartFromBlockN-1_Take1000Blocks-8 9.35ms ± 2% 8.14ms ± 2% -12.91% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/LevelPS_StartFromBlockN-100_Take100Blocks-8 1.85ms ± 4% 0.89ms ±10% -51.68% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/LevelPS_StartFromBlockN-100_Take1000Blocks-8 10.6ms ± 4% 8.2ms ± 2% -22.44% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/LevelPS_StartFromBlockN-1000_Take100Blocks-8 10.7ms ± 2% 0.9ms ± 2% -91.90% (p=0.000 n=8+10) Blockchain_ForEachNEP17Transfer/LevelPS_StartFromBlockN-1000_Take1000Blocks-8 21.8ms ±15% 8.2ms ± 1% -62.25% (p=0.000 n=10+10) name old alloc/op new alloc/op delta Blockchain_ForEachNEP17Transfer/MemPS_StartFromBlockN-1_Take100Blocks-8 650kB ± 0% 1010kB ± 7% +55.45% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/MemPS_StartFromBlockN-1_Take1000Blocks-8 6.39MB ± 0% 9.89MB ± 1% +54.74% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/MemPS_StartFromBlockN-100_Take100Blocks-8 1.28MB ± 0% 1.14MB ± 0% -11.25% (p=0.000 n=9+10) Blockchain_ForEachNEP17Transfer/MemPS_StartFromBlockN-100_Take1000Blocks-8 7.02MB ± 0% 10.01MB ± 0% +42.54% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/MemPS_StartFromBlockN-1000_Take100Blocks-8 7.02MB ± 0% 1.08MB ± 0% -84.64% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/MemPS_StartFromBlockN-1000_Take1000Blocks-8 12.8MB ± 0% 10.0MB ± 0% -22.04% (p=0.000 n=10+9) Blockchain_ForEachNEP17Transfer/BoltPS_StartFromBlockN-1_Take100Blocks-8 823kB ± 3% 866kB ± 5% +5.19% (p=0.001 n=9+10) Blockchain_ForEachNEP17Transfer/BoltPS_StartFromBlockN-1_Take1000Blocks-8 9.92MB ± 0% 9.85MB ± 0% -0.71% (p=0.000 n=10+9) Blockchain_ForEachNEP17Transfer/BoltPS_StartFromBlockN-100_Take100Blocks-8 1.84MB ± 4% 1.01MB ± 5% -44.75% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/BoltPS_StartFromBlockN-100_Take1000Blocks-8 11.0MB ± 0% 10.0MB ± 1% -8.45% (p=0.000 n=10+9) Blockchain_ForEachNEP17Transfer/BoltPS_StartFromBlockN-1000_Take100Blocks-8 11.0MB ± 0% 1.0MB ± 1% -90.55% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/BoltPS_StartFromBlockN-1000_Take1000Blocks-8 20.0MB ± 0% 10.1MB ± 0% -49.69% (p=0.000 n=9+10) Blockchain_ForEachNEP17Transfer/LevelPS_StartFromBlockN-1_Take100Blocks-8 913kB ± 5% 907kB ± 6% ~ (p=0.497 n=9+10) Blockchain_ForEachNEP17Transfer/LevelPS_StartFromBlockN-1_Take1000Blocks-8 10.0MB ± 1% 10.0MB ± 1% -0.63% (p=0.001 n=10+8) Blockchain_ForEachNEP17Transfer/LevelPS_StartFromBlockN-100_Take100Blocks-8 1.92MB ± 2% 1.04MB ± 0% -45.53% (p=0.000 n=9+8) Blockchain_ForEachNEP17Transfer/LevelPS_StartFromBlockN-100_Take1000Blocks-8 11.1MB ± 1% 10.1MB ± 0% -9.22% (p=0.000 n=10+7) Blockchain_ForEachNEP17Transfer/LevelPS_StartFromBlockN-1000_Take100Blocks-8 11.1MB ± 1% 1.0MB ± 0% -90.61% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/LevelPS_StartFromBlockN-1000_Take1000Blocks-8 20.4MB ± 1% 10.1MB ± 0% -50.46% (p=0.000 n=10+10) name old allocs/op new allocs/op delta Blockchain_ForEachNEP17Transfer/MemPS_StartFromBlockN-1_Take100Blocks-8 11.1k ± 0% 11.7k ± 0% +5.35% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/MemPS_StartFromBlockN-1_Take1000Blocks-8 110k ± 0% 110k ± 0% +0.55% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/MemPS_StartFromBlockN-100_Take100Blocks-8 22.0k ± 0% 11.9k ± 0% -46.14% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/MemPS_StartFromBlockN-100_Take1000Blocks-8 120k ± 0% 110k ± 0% -8.44% (p=0.000 n=10+9) Blockchain_ForEachNEP17Transfer/MemPS_StartFromBlockN-1000_Take100Blocks-8 120k ± 0% 12k ± 0% -90.36% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/MemPS_StartFromBlockN-1000_Take1000Blocks-8 219k ± 0% 110k ± 0% -49.73% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/BoltPS_StartFromBlockN-1_Take100Blocks-8 11.3k ± 0% 11.2k ± 0% -1.06% (p=0.000 n=9+10) Blockchain_ForEachNEP17Transfer/BoltPS_StartFromBlockN-1_Take1000Blocks-8 112k ± 0% 110k ± 0% -2.36% (p=0.000 n=9+10) Blockchain_ForEachNEP17Transfer/BoltPS_StartFromBlockN-100_Take100Blocks-8 22.5k ± 0% 11.3k ± 0% -49.65% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/BoltPS_StartFromBlockN-100_Take1000Blocks-8 124k ± 0% 110k ± 0% -11.08% (p=0.000 n=9+10) Blockchain_ForEachNEP17Transfer/BoltPS_StartFromBlockN-1000_Take100Blocks-8 124k ± 0% 11k ± 0% -90.84% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/BoltPS_StartFromBlockN-1000_Take1000Blocks-8 225k ± 0% 110k ± 0% -51.07% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/LevelPS_StartFromBlockN-1_Take100Blocks-8 11.4k ± 0% 11.3k ± 0% -1.36% (p=0.000 n=9+9) Blockchain_ForEachNEP17Transfer/LevelPS_StartFromBlockN-1_Take1000Blocks-8 114k ± 0% 111k ± 0% -2.33% (p=0.000 n=10+9) Blockchain_ForEachNEP17Transfer/LevelPS_StartFromBlockN-100_Take100Blocks-8 22.7k ± 0% 11.5k ± 0% -49.56% (p=0.000 n=9+10) Blockchain_ForEachNEP17Transfer/LevelPS_StartFromBlockN-100_Take1000Blocks-8 125k ± 0% 111k ± 0% -11.12% (p=0.000 n=10+10) Blockchain_ForEachNEP17Transfer/LevelPS_StartFromBlockN-1000_Take100Blocks-8 125k ± 0% 11k ± 0% -90.82% (p=0.000 n=8+10) Blockchain_ForEachNEP17Transfer/LevelPS_StartFromBlockN-1000_Take1000Blocks-8 229k ± 1% 111k ± 0% -51.42% (p=0.000 n=10+10)
This commit is contained in:
parent
e3af21ab4a
commit
9b841b9b8f
7 changed files with 97 additions and 70 deletions
|
@ -286,12 +286,12 @@ func (chain *FakeChain) GetTokenLastUpdated(acc util.Uint160) (map[int32]uint32,
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForEachNEP17Transfer implements Blockchainer interface.
|
// ForEachNEP17Transfer implements Blockchainer interface.
|
||||||
func (chain *FakeChain) ForEachNEP11Transfer(util.Uint160, func(*state.NEP11Transfer) (bool, error)) error {
|
func (chain *FakeChain) ForEachNEP11Transfer(util.Uint160, uint64, func(*state.NEP11Transfer) (bool, error)) error {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForEachNEP17Transfer implements Blockchainer interface.
|
// ForEachNEP17Transfer implements Blockchainer interface.
|
||||||
func (chain *FakeChain) ForEachNEP17Transfer(util.Uint160, func(*state.NEP17Transfer) (bool, error)) error {
|
func (chain *FakeChain) ForEachNEP17Transfer(util.Uint160, uint64, func(*state.NEP17Transfer) (bool, error)) error {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,7 +93,7 @@ func benchmarkForEachNEP17Transfer(t *testing.B, ps storage.Store, startFromBloc
|
||||||
|
|
||||||
newestB, err := bc.GetBlock(bc.GetHeaderHash(int(bc.BlockHeight()) - startFromBlock + 1))
|
newestB, err := bc.GetBlock(bc.GetHeaderHash(int(bc.BlockHeight()) - startFromBlock + 1))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
_ = newestB.Timestamp
|
newestTimestamp := newestB.Timestamp
|
||||||
oldestB, err := bc.GetBlock(bc.GetHeaderHash(int(newestB.Index) - nBlocksToTake))
|
oldestB, err := bc.GetBlock(bc.GetHeaderHash(int(newestB.Index) - nBlocksToTake))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
oldestTimestamp := oldestB.Timestamp
|
oldestTimestamp := oldestB.Timestamp
|
||||||
|
@ -102,7 +102,7 @@ func benchmarkForEachNEP17Transfer(t *testing.B, ps storage.Store, startFromBloc
|
||||||
t.ReportAllocs()
|
t.ReportAllocs()
|
||||||
t.StartTimer()
|
t.StartTimer()
|
||||||
for i := 0; i < t.N; i++ {
|
for i := 0; i < t.N; i++ {
|
||||||
require.NoError(t, bc.ForEachNEP17Transfer(acc, func(t *state.NEP17Transfer) (bool, error) {
|
require.NoError(t, bc.ForEachNEP17Transfer(acc, newestTimestamp, func(t *state.NEP17Transfer) (bool, error) {
|
||||||
if t.Timestamp < oldestTimestamp {
|
if t.Timestamp < oldestTimestamp {
|
||||||
// iterating from newest to oldest, already have reached the needed height
|
// iterating from newest to oldest, already have reached the needed height
|
||||||
return false, nil
|
return false, nil
|
||||||
|
|
|
@ -1023,14 +1023,14 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !trData.Info.NewNEP11Batch {
|
if !trData.Info.NewNEP11Batch {
|
||||||
err = kvcache.PutTokenTransferLog(acc, trData.Info.NextNEP11Batch, true, &trData.Log11)
|
err = kvcache.PutTokenTransferLog(acc, trData.Info.NextNEP11NewestTimestamp, trData.Info.NextNEP11Batch, true, &trData.Log11)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
aerdone <- err
|
aerdone <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !trData.Info.NewNEP17Batch {
|
if !trData.Info.NewNEP17Batch {
|
||||||
err = kvcache.PutTokenTransferLog(acc, trData.Info.NextNEP17Batch, false, &trData.Log17)
|
err = kvcache.PutTokenTransferLog(acc, trData.Info.NextNEP17NewestTimestamp, trData.Info.NextNEP17Batch, false, &trData.Log17)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
aerdone <- err
|
aerdone <- err
|
||||||
return
|
return
|
||||||
|
@ -1334,18 +1334,18 @@ func (bc *Blockchain) processTokenTransfer(cache dao.DAO, transCache map[util.Ui
|
||||||
}
|
}
|
||||||
if !from.Equals(util.Uint160{}) {
|
if !from.Equals(util.Uint160{}) {
|
||||||
_ = nep17xfer.Amount.Neg(amount) // We already have the Int.
|
_ = nep17xfer.Amount.Neg(amount) // We already have the Int.
|
||||||
if appendTokenTransfer(cache, transCache, from, transfer, id, b.Index, isNEP11) != nil {
|
if appendTokenTransfer(cache, transCache, from, transfer, id, b.Index, b.Timestamp, isNEP11) != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !to.Equals(util.Uint160{}) {
|
if !to.Equals(util.Uint160{}) {
|
||||||
_ = nep17xfer.Amount.Set(amount) // We already have the Int.
|
_ = nep17xfer.Amount.Set(amount) // We already have the Int.
|
||||||
_ = appendTokenTransfer(cache, transCache, to, transfer, id, b.Index, isNEP11) // Nothing useful we can do.
|
_ = appendTokenTransfer(cache, transCache, to, transfer, id, b.Index, b.Timestamp, isNEP11) // Nothing useful we can do.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func appendTokenTransfer(cache dao.DAO, transCache map[util.Uint160]transferData, addr util.Uint160, transfer io.Serializable,
|
func appendTokenTransfer(cache dao.DAO, transCache map[util.Uint160]transferData, addr util.Uint160, transfer io.Serializable,
|
||||||
token int32, bIndex uint32, isNEP11 bool) error {
|
token int32, bIndex uint32, bTimestamp uint64, isNEP11 bool) error {
|
||||||
transferData, ok := transCache[addr]
|
transferData, ok := transCache[addr]
|
||||||
if !ok {
|
if !ok {
|
||||||
balances, err := cache.GetTokenTransferInfo(addr)
|
balances, err := cache.GetTokenTransferInfo(addr)
|
||||||
|
@ -1353,14 +1353,14 @@ func appendTokenTransfer(cache dao.DAO, transCache map[util.Uint160]transferData
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !balances.NewNEP11Batch {
|
if !balances.NewNEP11Batch {
|
||||||
trLog, err := cache.GetTokenTransferLog(addr, balances.NextNEP11Batch, true)
|
trLog, err := cache.GetTokenTransferLog(addr, balances.NextNEP11NewestTimestamp, balances.NextNEP11Batch, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
transferData.Log11 = *trLog
|
transferData.Log11 = *trLog
|
||||||
}
|
}
|
||||||
if !balances.NewNEP17Batch {
|
if !balances.NewNEP17Batch {
|
||||||
trLog, err := cache.GetTokenTransferLog(addr, balances.NextNEP17Batch, false)
|
trLog, err := cache.GetTokenTransferLog(addr, balances.NextNEP17NewestTimestamp, balances.NextNEP17Batch, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1372,15 +1372,18 @@ func appendTokenTransfer(cache dao.DAO, transCache map[util.Uint160]transferData
|
||||||
log *state.TokenTransferLog
|
log *state.TokenTransferLog
|
||||||
newBatch *bool
|
newBatch *bool
|
||||||
nextBatch *uint32
|
nextBatch *uint32
|
||||||
|
currTimestamp *uint64
|
||||||
)
|
)
|
||||||
if !isNEP11 {
|
if !isNEP11 {
|
||||||
log = &transferData.Log17
|
log = &transferData.Log17
|
||||||
newBatch = &transferData.Info.NewNEP17Batch
|
newBatch = &transferData.Info.NewNEP17Batch
|
||||||
nextBatch = &transferData.Info.NextNEP17Batch
|
nextBatch = &transferData.Info.NextNEP17Batch
|
||||||
|
currTimestamp = &transferData.Info.NextNEP17NewestTimestamp
|
||||||
} else {
|
} else {
|
||||||
log = &transferData.Log11
|
log = &transferData.Log11
|
||||||
newBatch = &transferData.Info.NewNEP11Batch
|
newBatch = &transferData.Info.NewNEP11Batch
|
||||||
nextBatch = &transferData.Info.NextNEP11Batch
|
nextBatch = &transferData.Info.NextNEP11Batch
|
||||||
|
currTimestamp = &transferData.Info.NextNEP11NewestTimestamp
|
||||||
}
|
}
|
||||||
err := log.Append(transfer)
|
err := log.Append(transfer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -1389,11 +1392,12 @@ func appendTokenTransfer(cache dao.DAO, transCache map[util.Uint160]transferData
|
||||||
transferData.Info.LastUpdated[token] = bIndex
|
transferData.Info.LastUpdated[token] = bIndex
|
||||||
*newBatch = log.Size() >= state.TokenTransferBatchSize
|
*newBatch = log.Size() >= state.TokenTransferBatchSize
|
||||||
if *newBatch {
|
if *newBatch {
|
||||||
err = cache.PutTokenTransferLog(addr, *nextBatch, isNEP11, log)
|
err = cache.PutTokenTransferLog(addr, *currTimestamp, *nextBatch, isNEP11, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
*nextBatch++
|
*nextBatch++
|
||||||
|
*currTimestamp = bTimestamp
|
||||||
// Put makes a copy of it anyway.
|
// Put makes a copy of it anyway.
|
||||||
log.Raw = log.Raw[:0]
|
log.Raw = log.Raw[:0]
|
||||||
}
|
}
|
||||||
|
@ -1401,48 +1405,18 @@ func appendTokenTransfer(cache dao.DAO, transCache map[util.Uint160]transferData
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForEachNEP17Transfer executes f for each NEP-17 transfer in log.
|
// ForEachNEP17Transfer executes f for each NEP-17 transfer in log starting from
|
||||||
func (bc *Blockchain) ForEachNEP17Transfer(acc util.Uint160, f func(*state.NEP17Transfer) (bool, error)) error {
|
// the transfer with the newest timestamp up to the oldest transfer. It continues
|
||||||
balances, err := bc.dao.GetTokenTransferInfo(acc)
|
// iteration until false is returned from f. The last non-nil error is returned.
|
||||||
if err != nil {
|
func (bc *Blockchain) ForEachNEP17Transfer(acc util.Uint160, newestTimestamp uint64, f func(*state.NEP17Transfer) (bool, error)) error {
|
||||||
return nil
|
return bc.dao.SeekNEP17TransferLog(acc, newestTimestamp, f)
|
||||||
}
|
|
||||||
for i := int(balances.NextNEP17Batch); i >= 0; i-- {
|
|
||||||
lg, err := bc.dao.GetTokenTransferLog(acc, uint32(i), false)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
cont, err := lg.ForEachNEP17(f)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !cont {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForEachNEP11Transfer executes f for each NEP-11 transfer in log.
|
// ForEachNEP11Transfer executes f for each NEP-11 transfer in log starting from
|
||||||
func (bc *Blockchain) ForEachNEP11Transfer(acc util.Uint160, f func(*state.NEP11Transfer) (bool, error)) error {
|
// the transfer with the newest timestamp up to the oldest transfer. It continues
|
||||||
balances, err := bc.dao.GetTokenTransferInfo(acc)
|
// iteration until false is returned from f. The last non-nil error is returned.
|
||||||
if err != nil {
|
func (bc *Blockchain) ForEachNEP11Transfer(acc util.Uint160, newestTimestamp uint64, f func(*state.NEP11Transfer) (bool, error)) error {
|
||||||
return nil
|
return bc.dao.SeekNEP11TransferLog(acc, newestTimestamp, f)
|
||||||
}
|
|
||||||
for i := int(balances.NextNEP11Batch); i >= 0; i-- {
|
|
||||||
lg, err := bc.dao.GetTokenTransferLog(acc, uint32(i), true)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
cont, err := lg.ForEachNEP11(f)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !cont {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNEP17Contracts returns the list of deployed NEP-17 contracts.
|
// GetNEP17Contracts returns the list of deployed NEP-17 contracts.
|
||||||
|
|
|
@ -36,8 +36,8 @@ type Blockchainer interface {
|
||||||
GetContractScriptHash(id int32) (util.Uint160, error)
|
GetContractScriptHash(id int32) (util.Uint160, error)
|
||||||
GetEnrollments() ([]state.Validator, error)
|
GetEnrollments() ([]state.Validator, error)
|
||||||
GetGoverningTokenBalance(acc util.Uint160) (*big.Int, uint32)
|
GetGoverningTokenBalance(acc util.Uint160) (*big.Int, uint32)
|
||||||
ForEachNEP11Transfer(util.Uint160, func(*state.NEP11Transfer) (bool, error)) error
|
ForEachNEP11Transfer(acc util.Uint160, newestTimestamp uint64, f func(*state.NEP11Transfer) (bool, error)) error
|
||||||
ForEachNEP17Transfer(util.Uint160, func(*state.NEP17Transfer) (bool, error)) error
|
ForEachNEP17Transfer(acc util.Uint160, newestTimestamp uint64, f func(*state.NEP17Transfer) (bool, error)) error
|
||||||
GetHeaderHash(int) util.Uint256
|
GetHeaderHash(int) util.Uint256
|
||||||
GetHeader(hash util.Uint256) (*block.Header, error)
|
GetHeader(hash util.Uint256) (*block.Header, error)
|
||||||
CurrentHeaderHash() util.Uint256
|
CurrentHeaderHash() util.Uint256
|
||||||
|
|
|
@ -42,7 +42,7 @@ type DAO interface {
|
||||||
GetCurrentHeaderHeight() (i uint32, h util.Uint256, err error)
|
GetCurrentHeaderHeight() (i uint32, h util.Uint256, err error)
|
||||||
GetHeaderHashes() ([]util.Uint256, error)
|
GetHeaderHashes() ([]util.Uint256, error)
|
||||||
GetTokenTransferInfo(acc util.Uint160) (*state.TokenTransferInfo, error)
|
GetTokenTransferInfo(acc util.Uint160) (*state.TokenTransferInfo, error)
|
||||||
GetTokenTransferLog(acc util.Uint160, index uint32, isNEP11 bool) (*state.TokenTransferLog, error)
|
GetTokenTransferLog(acc util.Uint160, start uint64, index uint32, isNEP11 bool) (*state.TokenTransferLog, error)
|
||||||
GetStateSyncPoint() (uint32, error)
|
GetStateSyncPoint() (uint32, error)
|
||||||
GetStateSyncCurrentBlockHeight() (uint32, error)
|
GetStateSyncCurrentBlockHeight() (uint32, error)
|
||||||
GetStorageItem(id int32, key []byte) state.StorageItem
|
GetStorageItem(id int32, key []byte) state.StorageItem
|
||||||
|
@ -57,7 +57,7 @@ type DAO interface {
|
||||||
PutContractID(id int32, hash util.Uint160) error
|
PutContractID(id int32, hash util.Uint160) error
|
||||||
PutCurrentHeader(hashAndIndex []byte) error
|
PutCurrentHeader(hashAndIndex []byte) error
|
||||||
PutTokenTransferInfo(acc util.Uint160, bs *state.TokenTransferInfo) error
|
PutTokenTransferInfo(acc util.Uint160, bs *state.TokenTransferInfo) error
|
||||||
PutTokenTransferLog(acc util.Uint160, index uint32, isNEP11 bool, lg *state.TokenTransferLog) error
|
PutTokenTransferLog(acc util.Uint160, start uint64, index uint32, isNEP11 bool, lg *state.TokenTransferLog) error
|
||||||
PutStateSyncPoint(p uint32) error
|
PutStateSyncPoint(p uint32) error
|
||||||
PutStateSyncCurrentBlockHeight(h uint32) error
|
PutStateSyncCurrentBlockHeight(h uint32) error
|
||||||
PutStorageItem(id int32, key []byte, si state.StorageItem) error
|
PutStorageItem(id int32, key []byte, si state.StorageItem) error
|
||||||
|
@ -180,21 +180,66 @@ func (dao *Simple) putTokenTransferInfo(acc util.Uint160, bs *state.TokenTransfe
|
||||||
|
|
||||||
// -- start transfer log.
|
// -- start transfer log.
|
||||||
|
|
||||||
func getTokenTransferLogKey(acc util.Uint160, index uint32, isNEP11 bool) []byte {
|
func getTokenTransferLogKey(acc util.Uint160, newestTimestamp uint64, index uint32, isNEP11 bool) []byte {
|
||||||
key := make([]byte, 1+util.Uint160Size+4)
|
key := make([]byte, 1+util.Uint160Size+8+4)
|
||||||
if isNEP11 {
|
if isNEP11 {
|
||||||
key[0] = byte(storage.STNEP11Transfers)
|
key[0] = byte(storage.STNEP11Transfers)
|
||||||
} else {
|
} else {
|
||||||
key[0] = byte(storage.STNEP17Transfers)
|
key[0] = byte(storage.STNEP17Transfers)
|
||||||
}
|
}
|
||||||
copy(key[1:], acc.BytesBE())
|
copy(key[1:], acc.BytesBE())
|
||||||
binary.LittleEndian.PutUint32(key[util.Uint160Size:], index)
|
binary.BigEndian.PutUint64(key[1+util.Uint160Size:], newestTimestamp)
|
||||||
|
binary.BigEndian.PutUint32(key[1+util.Uint160Size+8:], index)
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SeekNEP17TransferLog executes f for each NEP-17 transfer in log starting from
|
||||||
|
// the transfer with the newest timestamp up to the oldest transfer. It continues
|
||||||
|
// iteration until false is returned from f. The last non-nil error is returned.
|
||||||
|
func (dao *Simple) SeekNEP17TransferLog(acc util.Uint160, newestTimestamp uint64, f func(*state.NEP17Transfer) (bool, error)) error {
|
||||||
|
key := getTokenTransferLogKey(acc, newestTimestamp, 0, false)
|
||||||
|
prefixLen := 1 + util.Uint160Size
|
||||||
|
var seekErr error
|
||||||
|
dao.Store.Seek(storage.SeekRange{
|
||||||
|
Prefix: key[:prefixLen],
|
||||||
|
Start: key[prefixLen : prefixLen+8],
|
||||||
|
Backwards: true,
|
||||||
|
}, func(k, v []byte) bool {
|
||||||
|
lg := &state.TokenTransferLog{Raw: v}
|
||||||
|
cont, err := lg.ForEachNEP17(f)
|
||||||
|
if err != nil {
|
||||||
|
seekErr = err
|
||||||
|
}
|
||||||
|
return cont
|
||||||
|
})
|
||||||
|
return seekErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// SeekNEP11TransferLog executes f for each NEP-11 transfer in log starting from
|
||||||
|
// the transfer with the newest timestamp up to the oldest transfer. It continues
|
||||||
|
// iteration until false is returned from f. The last non-nil error is returned.
|
||||||
|
func (dao *Simple) SeekNEP11TransferLog(acc util.Uint160, newestTimestamp uint64, f func(*state.NEP11Transfer) (bool, error)) error {
|
||||||
|
key := getTokenTransferLogKey(acc, newestTimestamp, 0, true)
|
||||||
|
prefixLen := 1 + util.Uint160Size
|
||||||
|
var seekErr error
|
||||||
|
dao.Store.Seek(storage.SeekRange{
|
||||||
|
Prefix: key[:prefixLen],
|
||||||
|
Start: key[prefixLen : prefixLen+8],
|
||||||
|
Backwards: true,
|
||||||
|
}, func(k, v []byte) bool {
|
||||||
|
lg := &state.TokenTransferLog{Raw: v}
|
||||||
|
cont, err := lg.ForEachNEP11(f)
|
||||||
|
if err != nil {
|
||||||
|
seekErr = err
|
||||||
|
}
|
||||||
|
return cont
|
||||||
|
})
|
||||||
|
return seekErr
|
||||||
|
}
|
||||||
|
|
||||||
// GetTokenTransferLog retrieves transfer log from the cache.
|
// GetTokenTransferLog retrieves transfer log from the cache.
|
||||||
func (dao *Simple) GetTokenTransferLog(acc util.Uint160, index uint32, isNEP11 bool) (*state.TokenTransferLog, error) {
|
func (dao *Simple) GetTokenTransferLog(acc util.Uint160, newestTimestamp uint64, index uint32, isNEP11 bool) (*state.TokenTransferLog, error) {
|
||||||
key := getTokenTransferLogKey(acc, index, isNEP11)
|
key := getTokenTransferLogKey(acc, newestTimestamp, index, isNEP11)
|
||||||
value, err := dao.Store.Get(key)
|
value, err := dao.Store.Get(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == storage.ErrKeyNotFound {
|
if err == storage.ErrKeyNotFound {
|
||||||
|
@ -206,8 +251,8 @@ func (dao *Simple) GetTokenTransferLog(acc util.Uint160, index uint32, isNEP11 b
|
||||||
}
|
}
|
||||||
|
|
||||||
// PutTokenTransferLog saves given transfer log in the cache.
|
// PutTokenTransferLog saves given transfer log in the cache.
|
||||||
func (dao *Simple) PutTokenTransferLog(acc util.Uint160, index uint32, isNEP11 bool, lg *state.TokenTransferLog) error {
|
func (dao *Simple) PutTokenTransferLog(acc util.Uint160, start uint64, index uint32, isNEP11 bool, lg *state.TokenTransferLog) error {
|
||||||
key := getTokenTransferLogKey(acc, index, isNEP11)
|
key := getTokenTransferLogKey(acc, start, index, isNEP11)
|
||||||
return dao.Store.Put(key, lg.Raw)
|
return dao.Store.Put(key, lg.Raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,10 @@ type TokenTransferInfo struct {
|
||||||
NextNEP11Batch uint32
|
NextNEP11Batch uint32
|
||||||
// NextNEP17Batch stores the index of the next NEP-17 transfer batch.
|
// NextNEP17Batch stores the index of the next NEP-17 transfer batch.
|
||||||
NextNEP17Batch uint32
|
NextNEP17Batch uint32
|
||||||
|
// NextNEP11NewestTimestamp stores the block timestamp of the first NEP-11 transfer in raw.
|
||||||
|
NextNEP11NewestTimestamp uint64
|
||||||
|
// NextNEP17NewestTimestamp stores the block timestamp of the first NEP-17 transfer in raw.
|
||||||
|
NextNEP17NewestTimestamp uint64
|
||||||
// NewNEP11Batch is true if batch with the `NextNEP11Batch` index should be created.
|
// NewNEP11Batch is true if batch with the `NextNEP11Batch` index should be created.
|
||||||
NewNEP11Batch bool
|
NewNEP11Batch bool
|
||||||
// NewNEP17Batch is true if batch with the `NextNEP17Batch` index should be created.
|
// NewNEP17Batch is true if batch with the `NextNEP17Batch` index should be created.
|
||||||
|
@ -72,6 +76,8 @@ func NewTokenTransferInfo() *TokenTransferInfo {
|
||||||
func (bs *TokenTransferInfo) DecodeBinary(r *io.BinReader) {
|
func (bs *TokenTransferInfo) DecodeBinary(r *io.BinReader) {
|
||||||
bs.NextNEP11Batch = r.ReadU32LE()
|
bs.NextNEP11Batch = r.ReadU32LE()
|
||||||
bs.NextNEP17Batch = r.ReadU32LE()
|
bs.NextNEP17Batch = r.ReadU32LE()
|
||||||
|
bs.NextNEP11NewestTimestamp = r.ReadU64LE()
|
||||||
|
bs.NextNEP17NewestTimestamp = r.ReadU64LE()
|
||||||
bs.NewNEP11Batch = r.ReadBool()
|
bs.NewNEP11Batch = r.ReadBool()
|
||||||
bs.NewNEP17Batch = r.ReadBool()
|
bs.NewNEP17Batch = r.ReadBool()
|
||||||
lenBalances := r.ReadVarUint()
|
lenBalances := r.ReadVarUint()
|
||||||
|
@ -87,6 +93,8 @@ func (bs *TokenTransferInfo) DecodeBinary(r *io.BinReader) {
|
||||||
func (bs *TokenTransferInfo) EncodeBinary(w *io.BinWriter) {
|
func (bs *TokenTransferInfo) EncodeBinary(w *io.BinWriter) {
|
||||||
w.WriteU32LE(bs.NextNEP11Batch)
|
w.WriteU32LE(bs.NextNEP11Batch)
|
||||||
w.WriteU32LE(bs.NextNEP17Batch)
|
w.WriteU32LE(bs.NextNEP17Batch)
|
||||||
|
w.WriteU64LE(bs.NextNEP11NewestTimestamp)
|
||||||
|
w.WriteU64LE(bs.NextNEP17NewestTimestamp)
|
||||||
w.WriteBool(bs.NewNEP11Batch)
|
w.WriteBool(bs.NewNEP11Batch)
|
||||||
w.WriteBool(bs.NewNEP17Batch)
|
w.WriteBool(bs.NewNEP17Batch)
|
||||||
w.WriteVarUint(uint64(len(bs.LastUpdated)))
|
w.WriteVarUint(uint64(len(bs.LastUpdated)))
|
||||||
|
|
|
@ -1019,7 +1019,7 @@ func (s *Server) getTokenTransfers(ps request.Params, isNEP11 bool) (interface{}
|
||||||
return received, sent, !(limit != 0 && resCount >= limit), nil
|
return received, sent, !(limit != 0 && resCount >= limit), nil
|
||||||
}
|
}
|
||||||
if !isNEP11 {
|
if !isNEP11 {
|
||||||
err = s.chain.ForEachNEP17Transfer(u, func(tr *state.NEP17Transfer) (bool, error) {
|
err = s.chain.ForEachNEP17Transfer(u, end, func(tr *state.NEP17Transfer) (bool, error) {
|
||||||
r, s, res, err := handleTransfer(tr)
|
r, s, res, err := handleTransfer(tr)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if r != nil {
|
if r != nil {
|
||||||
|
@ -1032,7 +1032,7 @@ func (s *Server) getTokenTransfers(ps request.Params, isNEP11 bool) (interface{}
|
||||||
return res, err
|
return res, err
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
err = s.chain.ForEachNEP11Transfer(u, func(tr *state.NEP11Transfer) (bool, error) {
|
err = s.chain.ForEachNEP11Transfer(u, end, func(tr *state.NEP11Transfer) (bool, error) {
|
||||||
r, s, res, err := handleTransfer(&tr.NEP17Transfer)
|
r, s, res, err := handleTransfer(&tr.NEP17Transfer)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
id := hex.EncodeToString(tr.ID)
|
id := hex.EncodeToString(tr.ID)
|
||||||
|
@ -1047,7 +1047,7 @@ func (s *Server) getTokenTransfers(ps request.Params, isNEP11 bool) (interface{}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, response.NewInternalServerError("invalid transfer log", err)
|
return nil, response.NewInternalServerError(fmt.Sprintf("invalid transfer log: %v", err), err)
|
||||||
}
|
}
|
||||||
return bs, nil
|
return bs, nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue