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]
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
}
}
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{}
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 {
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
}
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)
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
}