Skip to content

Commit 28bb9c3

Browse files
authored
603 multisig apply (#623)
* #603 initialize multisig service layer * #603 implement apply confirmed * #603 add sender address in pending transaction * #603 update multisignature.PendingTransaction schema * #603 delete multisig tx util * #603 add sign command to support multisig development * #603 add --sender-address flag for generating unsigned bytes * #604 add sender address to unsigned tx * #603 return raw error from execute transaction to enable sqlite error casting * #603 complete multisig implementation * #603 fix tests * #603 add latest flag to pending transaction * #603 update pending_transaction status on executed * #603 add latest flag to pending transaction * #603 add filter to pending transaction query * #603 add latest flag to multisig-info and signatureInfo * #603 add multisig-child flag to tx table * #603 add multisig-child flag to tx table * #603 add multisig-child flag to tx model * #603 add latest field to all pending tables * #603 adjust query to handle latest flag * #603 insert multisig-child transaction to transaction table * #603 dfix test * #603 adjust cmd tools and crypto package to validate multisig signature (hierarchical multisig) * #603 fix example cmd * #603 update schema * #603 remove binary * #603 convert address-Signature to format stringTostring * #603 fix query inconsistency * #603 handle unsigned transaction execution status * #603 revert unnecessary change * #603 handle submit multisig info execute multiple tx * #603 fix query inconsistency * #603 add multisig signature type * #603 add constant for multisig signature validation type; * #603 remove debug log
1 parent 132c293 commit 28bb9c3

31 files changed

+1269
-387
lines changed

api/service/transactionApiService.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,7 @@ func (ts *TransactionService) GetTransactions(
193193
&tx.Signature,
194194
&tx.Version,
195195
&tx.TransactionIndex,
196+
&tx.MultisigChild,
196197
)
197198
if err != nil {
198199
if err != sql.ErrNoRows {

api/service/transactionApiService_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,7 @@ func (*mockQueryGetTransactionsSuccess) ExecuteSelect(qStr string, tx bool, args
591591
[]byte{0, 0, 0, 0, 0, 0, 0},
592592
1,
593593
1,
594+
false,
594595
),
595596
)
596597
}
@@ -684,6 +685,7 @@ func TestTransactionService_GetTransactions(t *testing.T) {
684685
Signature: []byte{0, 0, 0, 0, 0, 0, 0},
685686
Version: 1,
686687
TransactionIndex: 1,
688+
MultisigChild: false,
687689
},
688690
},
689691
},
@@ -737,6 +739,7 @@ func (*mockQueryGetTransactionSuccess) ExecuteSelect(
737739
8,
738740
[]byte{1, 2, 3, 4, 5, 6, 7, 8},
739741
[]byte{0, 0, 0, 0, 0, 0, 0}, 1, 1,
742+
false,
740743
),
741744
)
742745
return db.Query("")
@@ -759,6 +762,7 @@ func (*mockQueryGetTransactionSuccess) ExecuteSelectRow(qstr string, tx bool, ar
759762
8,
760763
[]byte{1, 2, 3, 4, 5, 6, 7, 8},
761764
[]byte{0, 0, 0, 0, 0, 0, 0}, 1, 1,
765+
false,
762766
),
763767
)
764768
return db.QueryRow(""), nil
@@ -837,6 +841,7 @@ func TestTransactionService_GetTransaction(t *testing.T) {
837841
Signature: []byte{0, 0, 0, 0, 0, 0, 0},
838842
Version: 1,
839843
TransactionIndex: 1,
844+
MultisigChild: false,
840845
},
841846
},
842847
}

cmd/main.go

Lines changed: 3 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/signature"
11+
1012
"github.com/spf13/cobra"
1113
"github.com/spf13/viper"
1214
"github.com/zoobc/zoobc-core/cmd/account"
@@ -73,6 +75,7 @@ func main() {
7375
rootCmd.AddCommand(genesisblock.Commands())
7476
rootCmd.AddCommand(rollback.Commands(sqliteDB))
7577
rootCmd.AddCommand(parserCmd)
78+
rootCmd.AddCommand(signature.Commands())
7679
generateCmd.AddCommand(account.Commands())
7780
generateCmd.AddCommand(transaction.Commands(sqliteDB))
7881
generateCmd.AddCommand(block.Commands())

cmd/readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ ofiness deviation starved"
103103

104104
### Account Generating multisig
105105
```bash
106-
go run main.go generate account multisig --addresses BCZnSfqpP5tqFQlMTYkDeBVFWnbyVK7vLr5ORFpTjgtN --addresses BCZD_VxfO2S9aziIL3cn_cXW7uPDVPOrnXuP98GEAUC7 --addresses BCZKLvgUYZ1KKx-jtF9KoJskjVPvB9jpIjfzzI6zDW0J —min-sigs 2 —nonce 3
106+
go run main.go generate account multisig --addresses BCZnSfqpP5tqFQlMTYkDeBVFWnbyVK7vLr5ORFpTjgtN --addresses BCZD_VxfO2S9aziIL3cn_cXW7uPDVPOrnXuP98GEAUC7 --addresses BCZKLvgUYZ1KKx-jtF9KoJskjVPvB9jpIjfzzI6zDW0J —-min-sigs=2 --nonce=3
107107
```
108108

109109
### Account Generate with spesific signature type

cmd/signature/cmd.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package signature
2+
3+
import (
4+
"encoding/hex"
5+
"fmt"
6+
"strconv"
7+
"strings"
8+
9+
"github.com/zoobc/zoobc-core/common/model"
10+
11+
"github.com/zoobc/zoobc-core/common/crypto"
12+
"golang.org/x/crypto/sha3"
13+
14+
"github.com/spf13/cobra"
15+
)
16+
17+
var (
18+
/*
19+
Signer command line tools
20+
*/
21+
signerCmd = &cobra.Command{
22+
Use: "sign",
23+
Short: "sign provided data",
24+
Long: "sign any provided data by using the --seed parameter",
25+
}
26+
)
27+
28+
func init() {
29+
signerCmd.Flags().StringVar(&dataHex, "data-hex", "", "hex string of the data to sign")
30+
signerCmd.Flags().StringVar(&dataBytes, "data-bytes", "", "data bytes separated by `, `. eg:"+
31+
"--data-bytes='1, 222, 54, 12, 32'")
32+
signerCmd.Flags().StringVar(&seed, "seed", "", "your secret phrase")
33+
signerCmd.Flags().BoolVar(&hash, "hash", false, "turn this flag on to hash the data before signing")
34+
}
35+
36+
func Commands() *cobra.Command {
37+
signerCmd.Run = SignData
38+
return signerCmd
39+
}
40+
41+
func SignData(*cobra.Command, []string) {
42+
var (
43+
unsignedBytes []byte
44+
hashedUnsignedBytes [32]byte
45+
signature []byte
46+
)
47+
if dataHex != "" {
48+
unsignedBytes, _ = hex.DecodeString(dataHex)
49+
} else {
50+
txByteCharSlice := strings.Split(dataBytes, ", ")
51+
for _, v := range txByteCharSlice {
52+
byteValue, err := strconv.Atoi(v)
53+
if err != nil {
54+
panic("failed to parse transaction bytes")
55+
}
56+
unsignedBytes = append(unsignedBytes, byte(byteValue))
57+
}
58+
}
59+
if hash {
60+
hashedUnsignedBytes = sha3.Sum256(unsignedBytes)
61+
signature, _ = (&crypto.Signature{}).Sign(hashedUnsignedBytes[:], model.SignatureType_DefaultSignature, seed)
62+
} else {
63+
signature, _ = (&crypto.Signature{}).Sign(unsignedBytes, model.SignatureType_DefaultSignature, seed)
64+
}
65+
edUtil := crypto.NewEd25519Signature()
66+
fmt.Printf("account-address:\t%v\n", edUtil.GetAddressFromSeed(seed))
67+
fmt.Printf("transaction-bytes:\t%v\n", unsignedBytes)
68+
fmt.Printf("transaction-hash:\t%v\n", hex.EncodeToString(hashedUnsignedBytes[:]))
69+
fmt.Printf("signature-bytes:\t%v\n", signature)
70+
fmt.Printf("signature-hex:\t%v\n", hex.EncodeToString(signature))
71+
}

cmd/signature/const.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package signature
2+
3+
var (
4+
seed string
5+
dataHex string
6+
dataBytes string
7+
hash bool
8+
)

cmd/transaction/cmd.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ func init() {
7878
txCmd.PersistentFlags().Int64Var(&fee, "fee", 1, "defines the fee of the transaction")
7979
txCmd.PersistentFlags().BoolVar(&post, "post", false, "post generated bytes to [127.0.0.1:7000](default)")
8080
txCmd.PersistentFlags().StringVar(&postHost, "post-host", "127.0.0.1:7000", "destination of post action")
81+
txCmd.PersistentFlags().StringVar(&senderAddress, "sender-address", "", "transaction's sender address")
8182
txCmd.PersistentFlags().Int32Var(
8283
&senderSignatureType,
8384
"sender-signature-type",
@@ -150,8 +151,8 @@ func init() {
150151
"to be valid")
151152
multiSigCmd.Flags().StringVar(&unsignedTxHex, "unsigned-transaction", "", "hex string of the unsigned transaction bytes")
152153
multiSigCmd.Flags().StringVar(&txHash, "transaction-hash", "", "hash of transaction being signed by address-signature list (hex)")
153-
multiSigCmd.Flags().StringSliceVar(&addressSignatures, "address-signatures", []string{}, "address-signature list "+
154-
"--address-signatures='address1-signature1,address2-signature2'")
154+
multiSigCmd.Flags().StringToStringVar(&addressSignatures, "address-signatures", make(map[string]string), "address:signature list "+
155+
"--address1='signature1' --address2='signature2'")
155156
}
156157

157158
// Commands set TXGeneratorCommandsInstance that will used by whole commands

cmd/transaction/const.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ var (
2727
fee int64
2828
post bool
2929
postHost string
30+
senderAddress string
3031
senderSignatureType int32
3132

3233
// Send money transaction
@@ -55,7 +56,7 @@ var (
5556

5657
// multiSignature
5758
unsignedTxHex string
58-
addressSignatures []string
59+
addressSignatures map[string]string
5960
txHash string
6061
addresses []string
6162
nonce int64

cmd/transaction/generator.go

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -239,22 +239,28 @@ func GenerateBasicTransaction(
239239
timestamp, fee int64,
240240
recipientAccountAddress string,
241241
) *model.Transaction {
242-
var senderAccountAddress string
243-
switch model.SignatureType(senderSignatureType) {
244-
case model.SignatureType_DefaultSignature:
245-
senderAccountAddress = crypto.NewEd25519Signature().GetAddressFromSeed(senderSeed)
246-
case model.SignatureType_BitcoinSignature:
247-
var (
248-
bitcoinSig = crypto.NewBitcoinSignature(crypto.DefaultBitcoinNetworkParams(), crypto.DefaultBitcoinCurve())
249-
pubKey = bitcoinSig.GetPublicKeyFromSeed(senderSeed, crypto.DefaultBitcoinPublicKeyFormat())
250-
err error
251-
)
252-
senderAccountAddress, err = bitcoinSig.GetAddressPublicKey(pubKey)
253-
if err != nil {
254-
fmt.Println("GenerateBasicTransaction-BitcoinSignature-Failed GetPublicKey")
242+
var (
243+
senderAccountAddress string
244+
)
245+
if senderSeed == "" {
246+
senderAccountAddress = senderAddress
247+
} else {
248+
switch model.SignatureType(senderSignatureType) {
249+
case model.SignatureType_DefaultSignature:
250+
senderAccountAddress = crypto.NewEd25519Signature().GetAddressFromSeed(senderSeed)
251+
case model.SignatureType_BitcoinSignature:
252+
var (
253+
bitcoinSig = crypto.NewBitcoinSignature(crypto.DefaultBitcoinNetworkParams(), crypto.DefaultBitcoinCurve())
254+
pubKey = bitcoinSig.GetPublicKeyFromSeed(senderSeed, crypto.DefaultBitcoinPublicKeyFormat())
255+
err error
256+
)
257+
senderAccountAddress, err = bitcoinSig.GetAddressPublicKey(pubKey)
258+
if err != nil {
259+
fmt.Println("GenerateBasicTransaction-BitcoinSignature-Failed GetPublicKey")
260+
}
261+
default:
262+
panic("GenerateBasicTransaction-Invalid Signature Type")
255263
}
256-
default:
257-
panic("GenerateBasicTransaction-Invalid Signature Type")
258264
}
259265

260266
if timestamp <= 0 {
@@ -318,6 +324,9 @@ func GenerateSignedTxBytes(tx *model.Transaction, senderSeed string, signatureTy
318324
tx.Fee += minimumFee
319325

320326
unsignedTxBytes, _ := transactionUtil.GetTransactionBytes(tx, false)
327+
if senderSeed == "" {
328+
return unsignedTxBytes
329+
}
321330
tx.Signature, _ = signature.Sign(
322331
unsignedTxBytes,
323332
model.SignatureType(signatureType),
@@ -388,7 +397,7 @@ func GeneratedMultiSignatureTransaction(
388397
minSignature uint32,
389398
nonce int64,
390399
unsignedTxHex, txHash string,
391-
addressSignatures, addresses []string,
400+
addressSignatures map[string]string, addresses []string,
392401
) *model.Transaction {
393402
var (
394403
signatures = make(map[string][]byte)
@@ -410,29 +419,28 @@ func GeneratedMultiSignatureTransaction(
410419
return nil
411420
}
412421
}
413-
414422
if txHash != "" {
415423
transactionHash, err := hex.DecodeString(txHash)
416424
if err != nil {
417425
return nil
418426
}
419-
for _, v := range addressSignatures {
420-
asig := strings.Split(v, "-")
421-
if len(asig) < 2 {
422-
return nil
427+
for k, v := range addressSignatures {
428+
if k == "" {
429+
sigType := util.ConvertUint32ToBytes(2)
430+
signatures[k] = sigType
431+
} else {
432+
signature, err := hex.DecodeString(v)
433+
if err != nil {
434+
return nil
435+
}
436+
signatures[k] = signature
423437
}
424-
signature, err := hex.DecodeString(asig[1])
425-
if err != nil {
426-
return nil
427-
}
428-
signatures[asig[0]] = signature
429438
}
430439
signatureInfo = &model.SignatureInfo{
431440
TransactionHash: transactionHash,
432441
Signatures: signatures,
433442
}
434443
}
435-
436444
tx.TransactionType = util.ConvertBytesToUint32(txTypeMap["multiSignature"])
437445
txBody := &model.MultiSignatureTransactionBody{
438446
MultiSignatureInfo: multiSigInfo,

cmd/zoomd

30.1 MB
Binary file not shown.

common/crypto/signature.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,8 @@ func (*Signature) VerifySignature(payload, signature []byte, accountAddress stri
129129
)
130130
}
131131
return nil
132+
case model.SignatureType_MultisigSignature: // multisig validation-only
133+
return nil
132134
default:
133135
return blocker.NewBlocker(
134136
blocker.ValidationErr,

common/database/migration.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,20 +278,23 @@ func (m *Migration) Init() error {
278278
`,
279279
`
280280
CREATE TABLE IF NOT EXISTS "pending_transaction" (
281+
"sender_address" TEXT, -- sender of transaction
281282
"transaction_hash" BLOB, -- transaction hash of pending transaction
282283
"transaction_bytes" BLOB, -- full transaction bytes of the pending transaction
283284
"status" INTEGER, -- execution status of the pending transaction
284285
"block_height" INTEGER, -- height when pending transaction inserted/updated
286+
"latest" INTEGER, -- latest flag for pending transaction
285287
PRIMARY KEY("transaction_hash", "block_height")
286288
)
287289
`,
288290
`
289291
CREATE TABLE IF NOT EXISTS "pending_signature" (
290-
"transaction_hash" INTEGER, -- transaction hash of pending transaction being signed
292+
"transaction_hash" BLOB, -- transaction hash of pending transaction being signed
291293
"account_address" TEXT, -- account address of the respective signature
292294
"signature" BLOB, -- full transaction bytes of the pending transaction
293295
"block_height" INTEGER, -- height when pending signature inserted/updated
294-
PRIMARY KEY("account_address", "transaction_hash")
296+
"latest" INTEGER, -- latest flag for pending signature
297+
PRIMARY KEY("account_address", "transaction_hash", "block_height")
295298
)
296299
`,
297300
`
@@ -301,10 +304,15 @@ func (m *Migration) Init() error {
301304
"nonce" INTEGER, -- full transaction bytes of the pending transaction
302305
"addresses" TEXT, -- list of addresses / participants of the multisig account
303306
"block_height" INTEGER, -- height when multisignature_info inserted / updated
307+
"latest" INTEGER, -- latest flag for pending signature
304308
PRIMARY KEY("multisig_address", "block_height")
305309
)
306310
`,
307311
`
312+
ALTER TABLE "transaction"
313+
ADD COLUMN "multisig_child" INTEGER DEFAULT 0
314+
`,
315+
`
308316
CREATE INDEX "node_registry_height_idx" ON "node_registry" ("height")
309317
`,
310318
`

0 commit comments

Comments
 (0)