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.
|
||||
storedHeaderCount uint32
|
||||
|
||||
generationAmount []int
|
||||
decrementInterval int
|
||||
|
||||
// All operations on headerList must be called from an
|
||||
// headersOp to be routine safe.
|
||||
headerList *HeaderHashList
|
||||
|
@ -154,6 +157,9 @@ func NewBlockchain(s storage.Store, cfg config.ProtocolConfiguration, log *zap.L
|
|||
memPool: mempool.NewMemPool(cfg.MemPoolSize),
|
||||
keyCache: make(map[util.Uint160]map[string]*keys.PublicKey),
|
||||
log: log,
|
||||
|
||||
generationAmount: genAmount,
|
||||
decrementInterval: decrementInterval,
|
||||
}
|
||||
|
||||
if err := bc.init(); err != nil {
|
||||
|
@ -1033,6 +1039,55 @@ func (bc *Blockchain) GetConfig() config.ProtocolConfiguration {
|
|||
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
|
||||
// joining each Input with the corresponding Output.
|
||||
// @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) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
|
|
|
@ -20,6 +20,7 @@ type Blockchainer interface {
|
|||
AddHeaders(...*block.Header) error
|
||||
AddBlock(*block.Block) error
|
||||
BlockHeight() uint32
|
||||
CalculateClaimable(value util.Fixed8, startHeight, endHeight uint32) (util.Fixed8, util.Fixed8, error)
|
||||
Close()
|
||||
HeaderHeight() uint32
|
||||
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 {
|
||||
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) {
|
||||
panic("TODO")
|
||||
|
|
Loading…
Reference in a new issue