forked from TrueCloudLab/neoneo-go
Merge pull request #765 from nspcc-dev/fix-issue-tx-verification
Fix issue tx verification
This commit is contained in:
commit
93236e0cfa
3 changed files with 70 additions and 13 deletions
|
@ -1660,6 +1660,13 @@ func (bc *Blockchain) verifyResults(t *transaction.Transaction, results []*trans
|
|||
if r.AssetID == UtilityTokenID() {
|
||||
return errors.New("issue tx issues utility tokens")
|
||||
}
|
||||
asset, err := bc.dao.GetAssetState(r.AssetID)
|
||||
if asset == nil || err != nil {
|
||||
return errors.New("invalid asset in issue tx")
|
||||
}
|
||||
if asset.Available < r.Amount {
|
||||
return errors.New("trying to issue more than available")
|
||||
}
|
||||
}
|
||||
break
|
||||
default:
|
||||
|
@ -1942,6 +1949,16 @@ func (bc *Blockchain) GetScriptHashesForVerifying(t *transaction.Transaction) ([
|
|||
case transaction.EnrollmentType:
|
||||
etx := t.Data.(*transaction.EnrollmentTX)
|
||||
hashes[etx.PublicKey.GetScriptHash()] = true
|
||||
case transaction.IssueType:
|
||||
for _, res := range refsAndOutsToResults(references, t.Outputs) {
|
||||
if res.Amount < 0 {
|
||||
asset, err := bc.dao.GetAssetState(res.AssetID)
|
||||
if asset == nil || err != nil {
|
||||
return nil, errors.New("invalid asset in issue tx")
|
||||
}
|
||||
hashes[asset.Issuer] = true
|
||||
}
|
||||
}
|
||||
case transaction.RegisterType:
|
||||
reg := t.Data.(*transaction.RegisterTX)
|
||||
hashes[reg.Owner.GetScriptHash()] = true
|
||||
|
|
|
@ -168,7 +168,7 @@ func (mp *Pool) Add(t *transaction.Transaction, fee Feer) error {
|
|||
}
|
||||
pItem.isLowPrio = fee.IsLowPriority(pItem.netFee)
|
||||
mp.lock.Lock()
|
||||
if !mp.verifyInputs(t) {
|
||||
if !mp.checkTxConflicts(t) {
|
||||
mp.lock.Unlock()
|
||||
return ErrConflict
|
||||
}
|
||||
|
@ -329,24 +329,39 @@ func (mp *Pool) GetVerifiedTransactions() []TxWithFee {
|
|||
return t
|
||||
}
|
||||
|
||||
// verifyInputs is an internal unprotected version of Verify.
|
||||
func (mp *Pool) verifyInputs(tx *transaction.Transaction) bool {
|
||||
for i := range tx.Inputs {
|
||||
n := findIndexForInput(mp.inputs, &tx.Inputs[i])
|
||||
if n < len(mp.inputs) && *mp.inputs[n] == tx.Inputs[i] {
|
||||
return false
|
||||
// areInputsInPool tries to find inputs in a given sorted pool and returns true
|
||||
// if it finds any.
|
||||
func areInputsInPool(inputs []transaction.Input, pool []*transaction.Input) bool {
|
||||
for i := range inputs {
|
||||
n := findIndexForInput(pool, &inputs[i])
|
||||
if n < len(pool) && *pool[n] == inputs[i] {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if tx.Type == transaction.ClaimType {
|
||||
return false
|
||||
}
|
||||
|
||||
// checkTxConflicts is an internal unprotected version of Verify.
|
||||
func (mp *Pool) checkTxConflicts(tx *transaction.Transaction) bool {
|
||||
if areInputsInPool(tx.Inputs, mp.inputs) {
|
||||
return false
|
||||
}
|
||||
switch tx.Type {
|
||||
case transaction.ClaimType:
|
||||
claim := tx.Data.(*transaction.ClaimTX)
|
||||
for i := range claim.Claims {
|
||||
n := findIndexForInput(mp.claims, &claim.Claims[i])
|
||||
if n < len(mp.claims) && *mp.claims[n] == claim.Claims[i] {
|
||||
if areInputsInPool(claim.Claims, mp.claims) {
|
||||
return false
|
||||
}
|
||||
case transaction.IssueType:
|
||||
// It's a hack, because technically we could check for
|
||||
// available asset amount, but these transactions are so rare
|
||||
// that no one really cares about this restriction.
|
||||
for i := range mp.verifiedTxes {
|
||||
if mp.verifiedTxes[i].txn.Type == transaction.IssueType {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -356,5 +371,5 @@ func (mp *Pool) verifyInputs(tx *transaction.Transaction) bool {
|
|||
func (mp *Pool) Verify(tx *transaction.Transaction) bool {
|
||||
mp.lock.RLock()
|
||||
defer mp.lock.RUnlock()
|
||||
return mp.verifyInputs(tx)
|
||||
return mp.checkTxConflicts(tx)
|
||||
}
|
||||
|
|
|
@ -177,6 +177,31 @@ func TestMemPoolVerifyClaims(t *testing.T) {
|
|||
require.Error(t, mp.Add(tx3, &FeerStub{}))
|
||||
}
|
||||
|
||||
func TestMemPoolVerifyIssue(t *testing.T) {
|
||||
mp := NewMemPool(50)
|
||||
tx1 := newIssueTX()
|
||||
require.Equal(t, true, mp.Verify(tx1))
|
||||
require.NoError(t, mp.Add(tx1, &FeerStub{}))
|
||||
|
||||
tx2 := newIssueTX()
|
||||
require.Equal(t, false, mp.Verify(tx2))
|
||||
require.Error(t, mp.Add(tx2, &FeerStub{}))
|
||||
}
|
||||
|
||||
func newIssueTX() *transaction.Transaction {
|
||||
return &transaction.Transaction{
|
||||
Type: transaction.IssueType,
|
||||
Data: &transaction.IssueTX{},
|
||||
Outputs: []transaction.Output{
|
||||
transaction.Output{
|
||||
AssetID: random.Uint256(),
|
||||
Amount: util.Fixed8FromInt64(42),
|
||||
ScriptHash: random.Uint160(),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func newMinerTX(i uint32) *transaction.Transaction {
|
||||
return &transaction.Transaction{
|
||||
Type: transaction.MinerType,
|
||||
|
|
Loading…
Reference in a new issue