Skip to content

Commit d4c01b5

Browse files
authored
596 multisig skeleton (#597)
* #596 add multisignature transaction body * #596 add constants for MultiSignature body fields * #596 add multisignature tx type skeleton * #596 add multisig tx type enum * #596 add command tools for generate multisignature tx and parsing any tx * #596 basic multisignature parsing functionality * #596 update schema commit * #596 add signature info * #596 update signature structure to use map * #596 adjust cmd tools to new multisig byte structure * #596 update multisig transaction bytes * #596 update schema
1 parent 7ed964b commit d4c01b5

File tree

15 files changed

+1008
-103
lines changed

15 files changed

+1008
-103
lines changed

cmd/main.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import (
77
"strings"
88
"time"
99

10+
"github.com/zoobc/zoobc-core/cmd/parser"
11+
1012
"github.com/spf13/cobra"
1113
"github.com/spf13/viper"
1214
"github.com/zoobc/zoobc-core/cmd/account"
@@ -48,6 +50,10 @@ func main() {
4850
Use: "generate",
4951
Short: "generate command is a parent command for generating stuffs",
5052
}
53+
parserCmd = &cobra.Command{
54+
Use: "parser",
55+
Short: "parse data to understandable struct",
56+
}
5157
)
5258

5359
sqliteDbInstance = database.NewSqliteDB()
@@ -67,9 +73,11 @@ func main() {
6773
rootCmd.AddCommand(generateCmd)
6874
rootCmd.AddCommand(genesisblock.Commands())
6975
rootCmd.AddCommand(rollback.Commands(sqliteDB))
76+
rootCmd.AddCommand(parserCmd)
7077
generateCmd.AddCommand(account.Commands())
7178
generateCmd.AddCommand(transaction.Commands(sqliteDB))
7279
generateCmd.AddCommand(block.Commands())
80+
parserCmd.AddCommand(parser.Commands())
7381
_ = rootCmd.Execute()
7482

7583
}

cmd/parser/cmd.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package parser
2+
3+
import (
4+
"encoding/hex"
5+
"fmt"
6+
"strconv"
7+
"strings"
8+
9+
"github.com/spf13/cobra"
10+
"github.com/zoobc/zoobc-core/common/transaction"
11+
)
12+
13+
var (
14+
/*
15+
Transaction Parser Command
16+
*/
17+
txParserCmd = &cobra.Command{
18+
Use: "tx",
19+
Short: "parse transaction from its hex representation",
20+
Long: "transaction parser to check the content of your transaction hex",
21+
}
22+
)
23+
24+
func init() {
25+
txParserCmd.Flags().StringVar(&parserTxHex, "transaction-hex", "", "hex string of the transaction bytes")
26+
txParserCmd.Flags().StringVar(&parserTxBytes, "transaction-bytes", "", "transaction bytes separated by `, `. eg:"+
27+
"--transaction-bytes='1, 222, 54, 12, 32'")
28+
}
29+
30+
func Commands() *cobra.Command {
31+
txParserCmd.Run = ParseTransaction
32+
return txParserCmd
33+
}
34+
35+
func ParseTransaction(*cobra.Command, []string) {
36+
var txBytes []byte
37+
if parserTxHex != "" {
38+
txBytes, _ = hex.DecodeString(parserTxHex)
39+
} else {
40+
txByteCharSlice := strings.Split(parserTxBytes, ", ")
41+
for _, v := range txByteCharSlice {
42+
byteValue, err := strconv.Atoi(v)
43+
if err != nil {
44+
panic("failed to parse transaction bytes")
45+
}
46+
txBytes = append(txBytes, byte(byteValue))
47+
}
48+
}
49+
tx, err := (&transaction.Util{}).ParseTransactionBytes(txBytes, false)
50+
if err != nil {
51+
panic("error parsing tx" + err.Error())
52+
}
53+
tx.TransactionBody, err = (&transaction.MultiSignatureTransaction{}).ParseBodyBytes(tx.TransactionBodyBytes)
54+
if err != nil {
55+
panic("error parsing tx body" + err.Error())
56+
}
57+
fmt.Printf("transaction:\n%v\n", tx)
58+
}

cmd/parser/const.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package parser
2+
3+
var (
4+
// txParser
5+
parserTxHex string
6+
parserTxBytes string
7+
)

cmd/transaction/cmd.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package transaction
22

33
import (
44
"database/sql"
5+
"fmt"
56
"time"
67

78
"github.com/spf13/cobra"
@@ -54,6 +55,12 @@ var (
5455
Short: "transaction sub command used to generate 'escrow approval' transaction",
5556
Long: "transaction sub command used to generate 'escrow approval' transaction. required transaction id and approval = true:false",
5657
}
58+
multiSigCmd = &cobra.Command{
59+
Use: "multi-signature",
60+
Short: "transaction sub command used to generate 'multi signature' transaction",
61+
Long: "transaction sub command used to generate 'multi signature' transaction that require multiple account to submit their signature " +
62+
"before it is valid to be executed",
63+
}
5764
)
5865

5966
func init() {
@@ -124,6 +131,18 @@ func init() {
124131
*/
125132
escrowApprovalCmd.Flags().Int64Var(&transactionID, "transaction-id", 0, "escrow approval body field which is int64")
126133
escrowApprovalCmd.Flags().BoolVar(&approval, "approval", false, "escrow approval body field which is bool")
134+
/*
135+
MultiSig Command
136+
*/
137+
multiSigCmd.Flags().StringSliceVar(&addresses, "addresses", []string{}, "list of participants "+
138+
"--addresses='address1,address2'")
139+
multiSigCmd.Flags().Int64Var(&nonce, "nonce", 0, "random number / access code for the multisig info")
140+
multiSigCmd.Flags().Uint32Var(&minSignature, "min-signature", 0, "minimum number of signature required for the transaction "+
141+
"to be valid")
142+
multiSigCmd.Flags().StringVar(&unsignedTxHex, "unsigned-transaction", "", "hex string of the unsigned transaction bytes")
143+
multiSigCmd.Flags().StringVar(&txHash, "transaction-hash", "", "hash of transaction being signed by address-signature list (hex)")
144+
multiSigCmd.Flags().StringSliceVar(&addressSignatures, "address-signatures", []string{}, "address-signature list "+
145+
"--address-signatures='address1-signature1,address2-signature2'")
127146
}
128147

129148
// Commands set TXGeneratorCommandsInstance that will used by whole commands
@@ -148,6 +167,8 @@ func Commands(sqliteDB *sql.DB) *cobra.Command {
148167
txCmd.AddCommand(removeAccountDatasetCmd)
149168
escrowApprovalCmd.Run = txGeneratorCommandsInstance.EscrowApprovalProcess()
150169
txCmd.AddCommand(escrowApprovalCmd)
170+
multiSigCmd.Run = txGeneratorCommandsInstance.MultiSignatureProcess()
171+
txCmd.AddCommand(multiSigCmd)
151172
return txCmd
152173
}
153174

@@ -258,3 +279,16 @@ func (*TXGeneratorCommands) EscrowApprovalProcess() RunCommand {
258279
PrintTx(GenerateSignedTxBytes(tx, senderSeed), outputType)
259280
}
260281
}
282+
283+
// MultiSignatureProcess for generate TX MultiSignature type
284+
func (*TXGeneratorCommands) MultiSignatureProcess() RunCommand {
285+
return func(ccmd *cobra.Command, args []string) {
286+
tx := GenerateBasicTransaction(senderSeed, version, timestamp, fee, recipientAccountAddress)
287+
tx = GeneratedMultiSignatureTransaction(tx, minSignature, nonce, unsignedTxHex, txHash, addressSignatures, addresses)
288+
if tx == nil {
289+
fmt.Printf("fail to generate transaction, please check the provided parameter")
290+
} else {
291+
PrintTx(GenerateSignedTxBytes(tx, senderSeed), outputType)
292+
}
293+
}
294+
}

cmd/transaction/const.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ var (
1212
"setupAccountDataset": {3, 0, 0, 0},
1313
"removeAccountDataset": {3, 1, 0, 0},
1414
"approvalEscrow": {4, 0, 0, 0},
15+
"multiSignature": {5, 0, 0, 0},
1516
}
1617
signature = &crypto.Signature{}
1718

@@ -46,4 +47,12 @@ var (
4647
// escrowApproval
4748
approval bool
4849
transactionID int64
50+
51+
// multiSignature
52+
unsignedTxHex string
53+
addressSignatures []string
54+
txHash string
55+
addresses []string
56+
nonce int64
57+
minSignature uint32
4958
)

cmd/transaction/generator.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ func GenerateSignedTxBytes(tx *model.Transaction, senderSeed string) []byte {
276276
senderSeed,
277277
)
278278
signedTxBytes, _ := transactionUtil.GetTransactionBytes(tx, true)
279+
fmt.Printf("signedBytes: %v\n", len(signedTxBytes))
279280
return signedTxBytes
280281
}
281282

@@ -324,3 +325,77 @@ func GenerateEscrowedTransaction(
324325
}
325326
return tx
326327
}
328+
329+
/*
330+
GeneratedMultiSignatureTransaction inject escrow. Need:
331+
1. unsignedTxHex
332+
2. signatures
333+
3. multisigInfo:
334+
- minSignature
335+
- nonce
336+
- addresses
337+
Invalid escrow validation when those fields has not set
338+
*/
339+
func GeneratedMultiSignatureTransaction(
340+
tx *model.Transaction,
341+
minSignature uint32,
342+
nonce int64,
343+
unsignedTxHex, txHash string,
344+
addressSignatures, addresses []string,
345+
) *model.Transaction {
346+
var (
347+
signatures = make(map[string][]byte)
348+
signatureInfo *model.SignatureInfo
349+
unsignedTx []byte
350+
multiSigInfo *model.MultiSignatureInfo
351+
err error
352+
)
353+
if minSignature > 0 && len(addresses) > 0 {
354+
multiSigInfo = &model.MultiSignatureInfo{
355+
MinimumSignatures: minSignature,
356+
Nonce: nonce,
357+
Addresses: addresses,
358+
}
359+
}
360+
if unsignedTxHex != "" {
361+
unsignedTx, err = hex.DecodeString(unsignedTxHex)
362+
if err != nil {
363+
return nil
364+
}
365+
}
366+
367+
if txHash != "" {
368+
transactionHash, err := hex.DecodeString(txHash)
369+
if err != nil {
370+
return nil
371+
}
372+
for _, v := range addressSignatures {
373+
asig := strings.Split(v, "-")
374+
if len(asig) < 2 {
375+
return nil
376+
}
377+
signature, err := hex.DecodeString(asig[1])
378+
if err != nil {
379+
return nil
380+
}
381+
signatures[asig[0]] = signature
382+
}
383+
signatureInfo = &model.SignatureInfo{
384+
TransactionHash: transactionHash,
385+
Signatures: signatures,
386+
}
387+
}
388+
389+
tx.TransactionType = util.ConvertBytesToUint32(txTypeMap["multiSignature"])
390+
txBody := &model.MultiSignatureTransactionBody{
391+
MultiSignatureInfo: multiSigInfo,
392+
UnsignedTransactionBytes: unsignedTx,
393+
SignatureInfo: signatureInfo,
394+
}
395+
tx.TransactionBodyBytes = (&transaction.MultiSignatureTransaction{
396+
Body: txBody,
397+
}).GetBodyBytes()
398+
fmt.Printf("length: %v\n", len(tx.TransactionBodyBytes))
399+
tx.TransactionBodyLength = uint32(len(tx.TransactionBodyBytes))
400+
return tx
401+
}

common/constant/fieldsSize.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,20 @@ var (
3535
EscrowID uint32 = 8
3636
EscrowApprovalBytesLength = EscrowApproval + EscrowID
3737
EscrowInstructionLength uint32 = 4
38+
MultisigFieldLength uint32 = 4
39+
// MultiSigFieldMissing indicate fields is missing, no need to read the bytes
40+
MultiSigFieldMissing uint32
41+
// MultiSigFieldPresent indicate fields is present, parse the byte accordingly
42+
MultiSigFieldPresent uint32 = 1
43+
MultiSigAddressLength uint32 = 4
44+
MultiSigSignatureLength uint32 = 4
45+
MultiSigSignatureAddressLength uint32 = 4
46+
MultiSigNumberOfAddress uint32 = 4
47+
MultiSigNumberOfSignatures uint32 = 4
48+
MultiSigUnsignedTxBytesLength uint32 = 4
49+
MultiSigInfoSize uint32 = 4
50+
MultiSigInfoSignatureInfoSize uint32 = 4
51+
MultiSigInfoNonce uint32 = 8
52+
MultiSigInfoMinSignature uint32 = 4
53+
MultiSigTransactionHash uint32 = 32
3854
)

0 commit comments

Comments
 (0)