Skip to content
This repository was archived by the owner on Jan 22, 2020. It is now read-only.

Commit 848f078

Browse files
committed
Add go example, same as nodejs
Signed-off-by: asettouf <adonis.settouf@gmail.com>
1 parent 6b43283 commit 848f078

File tree

39 files changed

+10208
-0
lines changed

39 files changed

+10208
-0
lines changed
Lines changed: 260 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,260 @@
1+
/**
2+
* Copyright 2017 Intel Corporation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
* ------------------------------------------------------------------------------
16+
*/
17+
18+
package client
19+
20+
import (
21+
"encoding/hex"
22+
"fmt"
23+
"github.com/golang/protobuf/proto"
24+
"sawtooth_sdk/protobuf/batch_pb2"
25+
"sawtooth_sdk/protobuf/transaction_pb2"
26+
"time"
27+
)
28+
29+
type TransactionParams struct {
30+
FamilyName string
31+
FamilyVersion string
32+
PayloadEncoding string
33+
Nonce string
34+
BatcherPubkey string
35+
Dependencies []string
36+
Inputs []string
37+
Outputs []string
38+
}
39+
40+
type Encoder struct {
41+
privkey []byte
42+
pubkey string
43+
defaults TransactionParams
44+
}
45+
46+
// NewTransactionEncoder constructs a new encoder which can be used to generate
47+
// transactions and batches, and to serialize batches for submitting to the
48+
// REST API.
49+
func NewEncoder(privkey []byte, defaults TransactionParams) *Encoder {
50+
return &Encoder{
51+
privkey: privkey,
52+
pubkey: hex.EncodeToString(GenPubKey(privkey)),
53+
defaults: defaults,
54+
}
55+
}
56+
57+
// -- Transactions --
58+
59+
// NewTransaction Creates a new transaction and handles the construction and
60+
// signing of the transaction header.
61+
func (self *Encoder) NewTransaction(payload []byte, p TransactionParams) *Transaction {
62+
h := &transaction_pb2.TransactionHeader{
63+
// Load defaults
64+
FamilyName: self.defaults.FamilyName,
65+
FamilyVersion: self.defaults.FamilyVersion,
66+
PayloadEncoding: self.defaults.PayloadEncoding,
67+
Nonce: self.defaults.Nonce,
68+
BatcherPubkey: self.defaults.BatcherPubkey,
69+
70+
Inputs: self.defaults.Inputs,
71+
Outputs: self.defaults.Outputs,
72+
Dependencies: self.defaults.Dependencies,
73+
74+
// Set unique fields
75+
PayloadSha512: hex.EncodeToString(SHA512(payload)),
76+
SignerPubkey: self.pubkey,
77+
}
78+
79+
// Override defaults if set
80+
if p.FamilyName != "" {
81+
h.FamilyName = p.FamilyName
82+
}
83+
if p.FamilyVersion != "" {
84+
h.FamilyVersion = p.FamilyVersion
85+
}
86+
if p.PayloadEncoding != "" {
87+
h.PayloadEncoding = p.PayloadEncoding
88+
}
89+
if p.Nonce != "" {
90+
h.Nonce = p.Nonce
91+
}
92+
if p.BatcherPubkey != "" {
93+
h.BatcherPubkey = p.BatcherPubkey
94+
}
95+
96+
if p.Inputs != nil {
97+
h.Inputs = p.Inputs[:]
98+
}
99+
if p.Outputs != nil {
100+
h.Outputs = p.Outputs[:]
101+
}
102+
if p.Dependencies != nil {
103+
h.Dependencies = p.Dependencies[:]
104+
}
105+
106+
// Generate a nonce if none has been set yet
107+
if h.Nonce == "" {
108+
h.Nonce = fmt.Sprintf("%x", time.Now().UTC().UnixNano())
109+
}
110+
111+
// If a BatcherPubkey hasn't been set yet, assume its our key
112+
if h.BatcherPubkey == "" {
113+
h.BatcherPubkey = self.pubkey
114+
}
115+
116+
hb, err := proto.Marshal(h)
117+
if err != nil {
118+
panic(err)
119+
}
120+
hs := hex.EncodeToString(Sign(hb, self.privkey))
121+
122+
transaction := &transaction_pb2.Transaction{
123+
Header: hb,
124+
HeaderSignature: hs,
125+
Payload: payload,
126+
}
127+
128+
return (*Transaction)(transaction)
129+
}
130+
131+
// SerializeTransactions serializes the given transactions to bytes for
132+
// transmission to a separate batcher.
133+
func SerializeTransactions(transactions []*Transaction) []byte {
134+
txns := make([]*transaction_pb2.Transaction, 0, len(transactions))
135+
for _, tx := range transactions {
136+
txns = append(txns, tx.ToPb())
137+
}
138+
139+
tl := &transaction_pb2.TransactionList{
140+
Transactions: txns,
141+
}
142+
143+
tlb, err := proto.Marshal(tl)
144+
if err != nil {
145+
panic(err)
146+
}
147+
148+
return tlb
149+
}
150+
151+
// ParseTransactions deserializes the given bytes into a list of transactions.
152+
// The bytes are assumed to be in the format returned by SerializeTransactions.
153+
func ParseTransactions(b []byte) ([]*Transaction, error) {
154+
tl := &transaction_pb2.TransactionList{}
155+
err := proto.Unmarshal(b, tl)
156+
if err != nil {
157+
return nil, err
158+
}
159+
160+
txns := tl.GetTransactions()
161+
162+
transactions := make([]*Transaction, 0, len(txns))
163+
for _, tx := range txns {
164+
transactions = append(transactions, (*Transaction)(tx))
165+
}
166+
167+
return transactions, nil
168+
}
169+
170+
// -- Batches --
171+
172+
// NewBatch creates a new batch from the given transactions created by
173+
// NewTransaction. It handles the construction and signing of the batch header.
174+
func (self *Encoder) NewBatch(transactions []*Transaction) *Batch {
175+
txnIds := make([]string, 0, len(transactions))
176+
txns := make([]*transaction_pb2.Transaction, 0, len(transactions))
177+
for _, tx := range transactions {
178+
txnIds = append(txnIds, tx.Id())
179+
txns = append(txns, tx.ToPb())
180+
}
181+
182+
h := &batch_pb2.BatchHeader{
183+
SignerPubkey: self.pubkey,
184+
TransactionIds: txnIds,
185+
}
186+
187+
hb, err := proto.Marshal(h)
188+
if err != nil {
189+
panic(err)
190+
}
191+
192+
hs := hex.EncodeToString(Sign(hb, self.privkey))
193+
194+
batch := &batch_pb2.Batch{
195+
Header: hb,
196+
HeaderSignature: hs,
197+
Transactions: txns,
198+
}
199+
200+
return (*Batch)(batch)
201+
}
202+
203+
// SerializeBatches serializes the given batches to bytes in the form expected
204+
// by the REST API.
205+
func SerializeBatches(batches []*Batch) []byte {
206+
bs := make([]*batch_pb2.Batch, 0, len(batches))
207+
for _, b := range batches {
208+
bs = append(bs, b.ToPb())
209+
}
210+
bl := &batch_pb2.BatchList{
211+
Batches: bs,
212+
}
213+
214+
blb, err := proto.Marshal(bl)
215+
if err != nil {
216+
panic(err)
217+
}
218+
219+
return blb
220+
}
221+
222+
// ParseBatches deserializes the given bytes into a list of batches. The bytes
223+
// are assumed to be in the format returned by SerializeBatches.
224+
func ParseBatches(b []byte) ([]*Batch, error) {
225+
bl := &batch_pb2.BatchList{}
226+
err := proto.Unmarshal(b, bl)
227+
if err != nil {
228+
return nil, err
229+
}
230+
231+
bs := bl.GetBatches()
232+
233+
batches := make([]*Batch, 0, len(bs))
234+
for _, b := range bs {
235+
batches = append(batches, (*Batch)(b))
236+
}
237+
238+
return batches, nil
239+
}
240+
241+
// -- Wrap Protobuf --
242+
243+
// Wrap the protobuf types so that they do not need to be imported separately.
244+
type Transaction transaction_pb2.Transaction
245+
246+
func (t *Transaction) ToPb() *transaction_pb2.Transaction {
247+
return (*transaction_pb2.Transaction)(t)
248+
}
249+
250+
// GetId Returns the Transaction ID which can be used to specify this
251+
// transaction as a dependency for other transactions.
252+
func (t *Transaction) Id() string {
253+
return t.ToPb().GetHeaderSignature()
254+
}
255+
256+
type Batch batch_pb2.Batch
257+
258+
func (b *Batch) ToPb() *batch_pb2.Batch {
259+
return (*batch_pb2.Batch)(b)
260+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* Copyright 2017 Intel Corporation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
* ------------------------------------------------------------------------------
16+
*/
17+
18+
package client
19+
20+
// #cgo LDFLAGS: -lcrypto
21+
// #include "../../../../c/loader.c"
22+
import "C"
23+
24+
import "fmt"
25+
26+
func loadPemKey(pemstr string, pemstrLen int, password string) (priv_key string, pub_key string, err error) {
27+
cPemstr := C.CString(pemstr)
28+
cPemstrLen := C.size_t(pemstrLen)
29+
cPassword := C.CString(password)
30+
cOutPrivKey := C.CString("-----------------------------------------------------------------")
31+
cOutPubKey := C.CString("-----------------------------------------------------------------------------------------------------------------------------------")
32+
errnum := C.load_pem_key(cPemstr, cPemstrLen, cPassword, cOutPrivKey, cOutPubKey)
33+
if errnum < 0 {
34+
var errstr string
35+
switch errnum {
36+
case -1:
37+
errstr = "Failed to decrypt or decode private key"
38+
case -2:
39+
errstr = "Failed to create new big number context"
40+
case -3:
41+
errstr = "Failed to load group"
42+
case -4:
43+
errstr = "Failed to load private key"
44+
case -5:
45+
errstr = "Failed to load public key point"
46+
case -6:
47+
errstr = "Failed to construct public key from point"
48+
}
49+
return "", "", fmt.Errorf(errstr)
50+
}
51+
return C.GoString(cOutPrivKey), C.GoString(cOutPubKey), nil
52+
}

0 commit comments

Comments
 (0)