9 "github.com/bytom/account"
10 "github.com/bytom/blockchain/query"
11 "github.com/bytom/crypto/sha3pool"
12 "github.com/bytom/protocol/bc/types"
16 //UnconfirmedTxPrefix is txpool unconfirmed transactions prefix
17 UnconfirmedTxPrefix = "UTXS:"
20 func calcUnconfirmedTxKey(formatKey string) []byte {
21 return []byte(UnconfirmedTxPrefix + formatKey)
24 func (w *Wallet) buildAnnotatedUnconfirmedTx(tx *types.Tx) *query.AnnotatedTx {
25 annotatedTx := &query.AnnotatedTx{
27 Timestamp: uint64(time.Now().Unix()),
28 Inputs: make([]*query.AnnotatedInput, 0, len(tx.Inputs)),
29 Outputs: make([]*query.AnnotatedOutput, 0, len(tx.Outputs)),
30 Size: tx.SerializedSize,
33 for i := range tx.Inputs {
34 annotatedTx.Inputs = append(annotatedTx.Inputs, w.BuildAnnotatedInput(tx, uint32(i)))
36 for i := range tx.Outputs {
37 annotatedTx.Outputs = append(annotatedTx.Outputs, w.BuildAnnotatedOutput(tx, i))
43 // checkRelatedTransaction check related unconfirmed transaction.
44 func (w *Wallet) checkRelatedTransaction(tx *types.Tx) bool {
45 for _, v := range tx.Outputs {
47 sha3pool.Sum256(hash[:], v.ControlProgram)
48 if bytes := w.DB.Get(account.ContractKey(hash)); bytes != nil {
53 for _, v := range tx.Inputs {
54 outid, err := v.SpentOutputID()
58 if bytes := w.DB.Get(account.StandardUTXOKey(outid)); bytes != nil {
66 // SaveUnconfirmedTx save unconfirmed annotated transaction to the database
67 func (w *Wallet) SaveUnconfirmedTx(tx *types.Tx) error {
68 if !w.checkRelatedTransaction(tx) {
72 // annotate account and asset
73 annotatedTx := w.buildAnnotatedUnconfirmedTx(tx)
74 annotatedTxs := []*query.AnnotatedTx{}
75 annotatedTxs = append(annotatedTxs, annotatedTx)
76 annotateTxsAccount(annotatedTxs, w.DB)
78 rawTx, err := json.Marshal(annotatedTxs[0])
83 w.DB.Set(calcUnconfirmedTxKey(tx.ID.String()), rawTx)
87 // GetUnconfirmedTxByTxID get unconfirmed transaction by txID
88 func (w *Wallet) GetUnconfirmedTxByTxID(txID string) (*query.AnnotatedTx, error) {
89 annotatedTx := &query.AnnotatedTx{}
90 txInfo := w.DB.Get(calcUnconfirmedTxKey(txID))
92 return nil, fmt.Errorf("No transaction(tx_id=%s) from txpool", txID)
95 if err := json.Unmarshal(txInfo, annotatedTx); err != nil {
98 annotateTxsAsset(w, []*query.AnnotatedTx{annotatedTx})
100 return annotatedTx, nil
103 // SortByTimestamp implements sort.Interface for AnnotatedTx slices
104 type SortByTimestamp []*query.AnnotatedTx
106 func (a SortByTimestamp) Len() int { return len(a) }
107 func (a SortByTimestamp) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
108 func (a SortByTimestamp) Less(i, j int) bool { return a[i].Timestamp > a[j].Timestamp }
110 // GetUnconfirmedTxs get account unconfirmed transactions, filter transactions by accountID when accountID is not empty
111 func (w *Wallet) GetUnconfirmedTxs(accountID string) ([]*query.AnnotatedTx, error) {
112 annotatedTxs := []*query.AnnotatedTx{}
114 txIter := w.DB.IteratorPrefix([]byte(UnconfirmedTxPrefix))
115 defer txIter.Release()
117 annotatedTx := &query.AnnotatedTx{}
118 if err := json.Unmarshal(txIter.Value(), &annotatedTx); err != nil {
122 if accountID == "" || findTransactionsByAccount(annotatedTx, accountID) {
123 annotateTxsAsset(w, []*query.AnnotatedTx{annotatedTx})
124 annotatedTxs = append([]*query.AnnotatedTx{annotatedTx}, annotatedTxs...)
128 // sort SortByTimestamp by timestamp
129 sort.Sort(SortByTimestamp(annotatedTxs))
130 return annotatedTxs, nil