-
Notifications
You must be signed in to change notification settings - Fork 28
/
SendTx.go
137 lines (122 loc) · 3.39 KB
/
SendTx.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package tx
import (
"bytes"
"errors"
"fmt"
"github.com/QOSGroup/qbase/baseabci"
"github.com/QOSGroup/qbase/context"
"github.com/QOSGroup/qbase/example/basecoin/types"
"github.com/QOSGroup/qbase/txs"
btypes "github.com/QOSGroup/qbase/types"
)
type SendTx struct {
From btypes.AccAddress `json:"from"`
To btypes.AccAddress `json:"to"`
Coin btypes.BaseCoin `json:"coin"`
}
var _ txs.ITx = (*SendTx)(nil)
func NewSendTx(from btypes.AccAddress, to btypes.AccAddress, coin btypes.BaseCoin) SendTx {
return SendTx{From: from, To: to, Coin: coin}
}
func (tx *SendTx) ValidateData(ctx context.Context) error {
if tx.From.Empty() || tx.To.Empty() || btypes.NewInt(0).GT(tx.Coin.Amount) {
return errors.New("SendTx ValidateData error")
}
// 查询发送方账户信息
mapper := baseabci.GetAccountMapper(ctx)
fromAcc := mapper.GetAccount(tx.From).(*types.AppAccount)
if fromAcc.AccountAddress == nil {
return errors.New("SendTx ValidateData error")
}
// 校验发送金额
exists := false
for _, c := range fromAcc.Coins {
if c.Name == tx.Coin.Name {
exists = true
if c.Amount.LT(tx.Coin.Amount) {
return fmt.Errorf("coin %s has not much amount %d", c.Name, c.Amount.Int64())
}
}
}
if !exists {
return errors.New("sender does not have all the coins")
}
return nil
}
func (tx *SendTx) Exec(ctx context.Context) (result btypes.Result, crossTxQcps *txs.TxQcp) {
result = btypes.Result{
Code: btypes.CodeOK,
}
// 查询发送方账户信息
mapper := baseabci.GetAccountMapper(ctx)
fromAcc := mapper.GetAccount(tx.From).(*types.AppAccount)
if fromAcc.AccountAddress == nil {
result.Code = btypes.CodeInternal
return
}
// 校验发送金额
exists := false
for _, c := range fromAcc.Coins {
if c.Name == tx.Coin.Name {
exists = true
if c.Amount.LT(tx.Coin.Amount) {
result.Code = btypes.CodeInternal
result.Log = fmt.Sprintf("coin %s has not much amount %d", c.Name, c.Amount.Int64())
return
}
}
}
if !exists {
result.Code = btypes.CodeInternal
return
}
// 查询接收方账户信息
toAcc := mapper.GetAccount(tx.To)
if toAcc == nil {
toAcc = mapper.NewAccountWithAddress(tx.To).(*types.AppAccount)
}
toAccount := toAcc.(*types.AppAccount)
// 更新账户状态
for i, c := range fromAcc.Coins {
if c.Name == tx.Coin.Name {
fromAcc.Coins[i].Amount = c.Amount.Add(tx.Coin.Amount.Neg())
}
}
mapper.SetAccount(fromAcc)
exists = false
for i, c := range toAccount.Coins {
if c.Name == tx.Coin.Name {
exists = true
toAccount.Coins[i].Amount = c.Amount.Add(tx.Coin.Amount)
}
}
if !exists {
toAccount.Coins = append(toAccount.Coins, &(tx.Coin))
}
mapper.SetAccount(toAccount)
result.Events = result.Events.AppendEvents(btypes.Events{
btypes.NewEvent(
btypes.EventTypeMessage,
btypes.NewAttribute(btypes.EventTypeMessage, types.EventActionSend),
btypes.NewAttribute(types.AttributeKeySender, fromAcc.GetAddress().String()),
btypes.NewAttribute(types.AttributeKeyReceiver, toAcc.GetAddress().String()),
),
})
return
}
func (tx *SendTx) GetSigner() []btypes.AccAddress {
return []btypes.AccAddress{tx.From}
}
func (tx *SendTx) CalcGas() btypes.BigInt {
return btypes.ZeroInt()
}
func (tx *SendTx) GetGasPayer() btypes.AccAddress {
return tx.From
}
func (tx *SendTx) GetSignData() []byte {
var buf bytes.Buffer
buf.Write(tx.From.Bytes())
buf.Write(tx.To.Bytes())
buf.Write([]byte(tx.Coin.String()))
return buf.Bytes()
}