/
custom_tx.go
174 lines (155 loc) · 4.33 KB
/
custom_tx.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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*---------------------------------------------------------------------------------------------
* Copyright (c) IBAX. All rights reserved.
* See LICENSE in the project root for license information.
*--------------------------------------------------------------------------------------------*/
package types
import (
"errors"
"fmt"
"regexp"
"strings"
"github.com/shopspring/decimal"
log "github.com/sirupsen/logrus"
"github.com/vmihailenco/msgpack/v5"
"github.com/IBAX-io/go-ibax/packages/common/crypto"
"github.com/IBAX-io/go-ibax/packages/conf"
"github.com/IBAX-io/go-ibax/packages/consts"
"github.com/IBAX-io/go-ibax/packages/converter"
)
// Transaction types.
const (
FirstBlockTxType = iota + 1
StopNetworkTxType
SmartContractTxType
DelayTxType
UtxoTxType
TransferSelfTxType
)
// FirstBlock is the header of first block transaction
type FirstBlock struct {
KeyID int64
Time int64
PublicKey []byte
NodePublicKey []byte
StopNetworkCertBundle []byte
Test int64
PrivateBlockchain uint64
}
func (t *FirstBlock) TxType() byte { return FirstBlockTxType }
type StopNetwork struct {
KeyID int64
Time int64
StopNetworkCert []byte
}
func (t *StopNetwork) TxType() byte { return StopNetworkTxType }
// Header is contain header data
type Header struct {
ID int
EcosystemID int64
KeyID int64
Time int64
NetworkID int64
PublicKey []byte
}
type TransferSelf struct {
Value string
Source string
Target string
}
// UTXO Transfer
type UTXO struct {
ToID int64
Value string
Comment string
}
// SmartTransaction is storing smart contract data
type SmartTransaction struct {
*Header
MaxSum string
PayOver string
Lang string
Expedite string
SignedBy int64
TransferSelf *TransferSelf
UTXO *UTXO
Params map[string]any
}
func (s *SmartTransaction) TxType() byte {
if s.TransferSelf != nil {
return TransferSelfTxType
}
if s.UTXO != nil {
return UtxoTxType
}
return SmartContractTxType
}
func (s *SmartTransaction) WithPrivate(privateKey []byte, internal bool) error {
var (
publicKey []byte
err error
)
if publicKey, err = crypto.PrivateToPublic(privateKey); err != nil {
log.WithFields(log.Fields{"type": consts.CryptoError, "error": err}).Error("converting node private key to public")
return err
}
s.PublicKey = publicKey
if internal {
s.SignedBy = crypto.Address(publicKey)
}
if s.NetworkID != conf.Config.LocalConf.NetworkID {
return fmt.Errorf("error networkid invalid")
}
return nil
}
func (s *SmartTransaction) Unmarshal(buffer []byte) error {
return msgpack.Unmarshal(buffer, s)
}
func (s *SmartTransaction) Marshal() ([]byte, error) {
return msgpack.Marshal(s)
}
func (t SmartTransaction) Hash() ([]byte, error) {
b, err := t.Marshal()
if err != nil {
return nil, err
}
return crypto.DoubleHash(b), nil
}
func (txSmart *SmartTransaction) Validate() error {
if len(txSmart.Expedite) > 0 {
expedite, err := decimal.NewFromString(txSmart.Expedite)
if err != nil {
return fmt.Errorf("wrong expedite format")
}
if expedite.LessThan(decimal.Zero) {
return fmt.Errorf("expedite fee must be greater than 0")
}
}
if len(strings.TrimSpace(txSmart.Lang)) > 2 {
return fmt.Errorf(`localization size is greater than 2`)
}
if len(txSmart.MaxSum) > 0 && converter.StrToInt64(txSmart.MaxSum) <= 0 {
return fmt.Errorf(`maxsum must be greater than 0`)
}
if txSmart.NetworkID != conf.Config.LocalConf.NetworkID {
return fmt.Errorf("error networkid invalid")
}
if txSmart.TransferSelf != nil {
if ok, _ := regexp.MatchString("^\\d+$", txSmart.TransferSelf.Value); !ok {
return errors.New("error TransferSelf Value must be a positive integer")
}
if value, err := decimal.NewFromString(txSmart.TransferSelf.Value); err != nil || value.LessThanOrEqual(decimal.Zero) {
return errors.New("error TransferSelf Value must be greater than zero")
}
return nil
}
if txSmart.UTXO != nil {
if ok, _ := regexp.MatchString("^\\d+$", txSmart.UTXO.Value); !ok {
return errors.New("error UTXO Value must be a positive integer")
}
if value, err := decimal.NewFromString(txSmart.UTXO.Value); err != nil || value.LessThanOrEqual(decimal.Zero) {
return errors.New("error UTXO Value must be greater than zero")
}
return nil
}
return nil
}