• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vocdoni / vocdoni-node / 13793199355

11 Mar 2025 04:28PM UTC coverage: 62.51% (-0.03%) from 62.542%
13793199355

Pull #1405

github

p4u
vochain: allow faucet package on NewProcessTx

Signed-off-by: p4u <pau@dabax.net>
Pull Request #1405: vochain: allow faucet package on NewProcessTx

18 of 27 new or added lines in 3 files covered. (66.67%)

19 existing lines in 3 files now uncovered.

16832 of 26927 relevant lines covered (62.51%)

37950.15 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

42.16
/vochain/transaction/account_tx.go
1
package transaction
2

3
import (
4
        "bytes"
5
        "errors"
6
        "fmt"
7

8
        "github.com/ethereum/go-ethereum/common"
9
        "go.vocdoni.io/dvote/crypto/ethereum"
10
        "go.vocdoni.io/dvote/tree/arbo"
11
        "go.vocdoni.io/dvote/types"
12
        vstate "go.vocdoni.io/dvote/vochain/state"
13
        "go.vocdoni.io/dvote/vochain/transaction/vochaintx"
14
        "go.vocdoni.io/proto/build/go/models"
15
)
16

17
// CreateAccountTxCheck checks if an account creation tx is valid
18
func (t *TransactionHandler) CreateAccountTxCheck(vtx *vochaintx.Tx) error {
689✔
19
        if vtx == nil || vtx.SignedBody == nil || vtx.Signature == nil || vtx.Tx == nil {
689✔
20
                return ErrNilTx
×
21
        }
×
22
        tx := vtx.Tx.GetSetAccount()
689✔
23
        if tx == nil {
689✔
24
                return fmt.Errorf("invalid tx")
×
25
        }
×
26
        if tx.Txtype != models.TxType_CREATE_ACCOUNT {
689✔
27
                return fmt.Errorf("invalid tx type, expected %s, got %s", models.TxType_CREATE_ACCOUNT, tx.Txtype)
×
28
        }
×
29
        // check account does not exist
30
        pubKey, err := ethereum.PubKeyFromSignature(vtx.SignedBody, vtx.Signature)
689✔
31
        if err != nil {
689✔
32
                return fmt.Errorf("cannot extract public key from vtx.Signature: %w", err)
×
33
        }
×
34
        txSenderAddress, err := ethereum.AddrFromPublicKey(pubKey)
689✔
35
        if err != nil {
689✔
36
                return fmt.Errorf("cannot extract address from public key: %w", err)
×
37
        }
×
38
        txSenderAcc, err := t.state.GetAccount(txSenderAddress, false)
689✔
39
        if err != nil {
689✔
40
                return fmt.Errorf("cannot get account: %w", err)
×
41
        }
×
42
        if txSenderAcc != nil {
689✔
43
                return vstate.ErrAccountAlreadyExists
×
44
        }
×
45

46
        infoURI := tx.GetInfoURI()
689✔
47
        if len(infoURI) > types.MaxURLLength {
689✔
48
                return ErrInvalidURILength
×
49
        }
×
50
        if err := vstate.CheckDuplicateDelegates(tx.GetDelegates(), &txSenderAddress); err != nil {
689✔
51
                return fmt.Errorf("invalid delegates: %w", err)
×
52
        }
×
53
        txCost, err := t.state.TxBaseCost(models.TxType_CREATE_ACCOUNT, false)
689✔
54
        if err != nil {
689✔
55
                return fmt.Errorf("cannot get tx cost: %w", err)
×
56
        }
×
57
        // Check the faucet package
58
        canPayForTx, err := t.checkFaucetPackageAndTransfer(tx.FaucetPackage, txCost, txSenderAddress, vtx.TxID[:], false)
689✔
59
        if err != nil {
697✔
60
                return err
8✔
61
        }
8✔
62
        if !canPayForTx {
682✔
63
                return fmt.Errorf("faucet package is not enough for paying for the transaction cost")
1✔
64
        }
1✔
65
        return nil
680✔
66
}
67

68
// SetAccountDelegateTxCheck checks if a SetAccountDelegateTx and its data are valid
69
func (t *TransactionHandler) SetAccountDelegateTxCheck(vtx *vochaintx.Tx) error {
7✔
70
        if vtx == nil || vtx.Signature == nil || vtx.SignedBody == nil || vtx.Tx == nil {
7✔
71
                return ErrNilTx
×
72
        }
×
73
        tx := vtx.Tx.GetSetAccount()
7✔
74
        if tx == nil {
7✔
75
                return fmt.Errorf("invalid tx")
×
76
        }
×
77
        if tx.Txtype != models.TxType_ADD_DELEGATE_FOR_ACCOUNT &&
7✔
78
                tx.Txtype != models.TxType_DEL_DELEGATE_FOR_ACCOUNT {
7✔
79
                return fmt.Errorf("invalid tx type")
×
80
        }
×
81
        if len(tx.Delegates) == 0 {
7✔
82
                return fmt.Errorf("invalid delegates")
×
83
        }
×
84

85
        txSenderAccount, txSenderAddr, err := t.checkAccountCanPayCost(tx.Txtype, vtx, 0)
7✔
86
        if err != nil {
7✔
87
                return err
×
88
        }
×
89
        if err := vstate.CheckDuplicateDelegates(tx.Delegates, txSenderAddr); err != nil {
8✔
90
                return fmt.Errorf("checkDuplicateDelegates: %w", err)
1✔
91
        }
1✔
92

93
        switch tx.Txtype {
6✔
94
        case models.TxType_ADD_DELEGATE_FOR_ACCOUNT:
3✔
95
                for _, delegate := range tx.Delegates {
6✔
96
                        delegateAddress := common.BytesToAddress(delegate)
3✔
97
                        if txSenderAccount.IsDelegate(delegateAddress) {
4✔
98
                                return fmt.Errorf("delegate %s already exists", delegateAddress)
1✔
99
                        }
1✔
100
                }
101
                return nil
2✔
102
        case models.TxType_DEL_DELEGATE_FOR_ACCOUNT:
3✔
103
                for _, delegate := range tx.Delegates {
6✔
104
                        delegateAddress := common.BytesToAddress(delegate)
3✔
105
                        if !txSenderAccount.IsDelegate(delegateAddress) {
4✔
106
                                return fmt.Errorf("delegate %s does not exist", delegateAddress)
1✔
107
                        }
1✔
108
                }
109
                return nil
2✔
110
        default:
×
111
                // should never happen
×
112
                return fmt.Errorf("invalid tx type")
×
113
        }
114
}
115

116
// SetAccountInfoTxCheck checks if a set account info tx is valid
117
func (t *TransactionHandler) SetAccountInfoTxCheck(vtx *vochaintx.Tx) error {
30✔
118
        if vtx == nil || vtx.Signature == nil || vtx.SignedBody == nil || vtx.Tx == nil {
30✔
119
                return ErrNilTx
×
120
        }
×
121
        tx := vtx.Tx.GetSetAccount()
30✔
122
        if tx == nil {
30✔
123
                return fmt.Errorf("invalid transaction")
×
124
        }
×
125
        txSenderAccount, txSenderAddress, err := t.checkAccountCanPayCost(models.TxType_SET_ACCOUNT_INFO_URI, vtx, 0)
30✔
126
        if err != nil {
32✔
127
                return err
2✔
128
        }
2✔
129
        txAccountAddress := common.BytesToAddress(tx.GetAccount())
28✔
130
        if txAccountAddress == (common.Address{}) {
34✔
131
                txAccountAddress = *txSenderAddress
6✔
132
        }
6✔
133
        // check info URI
134
        infoURI := tx.GetInfoURI()
28✔
135
        if len(infoURI) == 0 || len(infoURI) > types.MaxURLLength {
30✔
136
                return fmt.Errorf("invalid URI, cannot be empty")
2✔
137
        }
2✔
138
        if bytes.Equal(txSenderAddress.Bytes(), txAccountAddress.Bytes()) {
49✔
139
                if infoURI == txSenderAccount.InfoURI {
23✔
140
                        return fmt.Errorf("invalid URI, must be different")
×
141
                }
×
142
                return nil
23✔
143
        }
144
        // if txSender != txAccount only delegate operations
145
        // get tx account Account
146
        txAccountAccount, err := t.state.GetAccount(txAccountAddress, false)
3✔
147
        if err != nil {
3✔
148
                return fmt.Errorf("cannot get tx account: %w", err)
×
149
        }
×
150
        if txAccountAccount == nil {
3✔
151
                return vstate.ErrAccountNotExist
×
152
        }
×
153
        if infoURI == txAccountAccount.InfoURI {
3✔
154
                return fmt.Errorf("invalid URI, must be different")
×
155
        }
×
156
        // check if delegate
157
        if !txAccountAccount.IsDelegate(*txSenderAddress) {
4✔
158
                return fmt.Errorf("tx sender is not a delegate")
1✔
159
        }
1✔
160
        return nil
2✔
161
}
162

163
// DelSIKTxCheck checks if a delete SIK tx is valid
164
func (t *TransactionHandler) DelSIKTxCheck(vtx *vochaintx.Tx) (common.Address, error) {
×
165
        if vtx == nil || vtx.Signature == nil || vtx.SignedBody == nil || vtx.Tx == nil {
×
166
                return common.Address{}, ErrNilTx
×
167
        }
×
168
        tx := vtx.Tx.GetDelSIK()
×
169
        if tx == nil {
×
170
                return common.Address{}, fmt.Errorf("invalid transaction")
×
171
        }
×
172
        // get the pubkey from the tx signature
173
        pubKey, err := ethereum.PubKeyFromSignature(vtx.SignedBody, vtx.Signature)
×
174
        if err != nil {
×
175
                return common.Address{}, fmt.Errorf("cannot extract public key from vtx.Signature: %w", err)
×
176
        }
×
177
        // get the account address from the pubkey
178
        txAddress, err := ethereum.AddrFromPublicKey(pubKey)
×
179
        if err != nil {
×
180
                return common.Address{}, fmt.Errorf("cannot extract address from public key: %w", err)
×
181
        }
×
182
        // check if the address is already registered
183
        if _, err := t.state.GetAccount(txAddress, false); err != nil {
×
184
                return common.Address{}, fmt.Errorf("cannot get tx account: %w", err)
×
185
        }
×
186
        // check if the address already has a registered SIK
187
        currentSIK, err := t.state.SIKFromAddress(txAddress)
×
188
        if err != nil {
×
189
                return common.Address{}, fmt.Errorf("cannot get current address SIK: %w", err)
×
190
        }
×
191
        // check that the registered SIK is still valid
192
        if !currentSIK.Valid() {
×
193
                return common.Address{}, fmt.Errorf("the SIK has already been deleted")
×
194
        }
×
195
        return txAddress, nil
×
196
}
197

198
// SetSIKTxCheck checks if a set SIK tx is valid and it is if the current
199
// address has not a SIK registered or the SIK registered had been already
200
// deleted.
201
func (t *TransactionHandler) SetSIKTxCheck(vtx *vochaintx.Tx) (common.Address, vstate.SIK, error) {
×
202
        if vtx == nil || vtx.Signature == nil || vtx.SignedBody == nil || vtx.Tx == nil {
×
203
                return common.Address{}, nil, ErrNilTx
×
204
        }
×
205
        tx := vtx.Tx.GetSetSIK()
×
206
        if tx == nil {
×
207
                return common.Address{}, nil, fmt.Errorf("invalid transaction")
×
208
        }
×
NEW
209
        _, txAddress, err := t.checkAccountCanPayCost(models.TxType_SET_ACCOUNT_SIK, vtx, 0)
×
210
        if err != nil {
×
211
                return common.Address{}, nil, err
×
212
        }
×
213
        newSIK := vtx.Tx.GetSetSIK().GetSIK()
×
214
        if newSIK == nil {
×
215
                return common.Address{}, nil, fmt.Errorf("no sik value provided")
×
216
        }
×
217
        // check if the address already has invalidated sik to ensure that it is
218
        // not updated after reach the correct height to avoid double voting
219
        if currentSIK, err := t.state.SIKFromAddress(*txAddress); err == nil {
×
220
                maxEndBlock, err := t.state.ProcessBlockRegistry.MaxEndBlock(t.state.CurrentHeight())
×
221
                if err != nil {
×
222
                        if errors.Is(err, arbo.ErrKeyNotFound) {
×
223
                                return *txAddress, newSIK, nil
×
224
                        }
×
225
                        return common.Address{}, nil, err
×
226
                }
227
                if height := currentSIK.DecodeInvalidatedHeight(); height >= maxEndBlock {
×
228
                        return *txAddress, nil, fmt.Errorf("the sik could not be changed yet")
×
229
                }
×
230
        }
231
        return *txAddress, newSIK, nil
×
232
}
233

234
// RegisterSIKTxCheck checks if the provided RegisterSIKTx is valid ensuring
235
// that the proof included on it is valid for the address of the transaction
236
// signer.
237
func (t *TransactionHandler) RegisterSIKTxCheck(vtx *vochaintx.Tx) (common.Address, vstate.SIK, []byte, bool, error) {
77✔
238
        if vtx == nil || vtx.Signature == nil || vtx.SignedBody == nil || vtx.Tx == nil {
77✔
239
                return common.Address{}, nil, nil, false, ErrNilTx
×
240
        }
×
241
        // parse transaction
242
        tx := vtx.Tx.GetRegisterSIK()
77✔
243
        if tx == nil {
77✔
244
                return common.Address{}, nil, nil, false, fmt.Errorf("invalid transaction")
×
245
        }
×
246
        // get the SIK provided
247
        newSIK := tx.GetSIK()
77✔
248
        if newSIK == nil {
77✔
249
                return common.Address{}, nil, nil, false, fmt.Errorf("no sik value provided")
×
250
        }
×
251
        // get census proof and election information provided
252
        censusProof := tx.GetCensusProof()
77✔
253
        if censusProof == nil {
77✔
254
                return common.Address{}, nil, nil, false, fmt.Errorf("no proof provided")
×
255
        }
×
256
        pid := tx.GetElectionId()
77✔
257
        if pid == nil {
77✔
258
                return common.Address{}, nil, nil, false, fmt.Errorf("no election provided")
×
259
        }
×
260
        // get the pubkey from the tx signature
261
        pubKey, err := ethereum.PubKeyFromSignature(vtx.SignedBody, vtx.Signature)
77✔
262
        if err != nil {
77✔
263
                return common.Address{}, nil, nil, false, fmt.Errorf("cannot extract public key from vtx.Signature: %w", err)
×
264
        }
×
265
        // get the account address from the pubkey
266
        txAddress, err := ethereum.AddrFromPublicKey(pubKey)
77✔
267
        if err != nil {
77✔
268
                return common.Address{}, nil, nil, false, fmt.Errorf("cannot extract address from public key: %w", err)
×
269
        }
×
270
        // check if the address is already registered
271
        if _, err := t.state.GetAccount(txAddress, false); err != nil {
77✔
272
                return common.Address{}, nil, nil, false, fmt.Errorf("cannot get the account for the tx address: %w", err)
×
273
        }
×
274
        // check if the address already has a registered SIK
275
        if _, err := t.state.SIKFromAddress(txAddress); err == nil {
77✔
276
                return txAddress, nil, nil, false, fmt.Errorf("this address already has a SIK")
×
277
        }
×
278
        // get the process data by its ID
279
        process, err := t.state.Process(pid, false)
77✔
280
        if err != nil {
77✔
281
                return common.Address{}, nil, nil, false, fmt.Errorf("error getting the process info: %w", err)
×
282
        }
×
283
        // ensure that the process is in READY state
284
        if process.GetStatus() != models.ProcessStatus_READY {
77✔
285
                return common.Address{}, nil, nil, false, fmt.Errorf("this process is not READY")
×
286
        }
×
287
        // ensure that the process is anonymous and the census origin is of the type OFF_CHAIN_TREE
288
        if process.CensusOrigin != models.CensusOrigin_OFF_CHAIN_TREE_WEIGHTED && process.CensusOrigin != models.CensusOrigin_OFF_CHAIN_TREE {
77✔
289
                return common.Address{}, nil, nil, false, fmt.Errorf("invalid census origin for register SIK transaction")
×
290
        }
×
291
        if !process.EnvelopeType.Anonymous {
77✔
292
                return common.Address{}, nil, nil, false, fmt.Errorf("only anonymous elections are allowed for register SIK transaction")
×
293
        }
×
294
        // check if the number of registered SIK via RegisterSIKTx associated to
295
        // this process reaches the MaxCensusSize
296
        numberOfRegisterSIK, err := t.state.CountRegisterSIK(pid)
77✔
297
        if err != nil {
77✔
298
                return common.Address{}, nil, nil, false, fmt.Errorf("error getting the counter of RegisterSIKTx: %w", err)
×
299
        }
×
300
        if process.GetMaxCensusSize() <= uint64(numberOfRegisterSIK) {
78✔
301
                return common.Address{}, nil, nil, false, fmt.Errorf("process MaxCensusSize reached")
1✔
302
        }
1✔
303
        // we need to set the anonymous flag to false to verify the signature proof
304
        process.EnvelopeType.Anonymous = false
76✔
305
        defer func() {
152✔
306
                process.EnvelopeType.Anonymous = true
76✔
307
        }()
76✔
308
        // verify the proof for the transaction signer address
309
        valid, _, err := VerifyProof(process, &models.VoteEnvelope{ProcessId: pid, Proof: censusProof}, vstate.NewVoterID(vstate.VoterIDTypeZkSnark, txAddress.Bytes()))
76✔
310
        if err != nil {
76✔
311
                return common.Address{}, nil, nil, false, fmt.Errorf("error verifying the proof: %w", err)
×
312
        }
×
313
        if !valid {
76✔
314
                return common.Address{}, nil, nil, false, fmt.Errorf("proof not valid: %x", process.CensusRoot)
×
315
        }
×
316
        return txAddress, newSIK, pid, process.GetTempSIKs(), nil
76✔
317
}
318

319
// SetAccountValidatorTxCheck upgrades an account to a validator.
320
func (t *TransactionHandler) SetAccountValidatorTxCheck(vtx *vochaintx.Tx) error {
×
321
        if vtx == nil || vtx.Signature == nil || vtx.SignedBody == nil || vtx.Tx == nil {
×
322
                return ErrNilTx
×
323
        }
×
NEW
324
        _, _, err := t.checkAccountCanPayCost(models.TxType_SET_ACCOUNT_VALIDATOR, vtx, 0)
×
325
        if err != nil {
×
326
                return err
×
327
        }
×
328
        validatorPubKey := vtx.Tx.GetSetAccount().GetPublicKey()
×
329
        if validatorPubKey == nil {
×
330
                return fmt.Errorf("invalid nil public key")
×
331
        }
×
332
        validatorAddress, err := ethereum.AddrFromPublicKey(validatorPubKey)
×
333
        if err != nil {
×
334
                return fmt.Errorf("cannot extract address from public key: %w", err)
×
335
        }
×
336
        validatorAccount, err := t.state.Validator(validatorAddress, false)
×
337
        if err != nil {
×
338
                return fmt.Errorf("cannot get validator: %w", err)
×
339
        }
×
340
        if validatorAccount != nil {
×
341
                return fmt.Errorf("account is already a validator")
×
342
        }
×
343
        return nil
×
344
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc