core: verify Claim transactions
This commit is contained in:
parent
9d5841df38
commit
45b8669b42
2 changed files with 94 additions and 0 deletions
|
@ -1268,11 +1268,97 @@ func (bc *Blockchain) verifyTx(t *transaction.Transaction, block *block.Block) e
|
|||
if bc.dao.IsDoubleClaim(claim) {
|
||||
return errors.New("double claim")
|
||||
}
|
||||
if err := bc.verifyClaims(t); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return bc.verifyTxWitnesses(t, block)
|
||||
}
|
||||
|
||||
func (bc *Blockchain) verifyClaims(tx *transaction.Transaction) (err error) {
|
||||
t := tx.Data.(*transaction.ClaimTX)
|
||||
var result *transaction.Result
|
||||
results := bc.GetTransactionResults(tx)
|
||||
for i := range results {
|
||||
if results[i].AssetID == UtilityTokenID() {
|
||||
result = results[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if result == nil || result.Amount.GreaterThan(0) {
|
||||
return errors.New("invalid output in claim tx")
|
||||
}
|
||||
|
||||
bonus, err := bc.calculateBonus(t.Claims)
|
||||
if err == nil && bonus != -result.Amount {
|
||||
return fmt.Errorf("wrong bonus calculated in claim tx: %s != %s",
|
||||
bonus.String(), (-result.Amount).String())
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (bc *Blockchain) calculateBonus(claims []transaction.Input) (util.Fixed8, error) {
|
||||
unclaimed := []*spentCoin{}
|
||||
inputs := transaction.GroupInputsByPrevHash(claims)
|
||||
|
||||
for _, group := range inputs {
|
||||
h := group[0].PrevHash
|
||||
claimable, err := bc.getUnclaimed(h)
|
||||
if err != nil || len(claimable) == 0 {
|
||||
return 0, errors.New("no unclaimed inputs")
|
||||
}
|
||||
|
||||
for _, c := range group {
|
||||
s, ok := claimable[c.PrevIndex]
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("can't find spent coins for %s (%d)", c.PrevHash.StringLE(), c.PrevIndex)
|
||||
}
|
||||
unclaimed = append(unclaimed, s)
|
||||
}
|
||||
}
|
||||
|
||||
return bc.calculateBonusInternal(unclaimed)
|
||||
}
|
||||
|
||||
func (bc *Blockchain) calculateBonusInternal(scs []*spentCoin) (util.Fixed8, error) {
|
||||
var claimed util.Fixed8
|
||||
for _, sc := range scs {
|
||||
gen, sys, err := bc.CalculateClaimable(sc.Output.Amount, sc.StartHeight, sc.EndHeight)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
claimed += gen + sys
|
||||
}
|
||||
|
||||
return claimed, nil
|
||||
}
|
||||
|
||||
func (bc *Blockchain) getUnclaimed(h util.Uint256) (map[uint16]*spentCoin, error) {
|
||||
tx, txHeight, err := bc.GetTransaction(h)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
scs, err := bc.dao.GetSpentCoinState(h)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make(map[uint16]*spentCoin)
|
||||
for i, height := range scs.items {
|
||||
result[i] = &spentCoin{
|
||||
Output: &tx.Outputs[i],
|
||||
StartHeight: txHeight,
|
||||
EndHeight: height,
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// isTxStillRelevant is a callback for mempool transaction filtering after the
|
||||
// new block addition. It returns false for transactions already present in the
|
||||
// chain (added by the new block), transactions using some inputs that are
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"github.com/CityOfZion/neo-go/pkg/core/transaction"
|
||||
"github.com/CityOfZion/neo-go/pkg/io"
|
||||
"github.com/CityOfZion/neo-go/pkg/util"
|
||||
)
|
||||
|
@ -14,6 +15,13 @@ type SpentCoinState struct {
|
|||
items map[uint16]uint32
|
||||
}
|
||||
|
||||
// spentCoin represents the state of a single spent coin output.
|
||||
type spentCoin struct {
|
||||
Output *transaction.Output
|
||||
StartHeight uint32
|
||||
EndHeight uint32
|
||||
}
|
||||
|
||||
// NewSpentCoinState returns a new SpentCoinState object.
|
||||
func NewSpentCoinState(hash util.Uint256, height uint32) *SpentCoinState {
|
||||
return &SpentCoinState{
|
||||
|
|
Loading…
Reference in a new issue