core: implement (*Blockchain).CalculateClaimable
Calculating amount of GAS that can be claimed is required for getclaimable RPC.
This commit is contained in:
parent
252a9f2f31
commit
7095ec6c51
4 changed files with 99 additions and 0 deletions
|
@ -93,6 +93,9 @@ type Blockchain struct {
|
||||||
// Number of headers stored in the chain file.
|
// Number of headers stored in the chain file.
|
||||||
storedHeaderCount uint32
|
storedHeaderCount uint32
|
||||||
|
|
||||||
|
generationAmount []int
|
||||||
|
decrementInterval int
|
||||||
|
|
||||||
// All operations on headerList must be called from an
|
// All operations on headerList must be called from an
|
||||||
// headersOp to be routine safe.
|
// headersOp to be routine safe.
|
||||||
headerList *HeaderHashList
|
headerList *HeaderHashList
|
||||||
|
@ -154,6 +157,9 @@ func NewBlockchain(s storage.Store, cfg config.ProtocolConfiguration, log *zap.L
|
||||||
memPool: mempool.NewMemPool(cfg.MemPoolSize),
|
memPool: mempool.NewMemPool(cfg.MemPoolSize),
|
||||||
keyCache: make(map[util.Uint160]map[string]*keys.PublicKey),
|
keyCache: make(map[util.Uint160]map[string]*keys.PublicKey),
|
||||||
log: log,
|
log: log,
|
||||||
|
|
||||||
|
generationAmount: genAmount,
|
||||||
|
decrementInterval: decrementInterval,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := bc.init(); err != nil {
|
if err := bc.init(); err != nil {
|
||||||
|
@ -1033,6 +1039,55 @@ func (bc *Blockchain) GetConfig() config.ProtocolConfiguration {
|
||||||
return bc.config
|
return bc.config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CalculateClaimable calculates the amount of GAS which can be claimed for a transaction with value.
|
||||||
|
// First return value is GAS generated between startHeight and endHeight.
|
||||||
|
// Second return value is GAS returned from accumulated SystemFees between startHeight and endHeight.
|
||||||
|
func (bc *Blockchain) CalculateClaimable(value util.Fixed8, startHeight, endHeight uint32) (util.Fixed8, util.Fixed8, error) {
|
||||||
|
var amount util.Fixed8
|
||||||
|
di := uint32(bc.decrementInterval)
|
||||||
|
|
||||||
|
ustart := startHeight / di
|
||||||
|
if genSize := uint32(len(bc.generationAmount)); ustart < genSize {
|
||||||
|
uend := endHeight / di
|
||||||
|
iend := endHeight % di
|
||||||
|
if uend >= genSize {
|
||||||
|
uend = genSize - 1
|
||||||
|
iend = di
|
||||||
|
} else if iend == 0 {
|
||||||
|
uend--
|
||||||
|
iend = di
|
||||||
|
}
|
||||||
|
|
||||||
|
istart := startHeight % di
|
||||||
|
for ustart < uend {
|
||||||
|
amount += util.Fixed8(di-istart) * util.Fixed8(bc.generationAmount[ustart])
|
||||||
|
ustart++
|
||||||
|
istart = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
amount += util.Fixed8(iend-istart) * util.Fixed8(bc.generationAmount[ustart])
|
||||||
|
}
|
||||||
|
|
||||||
|
var sysFeeTotal util.Fixed8
|
||||||
|
if startHeight == 0 {
|
||||||
|
startHeight++
|
||||||
|
}
|
||||||
|
for i := startHeight; i < endHeight; i++ {
|
||||||
|
h := bc.GetHeaderHash(int(i))
|
||||||
|
b, err := bc.GetBlock(h)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 0, err
|
||||||
|
}
|
||||||
|
for _, tx := range b.Transactions {
|
||||||
|
sysFeeTotal += bc.SystemFee(tx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sysFeeTotal /= 100000000
|
||||||
|
ratio := value / 100000000
|
||||||
|
return amount * ratio, sysFeeTotal * ratio, nil
|
||||||
|
}
|
||||||
|
|
||||||
// References maps transaction's inputs into a slice of InOuts, effectively
|
// References maps transaction's inputs into a slice of InOuts, effectively
|
||||||
// joining each Input with the corresponding Output.
|
// joining each Input with the corresponding Output.
|
||||||
// @TODO: unfortunately we couldn't attach this method to the Transaction struct in the
|
// @TODO: unfortunately we couldn't attach this method to the Transaction struct in the
|
||||||
|
|
|
@ -175,6 +175,46 @@ func TestGetTransaction(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetClaimable(t *testing.T) {
|
||||||
|
bc := newTestChain(t)
|
||||||
|
|
||||||
|
_, _, err := bc.CalculateClaimable(util.Fixed8FromInt64(1), 0, 2)
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
bc.generationAmount = []int{4, 3, 2, 1}
|
||||||
|
bc.decrementInterval = 2
|
||||||
|
_, err = bc.genBlocks(10)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
t.Run("first generation period", func(t *testing.T) {
|
||||||
|
amount, sysfee, err := bc.CalculateClaimable(util.Fixed8FromInt64(1), 0, 2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.EqualValues(t, 8, amount)
|
||||||
|
require.EqualValues(t, 0, sysfee)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("a number of full periods", func(t *testing.T) {
|
||||||
|
amount, sysfee, err := bc.CalculateClaimable(util.Fixed8FromInt64(1), 0, 6)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.EqualValues(t, 4+4+3+3+2+2, amount)
|
||||||
|
require.EqualValues(t, 0, sysfee)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("start from the 2-nd block", func(t *testing.T) {
|
||||||
|
amount, sysfee, err := bc.CalculateClaimable(util.Fixed8FromInt64(1), 1, 7)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.EqualValues(t, 4+3+3+2+2+1, amount)
|
||||||
|
require.EqualValues(t, 0, sysfee)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("end height after generation has ended", func(t *testing.T) {
|
||||||
|
amount, sysfee, err := bc.CalculateClaimable(util.Fixed8FromInt64(1), 1, 10)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.EqualValues(t, 4+3+3+2+2+1+1, amount)
|
||||||
|
require.EqualValues(t, 0, sysfee)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestClose(t *testing.T) {
|
func TestClose(t *testing.T) {
|
||||||
defer func() {
|
defer func() {
|
||||||
r := recover()
|
r := recover()
|
||||||
|
|
|
@ -20,6 +20,7 @@ type Blockchainer interface {
|
||||||
AddHeaders(...*block.Header) error
|
AddHeaders(...*block.Header) error
|
||||||
AddBlock(*block.Block) error
|
AddBlock(*block.Block) error
|
||||||
BlockHeight() uint32
|
BlockHeight() uint32
|
||||||
|
CalculateClaimable(value util.Fixed8, startHeight, endHeight uint32) (util.Fixed8, util.Fixed8, error)
|
||||||
Close()
|
Close()
|
||||||
HeaderHeight() uint32
|
HeaderHeight() uint32
|
||||||
GetBlock(hash util.Uint256) (*block.Block, error)
|
GetBlock(hash util.Uint256) (*block.Block, error)
|
||||||
|
|
|
@ -32,6 +32,9 @@ func (chain testChain) ApplyPolicyToTxSet([]mempool.TxWithFee) []mempool.TxWithF
|
||||||
func (chain testChain) GetConfig() config.ProtocolConfiguration {
|
func (chain testChain) GetConfig() config.ProtocolConfiguration {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
}
|
}
|
||||||
|
func (chain testChain) CalculateClaimable(util.Fixed8, uint32, uint32) (util.Fixed8, util.Fixed8, error) {
|
||||||
|
panic("TODO")
|
||||||
|
}
|
||||||
|
|
||||||
func (chain testChain) References(t *transaction.Transaction) ([]transaction.InOut, error) {
|
func (chain testChain) References(t *transaction.Transaction) ([]transaction.InOut, error) {
|
||||||
panic("TODO")
|
panic("TODO")
|
||||||
|
|
Loading…
Reference in a new issue