From 53784d9c76f1056423b57915f7e064a6f551100c Mon Sep 17 00:00:00 2001 From: wz Date: Thu, 16 May 2019 14:37:07 +0800 Subject: [PATCH] Add validate votetx (#64) * Add validate votetx * delete uint test * fix review * recover code * recover code * fix * fix --- protocol/bc/tx.go | 9 ++++++++ protocol/txpool.go | 15 +++++++++--- protocol/txpool_test.go | 58 +++++++++++++++++++++++++++++++++++++++++++++++ protocol/validation/tx.go | 50 +++++++++++++++++----------------------- 4 files changed, 100 insertions(+), 32 deletions(-) diff --git a/protocol/bc/tx.go b/protocol/bc/tx.go index cf5f763b..9b00d390 100644 --- a/protocol/bc/tx.go +++ b/protocol/bc/tx.go @@ -59,6 +59,15 @@ func (tx *Tx) CrossChainOutput(id Hash) (*CrossChainOutput, error) { return o, nil } +// Entry try to get the entry by given hash +func (tx *Tx) Entry(id Hash) (Entry, error) { + e, ok := tx.Entries[id] + if !ok || e == nil { + return nil, errors.Wrapf(ErrMissingEntry, "id %x", id.Bytes()) + } + return e, nil +} + // Spend try to get the spend entry by given hash func (tx *Tx) Spend(id Hash) (*Spend, error) { e, ok := tx.Entries[id] diff --git a/protocol/txpool.go b/protocol/txpool.go index 7d6bf9ff..957ab6af 100644 --- a/protocol/txpool.go +++ b/protocol/txpool.go @@ -277,12 +277,21 @@ func (tp *TxPool) addTransaction(txD *TxDesc) error { txD.Added = time.Now() tp.pool[tx.ID] = txD for _, id := range tx.ResultIds { - output, err := tx.IntraChainOutput(*id) + var assetID bc.AssetID + outputEntry, err := tx.Entry(*id) if err != nil { - // error due to it's a retirement, utxo doesn't care this output type so skip it + return err + } + switch output := outputEntry.(type) { + case *bc.IntraChainOutput: + assetID = *output.Source.Value.AssetId + case *bc.VoteOutput: + assetID = *output.Source.Value.AssetId + default: continue } - if !txD.StatusFail || *output.Source.Value.AssetId == *consensus.BTMAssetID { + + if !txD.StatusFail || assetID == *consensus.BTMAssetID { tp.utxo[*id] = tx } } diff --git a/protocol/txpool_test.go b/protocol/txpool_test.go index 9db8aa8c..05eff7f4 100644 --- a/protocol/txpool_test.go +++ b/protocol/txpool_test.go @@ -94,6 +94,19 @@ var testTxs = []*types.Tx{ types.NewIntraChainOutput(bc.NewAssetID([32]byte{0xa1}), 0, []byte{0x65}), }, }), + //tx7 + types.NewTx(types.TxData{ + SerializedSize: 150, + TimeRange: 0, + Inputs: []*types.TxInput{ + types.NewSpendInput(nil, bc.NewHash([32]byte{0x01}), *consensus.BTMAssetID, 1, 1, []byte{0x51}), + types.NewSpendInput(nil, bc.NewHash([32]byte{0x02}), bc.NewAssetID([32]byte{0xa1}), 4, 1, []byte{0x51}), + }, + Outputs: []*types.TxOutput{ + types.NewIntraChainOutput(*consensus.BTMAssetID, 1, []byte{0x6b}), + types.NewVoteOutput(bc.NewAssetID([32]byte{0xa1}), 4, []byte{0x61}, []byte("a8f410b9f7cd9ce352d215ed17c85559c351dc8d18ed89ad403ca28cfc423f612e04a1c9584f945c286c47ec1e5b8405c65ff56e31f44a2627aca4f77e03936f")), + }, + }), } type mockStore struct{} @@ -287,6 +300,51 @@ func TestAddTransaction(t *testing.T) { StatusFail: true, }, }, + { + before: &TxPool{ + pool: map[bc.Hash]*TxDesc{}, + utxo: map[bc.Hash]*types.Tx{}, + eventDispatcher: dispatcher, + }, + after: &TxPool{ + pool: map[bc.Hash]*TxDesc{ + testTxs[7].ID: { + Tx: testTxs[7], + StatusFail: false, + }, + }, + utxo: map[bc.Hash]*types.Tx{ + *testTxs[7].ResultIds[0]: testTxs[7], + *testTxs[7].ResultIds[1]: testTxs[7], + }, + }, + addTx: &TxDesc{ + Tx: testTxs[7], + StatusFail: false, + }, + }, + { + before: &TxPool{ + pool: map[bc.Hash]*TxDesc{}, + utxo: map[bc.Hash]*types.Tx{}, + eventDispatcher: dispatcher, + }, + after: &TxPool{ + pool: map[bc.Hash]*TxDesc{ + testTxs[7].ID: { + Tx: testTxs[7], + StatusFail: true, + }, + }, + utxo: map[bc.Hash]*types.Tx{ + *testTxs[7].ResultIds[0]: testTxs[7], + }, + }, + addTx: &TxDesc{ + Tx: testTxs[7], + StatusFail: true, + }, + }, } for i, c := range cases { diff --git a/protocol/validation/tx.go b/protocol/validation/tx.go index c12c04f3..1e2467b5 100644 --- a/protocol/validation/tx.go +++ b/protocol/validation/tx.go @@ -224,6 +224,13 @@ func checkValid(vs *validationState, e bc.Entry) (err error) { return errors.Wrap(err, "checking output source") } + case *bc.VoteOutput: + vs2 := *vs + vs2.sourcePos = 0 + if err = checkValidSrc(&vs2, e.Source); err != nil { + return errors.Wrap(err, "checking output source") + } + case *bc.Retirement: vs2 := *vs vs2.sourcePos = 0 @@ -417,6 +424,12 @@ func checkValidDest(vs *validationState, vd *bc.ValueDestination) error { } src = ref.Source + case *bc.VoteOutput: + if vd.Position != 0 { + return errors.Wrapf(ErrPosition, "invalid position %d for output destination", vd.Position) + } + src = ref.Source + case *bc.Retirement: if vd.Position != 0 { return errors.Wrapf(ErrPosition, "invalid position %d for retirement destination", vd.Position) @@ -465,45 +478,24 @@ func checkStandardTx(tx *bc.Tx, blockHeight uint64) error { continue } - intraChainSpentOutput, err := tx.IntraChainOutput(*spend.SpentOutputId) + code := []byte{} + outputEntry, err := tx.Entry(*spend.SpentOutputId) if err != nil { return err } - - if !segwit.IsP2WScript(intraChainSpentOutput.ControlProgram.Code) { - return ErrNotStandardTx - } - } - - for _, id := range tx.ResultIds { - e, ok := tx.Entries[*id] - if !ok { - return errors.Wrapf(bc.ErrMissingEntry, "id %x", id.Bytes()) - } - - var prog []byte - switch e := e.(type) { + switch output := outputEntry.(type) { case *bc.IntraChainOutput: - if *e.Source.Value.AssetId != *consensus.BTMAssetID { - continue - } - prog = e.ControlProgram.Code - - case *bc.CrossChainOutput: - if *e.Source.Value.AssetId != *consensus.BTMAssetID { - continue - } - prog = e.ControlProgram.Code - + code = output.ControlProgram.Code + case *bc.VoteOutput: + code = output.ControlProgram.Code default: - continue + return errors.Wrapf(bc.ErrEntryType, "entry %x has unexpected type %T", id.Bytes(), outputEntry) } - if !segwit.IsP2WScript(prog) { + if !segwit.IsP2WScript(code) { return ErrNotStandardTx } } - return nil } -- 2.11.0