Skip to content

Commit 1a6de6c

Browse files
authored
Merge pull request #380 from blinklabs-io/feat/tx-submission-test-program
feat: finish tx-submission test program
2 parents 4151649 + a7959e1 commit 1a6de6c

File tree

3 files changed

+171
-14
lines changed

3 files changed

+171
-14
lines changed

cbor/encode.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,27 @@ func EncodeGeneric(src interface{}) ([]byte, error) {
6565
}
6666
return cborData, nil
6767
}
68+
69+
type IndefLengthList struct {
70+
Items []any
71+
}
72+
73+
func (i *IndefLengthList) MarshalCBOR() ([]byte, error) {
74+
ret := []byte{
75+
// Start indefinite-length list
76+
0x9f,
77+
}
78+
for _, item := range i.Items {
79+
data, err := Encode(&item)
80+
if err != nil {
81+
return nil, err
82+
}
83+
ret = append(ret, data...)
84+
}
85+
ret = append(
86+
ret,
87+
// End indefinite length array
88+
byte(0xff),
89+
)
90+
return ret, nil
91+
}

cmd/tx-submission/main.go

Lines changed: 104 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,39 @@
1515
package main
1616

1717
import (
18+
"encoding/hex"
19+
"encoding/json"
1820
"fmt"
21+
"io/ioutil"
1922
"os"
23+
"time"
2024

2125
ouroboros "github.com/blinklabs-io/gouroboros"
26+
"github.com/blinklabs-io/gouroboros/cbor"
2227
"github.com/blinklabs-io/gouroboros/cmd/common"
2328
"github.com/blinklabs-io/gouroboros/protocol/txsubmission"
29+
30+
"golang.org/x/crypto/blake2b"
2431
)
2532

2633
type txSubmissionFlags struct {
2734
*common.GlobalFlags
35+
txFile string
36+
rawTxFile string
2837
}
2938

39+
var txBytes []byte
40+
var txHash [32]byte
41+
var sentTx bool
42+
var doneChan chan any
43+
3044
func main() {
3145
// Parse commandline
3246
f := txSubmissionFlags{
3347
GlobalFlags: common.NewGlobalFlags(),
3448
}
49+
f.Flagset.StringVar(&f.txFile, "tx-file", "", "path to the JSON transaction file to submit")
50+
f.Flagset.StringVar(&f.rawTxFile, "raw-tx-file", "", "path to the raw transaction file to submit")
3551
f.Parse()
3652
// Create connection
3753
conn := common.CreateClientConnection(f.GlobalFlags)
@@ -51,18 +67,8 @@ func main() {
5167
ouroboros.WithKeepAlive(true),
5268
ouroboros.WithTxSubmissionConfig(
5369
txsubmission.NewConfig(
54-
txsubmission.WithRequestTxIdsFunc(
55-
// TODO: do something more useful
56-
func(blocking bool, ack uint16, req uint16) ([]txsubmission.TxIdAndSize, error) {
57-
return []txsubmission.TxIdAndSize{}, nil
58-
},
59-
),
60-
txsubmission.WithRequestTxsFunc(
61-
// TODO: do something more useful
62-
func(txIds []txsubmission.TxId) ([]txsubmission.TxBody, error) {
63-
return []txsubmission.TxBody{}, nil
64-
},
65-
),
70+
txsubmission.WithRequestTxIdsFunc(handleRequestTxIds),
71+
txsubmission.WithRequestTxsFunc(handleRequestTxs),
6672
),
6773
),
6874
)
@@ -71,9 +77,93 @@ func main() {
7177
os.Exit(1)
7278
}
7379

80+
// Read the transaction file
81+
if f.txFile != "" {
82+
txData, err := ioutil.ReadFile(f.txFile)
83+
if err != nil {
84+
fmt.Printf("Failed to load transaction file: %s\n", err)
85+
os.Exit(1)
86+
}
87+
88+
var jsonData map[string]string
89+
err = json.Unmarshal(txData, &jsonData)
90+
if err != nil {
91+
fmt.Printf("failed to parse transaction file: %s\n", err)
92+
os.Exit(1)
93+
}
94+
95+
txBytes, err = hex.DecodeString(jsonData["cborHex"])
96+
if err != nil {
97+
fmt.Printf("failed to decode transaction: %s\n", err)
98+
os.Exit(1)
99+
}
100+
} else if f.rawTxFile != "" {
101+
txBytes, err = ioutil.ReadFile(f.rawTxFile)
102+
if err != nil {
103+
fmt.Printf("Failed to load transaction file: %s\n", err)
104+
os.Exit(1)
105+
}
106+
} else {
107+
fmt.Printf("You must specify one of -tx-file or -raw-tx-file\n")
108+
os.Exit(1)
109+
}
110+
111+
// Generate TX hash
112+
// Unwrap raw transaction bytes into a CBOR array
113+
var txUnwrap []cbor.RawMessage
114+
if _, err := cbor.Decode(txBytes, &txUnwrap); err != nil {
115+
fmt.Printf("ERROR: failed to unwrap transaction CBOR: %s", err)
116+
os.Exit(1)
117+
}
118+
// index 0 is the transaction body
119+
// Store index 0 (transaction body) as byte array
120+
txBody := txUnwrap[0]
121+
122+
// Convert the body into a blake2b256 hash string
123+
txHash = blake2b.Sum256(txBody)
124+
125+
// Create our "done" channel
126+
doneChan = make(chan any)
127+
74128
// Start the TxSubmission activity loop
75129
o.TxSubmission().Client.Init()
76130

77-
// Wait forever
78-
select {}
131+
// Wait until we're done
132+
<-doneChan
133+
134+
fmt.Printf("Successfully sent transaction %x\n", txHash)
135+
136+
if err := o.Close(); err != nil {
137+
fmt.Printf("ERROR: failed to close connection: %s\n", err)
138+
os.Exit(1)
139+
}
140+
}
141+
142+
func handleRequestTxIds(blocking bool, ack uint16, req uint16) ([]txsubmission.TxIdAndSize, error) {
143+
if sentTx {
144+
// Terrible syncronization hack for shutdown
145+
close(doneChan)
146+
time.Sleep(5 * time.Second)
147+
}
148+
ret := []txsubmission.TxIdAndSize{
149+
{
150+
TxId: txsubmission.TxId{
151+
EraId: 5,
152+
TxId: txHash,
153+
},
154+
Size: uint32(len(txBytes)),
155+
},
156+
}
157+
return ret, nil
158+
}
159+
160+
func handleRequestTxs(txIds []txsubmission.TxId) ([]txsubmission.TxBody, error) {
161+
ret := []txsubmission.TxBody{
162+
{
163+
EraId: 5,
164+
TxBody: txBytes,
165+
},
166+
}
167+
sentTx = true
168+
return ret, nil
79169
}

protocol/txsubmission/messages.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,20 @@ type MsgReplyTxIds struct {
8080
TxIds []TxIdAndSize
8181
}
8282

83+
func (m *MsgReplyTxIds) MarshalCBOR() ([]byte, error) {
84+
items := []any{}
85+
for _, txId := range m.TxIds {
86+
items = append(items, txId)
87+
}
88+
tmp := []any{
89+
MessageTypeReplyTxIds,
90+
cbor.IndefLengthList{
91+
Items: items,
92+
},
93+
}
94+
return cbor.Encode(tmp)
95+
}
96+
8397
func NewMsgReplyTxIds(txIds []TxIdAndSize) *MsgReplyTxIds {
8498
m := &MsgReplyTxIds{
8599
MessageBase: protocol.MessageBase{
@@ -110,6 +124,20 @@ type MsgReplyTxs struct {
110124
Txs []TxBody
111125
}
112126

127+
func (m *MsgReplyTxs) MarshalCBOR() ([]byte, error) {
128+
items := []any{}
129+
for _, tx := range m.Txs {
130+
items = append(items, tx)
131+
}
132+
tmp := []any{
133+
MessageTypeReplyTxs,
134+
cbor.IndefLengthList{
135+
Items: items,
136+
},
137+
}
138+
return cbor.Encode(tmp)
139+
}
140+
113141
func NewMsgReplyTxs(txs []TxBody) *MsgReplyTxs {
114142
m := &MsgReplyTxs{
115143
MessageBase: protocol.MessageBase{
@@ -147,16 +175,31 @@ func NewMsgInit() *MsgInit {
147175
}
148176

149177
type TxId struct {
178+
cbor.StructAsArray
150179
EraId uint16
151180
TxId [32]byte
152181
}
153182

154183
type TxBody struct {
184+
cbor.StructAsArray
155185
EraId uint16
156186
TxBody []byte
157187
}
158188

189+
func (t *TxBody) MarshalCBOR() ([]byte, error) {
190+
tmp := []any{
191+
t.EraId,
192+
cbor.Tag{
193+
// Wrapped CBOR
194+
Number: 24,
195+
Content: t.TxBody,
196+
},
197+
}
198+
return cbor.Encode(&tmp)
199+
}
200+
159201
type TxIdAndSize struct {
202+
cbor.StructAsArray
160203
TxId TxId
161204
Size uint32
162205
}

0 commit comments

Comments
 (0)