You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@milagro.apache.org by cm...@apache.org on 2019/09/25 13:03:54 UTC
[incubator-milagro-dta] 09/11: Crypto De/Encapsulate Fix
This is an automated email from the ASF dual-hosted git repository.
cmorris pushed a commit to branch splitroles-blockchain
in repository https://gitbox.apache.org/repos/asf/incubator-milagro-dta.git
commit af4d0dbc8b85183e5e2e4bbb0754c375f86dd00a
Author: Christopher Morris <ch...@morris.net>
AuthorDate: Wed Sep 25 12:48:44 2019 +0100
Crypto De/Encapsulate Fix
---
cmd/service/__debug_bin | Bin 51651284 -> 51655380 bytes
cmd/service/main.go | 2 +-
cmd/servicetester/block_test.sh | 249 +++++++++++++++++++++++++++++++++++++++-
libs/documents/crypto.go | 22 +++-
pkg/defaultservice/fulfill.go | 7 +-
pkg/defaultservice/order.go | 8 +-
pkg/tendermint/json.go | 5 +
pkg/tendermint/tendermint.go | 13 ++-
pkg/tendermint/websockets.go | 9 +-
r1 | 5 +
r2 | 5 +
r3 | 5 +
12 files changed, 310 insertions(+), 20 deletions(-)
diff --git a/cmd/service/__debug_bin b/cmd/service/__debug_bin
index 3a3cf1b..583f2a3 100755
Binary files a/cmd/service/__debug_bin and b/cmd/service/__debug_bin differ
diff --git a/cmd/service/main.go b/cmd/service/main.go
index 920fc46..944d373 100644
--- a/cmd/service/main.go
+++ b/cmd/service/main.go
@@ -146,7 +146,7 @@ func startDaemon(args []string) error {
return errors.Wrap(err, "init logger")
}
- go tendermint.Subscribe(logger, cfg.Node.NodeID)
+ go tendermint.Subscribe(logger, cfg.Node.NodeID, cfg.HTTP.ListenAddr)
if err != nil {
return errors.Wrap(err, "init Tendermint Blockchain")
}
diff --git a/cmd/servicetester/block_test.sh b/cmd/servicetester/block_test.sh
index 304490a..c6674e8 100755
--- a/cmd/servicetester/block_test.sh
+++ b/cmd/servicetester/block_test.sh
@@ -1 +1,248 @@
-curl -s -X POST "127.0.0.1:5556/v1/order1" -H "accept: */*" -H "Content-Type: application/json" -d "{\"beneficiaryIDDocumentCID\":\"\",\"extension\":{\"coin\":\"0\"}}"
\ No newline at end of file
+#!/bin/bash
+#End to End Test of Services using curl/bash
+
+apiVersion="v1"
+defaultURL="http://localhost:5556"
+apiURL="${1:-$defaultURL}"
+
+
+status () {
+ #Determine if an extension is running
+ statusOutput=$(curl -s -X GET "$apiURL/$apiVersion/status" -H "accept: */*" -H "Content-Type: application/json")
+
+echo "$apiURL/$apiVersion/status"
+
+ identity=$(echo $statusOutput | jq .nodeCID)
+ extensionVendor=$(echo $statusOutput | jq -r .extensionVendor)
+ plugin=$(echo $statusOutput | jq -r .plugin)
+ echo "Plugin $plugin"
+
+ if [ -z "${extensionVendor}" ]; then
+ echo "Server Not Running"
+ exit 1
+ fi
+}
+
+###############################################################################################################################
+
+execute_bitcoin () {
+ # #Run 4 Tests against the Bitcoin Extension
+ echo "Bitcoin Plugin Tests [4 Tests]"
+ output1=$(curl -s -X POST "$apiURL/$apiVersion/order" -H "accept: */*" -H "Content-Type: application/json" -d "{\"beneficiaryIDDocumentCID\":\"\",\"extension\":{\"coin\":\"0\"}}")
+ #echo $output1
+ op1=$(echo $output1 | jq .orderReference)
+ commitment1=$(echo $output1 | jq .commitment)
+ address1=$(echo $output1 | jq .extension.address)
+ output2=$(curl -s -X POST "$apiURL/$apiVersion/order/secret" -H "accept: */*" -H "Content-Type: application/json" -d "{\"orderReference\":$op1,\"beneficiaryIDDocumentCID\":$identity}")
+ address2=$(echo $output2 | jq .extension.address)
+ commitment2=$(echo $output2 | jq .commitment)
+
+ echo "Committment1 $commitment1 $address1"
+ echo "Committment2 $commitment2 $address2"
+
+ if [ -z $commitment2 ]; then
+ echo "Failed Commitment is empty"
+ exit 1
+ fi
+
+ if [ $commitment1 == $commitment2 ]; then
+ echo "Pass - Id, Order & OrderSecret(Beneficiary)"
+ else
+ echo "Fail"
+ exit 1
+ fi
+
+
+ output3=$(curl -s -X POST "$apiURL/$apiVersion/order" -H "accept: */*" -H "Content-Type: application/json" -d "{\"beneficiaryIDDocumentCID\":$identity,\"extension\":{\"coin\":\"0\"}}")
+
+ op3=$(echo $output3 | jq .orderReference)
+ commitment3=$(echo $output3 | jq .commitment)
+ address3=$(echo $output3 | jq .extension.address)
+ output4=$(curl -s -X POST "$apiURL/$apiVersion/order/secret" -H "accept: */*" -H "Content-Type: application/json" -d "{\"orderReference\":$op3}")
+ commitment4=$(echo $output4 | jq .commitment)
+ address4=$(echo $output4 | jq .extension.address)
+ orderReference=$(echo $output4 | jq .orderReference)
+ orderIndex=1
+
+ echo "Committment3 $commitment3 $address3"
+ echo "Committment4 $commitment4 $address4"
+
+ if [ -z $commitment4 ]; then
+ echo "Failed Commitment is empty"
+ exit 1
+ fi
+
+ if [ $commitment3 == $commitment4 ]; then
+ echo "Pass - Id, Order(Beneficiary) & OrderSecret"
+ else
+ echo "Fail"
+ exit 1
+ fi
+
+
+ #make another BeneficiaryID
+ output5=$(curl -s -X POST "http://localhost:5556/$apiVersion/identity" -H "accept: */*" -H "Content-Type: application/json" -d "{\"Name\":\"AA\"}")
+ benid=$(echo $output5 | jq -r .idDocumentCID)
+
+
+
+ #Tests against the Bitcoin Extension - different befificary
+ output6=$(curl -s -X POST "http://localhost:5556/$apiVersion/order" -H "accept: */*" -H "Content-Type: application/json" -d "{\"beneficiaryIDDocumentCID\":\"\",\"extension\":{\"coin\":\"0\"}}")
+ #echo $output6
+ op6=$(echo $output6 | jq .orderReference)
+ commitment6=$(echo $output6 | jq .commitment)
+ address6=$(echo $output6 | jq .extension.address)
+
+ output7=$(curl -s -X POST "http://localhost:5556/$apiVersion/order/secret" -H "accept: */*" -H "Content-Type: application/json" -d "{\"orderReference\":$op6,\"beneficiaryIDDocumentCID\":\"$benid\"}")
+ address7=$(echo $output7 | jq .extension.address)
+ commitment7=$(echo $output7 | jq .commitment)
+
+ echo "Committment5 $commitment6 $address6"
+ echo "Committment6 $commitment7 $address7"
+
+ if [ -z $commitment7 ]; then
+ echo "Failed Commitment is empty"
+ exit 1
+ fi
+
+ if [ $commitment6 == $commitment7 ]; then
+ echo "Pass - Id, Order & OrderSecret(Beneficiary)"
+ else
+ echo "Fail"
+ exit 1
+ fi
+
+ output8=$(curl -s -X POST "http://localhost:5556/$apiVersion/order" -H "accept: */*" -H "Content-Type: application/json" -d "{\"beneficiaryIDDocumentCID\":\"$benid\",\"extension\":{\"coin\":\"0\"}}")
+ op8=$(echo $output8 | jq .orderReference)
+ commitment8=$(echo $output8 | jq .commitment)
+ address8=$(echo $output8 | jq .extension.address)
+
+
+ output9=$(curl -s -X POST "http://localhost:5556/$apiVersion/order/secret" -H "accept: */*" -H "Content-Type: application/json" -d "{\"orderReference\":$op8}")
+ commitment9=$(echo $output9 | jq .commitment)
+ address9=$(echo $output9 | jq .extension.address)
+ orderReference=$(echo $output9 | jq .orderReference)
+ orderIndex=1
+
+ echo "Committment7 $commitment8 $address8"
+ echo "Committment8 $commitment9 $address9"
+
+ if [ -z $commitment9 ]; then
+ echo "Failed Commitment is empty"
+ exit 1
+ fi
+
+ if [ $commitment8 == $commitment9 ]; then
+ echo "Pass - Id, Order(Beneficiary) & OrderSecret"
+ else
+ echo "Fail"
+ exit 1
+ fi
+
+}
+
+
+###############################################################################################################################
+
+execute_safeguardsecret () {
+ inputString="This is some random test text 1234567890!"
+ echo "Encrypt a String [1 Test]"
+ echo $output1
+ output1=$(curl -s -X POST "$apiURL/$apiVersion/order" -H "accept: */*" -H "Content-Type: application/json" -d "{\"beneficiaryIDDocumentCID\":$identity,\"extension\":{\"plainText\":\"$inputString\"}}")
+ echo $output1
+ op1=$(echo $output1 | jq .orderReference)
+ cipherText=$(echo $output1 | jq .extension.cypherText)
+ tvalue=$(echo $output1 | jq .extension.t)
+ vvalue=$(echo $output1 | jq .extension.v)
+ commitment1=$(echo $output1 | jq .commitment)
+ output2=$(curl -s -X POST "$apiURL/$apiVersion/order/secret" -H "accept: */*" -H "Content-Type: application/json" -d "{\"orderReference\":$op1,\"beneficiaryIDDocumentCID\":$identity,\"extension\":{\"cypherText\":$cipherText,\"t\":$tvalue,\"v\":$vvalue}}")
+ result=$(echo $output2 | jq -r .extension.plainText)
+
+ orderReference=$(echo $output2 | jq .orderReference)
+ orderIndex=0
+
+
+ if [ "$inputString" == "$result" ]; then
+ echo "Pass"
+ else
+ echo "Fail"
+ exit 1
+ fi
+}
+
+# #############################################################################
+
+
+execute_milagro () {
+ echo "Milagro Tests [1 Test]"
+ output1=$(curl -s -X POST "$apiURL/$apiVersion/order" -H "accept: */*" -H "Content-Type: application/json" -d "{\"beneficiaryIDDocumentCID\":$identity}")
+ echo $output1
+ op1=$(echo $output1 | jq .orderReference)
+
+
+ commitment1=$(echo $output1 | jq .commitment)
+ output2=$(curl -s -X POST "$apiURL/$apiVersion/order/secret" -H "accept: */*" -H "Content-Type: application/json" -d "{\"orderReference\":$op1,\"beneficiaryIDDocumentCID\":$identity}")
+ commitment2=$(echo $output2 | jq .commitment)
+
+ orderReference=$(echo $output2 | jq .orderReference)
+ orderIndex=0
+
+
+ echo "Committment1 $commitment1"
+ echo "Committment2 $commitment2"
+
+ if [ -z $commitment2 ]; then
+ echo "Failed Commitment is empty"
+ exit 1
+ fi
+
+ if [ $commitment1 == $commitment2 ]; then
+ echo "Order Create/Retrieve Pass"
+ else
+ echo "Order Create/Retrieve Fail"
+ exit 1
+ fi
+}
+
+
+
+
+
+
+# #############################################################################
+
+execute_orderlist () {
+ echo "Milagro Tests [1 Test]"
+ commitment2=$(echo $output2 | jq .commitment)
+ outputList=$(curl -s -X GET "$apiURL/$apiVersion/order?page=0&perPage=2&sortBy=dateCreatedDsc" -H "accept: */*")
+ orderReference=$(echo $outputList | jq -r ".orderReference | .[$orderIndex]")
+ outputOrder=$(curl -s -X GET "$apiURL/$apiVersion/order/$orderReference" -H "accept: */*")
+
+ #A simple smoke test to ensure some sort of order is returned
+ hasSecret=`echo $outputOrder | grep "Secret"`
+
+ if [ -z $hasSecret ]; then
+ echo "Failed Order has error"
+ exit 1
+ else
+ echo "Passed orderList & get"
+ fi
+}
+
+# #############################################################################
+
+status
+
+if [ $plugin == "bitcoinwallet" ]; then
+ execute_bitcoin
+fi
+
+if [ $plugin == "milagro" ]; then
+ execute_milagro
+fi
+
+if [ $plugin == "safeguardsecret" ]; then
+ execute_safeguardsecret
+fi
+execute_orderlist
+
diff --git a/libs/documents/crypto.go b/libs/documents/crypto.go
index f504ec0..8861e0e 100644
--- a/libs/documents/crypto.go
+++ b/libs/documents/crypto.go
@@ -48,7 +48,17 @@ func decapsulateWithRecipient(recipient Recipient, sikeSK []byte) ([]byte, error
encapsulatedKey := recipient.EncapsulatedKey
encapIV := recipient.IV
- rc, recreatedAesKey := crypto.DecapsulateDecrypt(cipherText, encapIV, sikeSK, encapsulatedKey)
+ cipherTextTemp := make([]byte, len(cipherText))
+ encapIVTemp := make([]byte, len(encapIV))
+ sikeSKTemp := make([]byte, len(sikeSK))
+ encapsulatedKeyTemp := make([]byte, len(encapsulatedKey))
+
+ copy(cipherTextTemp, cipherText)
+ copy(encapIVTemp, encapIV)
+ copy(sikeSKTemp, sikeSK)
+ copy(encapsulatedKeyTemp, encapsulatedKey)
+
+ rc, recreatedAesKey := crypto.DecapsulateDecrypt(cipherTextTemp, encapIVTemp, sikeSKTemp, encapsulatedKeyTemp)
if rc != 0 {
return nil, errFailedDecapsulation
@@ -67,7 +77,15 @@ func encapsulateKeyForRecipient(recipientsIDDocs map[string]IDDoc, secret []byte
r.IV = iv
sikePK := idDocument.SikePublicKey
- rc, cipherText, encapsulatedKey := crypto.EncapsulateEncrypt(secret, iv, sikePK)
+ //Make Copies of EncapsulateEncrypt's input params as its destructive
+ secretTemp := make([]byte, len(secret))
+ ivTemp := make([]byte, len(iv))
+ sikePKtemp := make([]byte, len(sikePK))
+ copy(secretTemp, secret)
+ copy(ivTemp, iv)
+ copy(sikePKtemp, sikePK)
+
+ rc, cipherText, encapsulatedKey := crypto.EncapsulateEncrypt(secretTemp, ivTemp, sikePKtemp)
if rc != 0 {
return nil, errFailedToGenerateAESKey
diff --git a/pkg/defaultservice/fulfill.go b/pkg/defaultservice/fulfill.go
index 8b1b87b..28eb3e4 100644
--- a/pkg/defaultservice/fulfill.go
+++ b/pkg/defaultservice/fulfill.go
@@ -47,7 +47,7 @@ func (s *Service) FulfillOrder(req *api.FulfillOrderRequest) (string, error) {
return "", err
}
- recipientList, err := common.BuildRecipientList(s.Ipfs, nodeID, nodeID)
+ recipientList, err := common.BuildRecipientList(s.Ipfs, order.PrincipalCID, nodeID)
if err != nil {
return "", err
}
@@ -80,10 +80,9 @@ func (s *Service) FulfillOrder(req *api.FulfillOrderRequest) (string, error) {
chainTX := &api.BlockChainTX{
Processor: api.TXFulfillResponse,
SenderID: nodeID,
- RecipientID: []string{s.MasterFiduciaryNodeID()},
+ RecipientID: []string{order.PrincipalCID},
Payload: marshaledRequest,
}
- //curl --data-binary '{"jsonrpc":"2.0","id":"anything","method":"broadcast_tx_commit","params": {"tx": "YWFhcT1hYWFxCg=="}}' -H 'content-type:text/plain;' http://localhost:26657
return tendermint.PostToChain(chainTX, "FulfillOrder")
}
@@ -146,7 +145,5 @@ func (s *Service) FulfillOrderSecret(req *api.FulfillOrderSecretRequest) (string
RecipientID: []string{s.MasterFiduciaryNodeID()},
Payload: marshaledRequest,
}
- //curl --data-binary '{"jsonrpc":"2.0","id":"anything","method":"broadcast_tx_commit","params": {"tx": "YWFhcT1hYWFxCg=="}}' -H 'content-type:text/plain;' http://localhost:26657
return tendermint.PostToChain(chainTX, "FulfillOrderSecret")
-
}
diff --git a/pkg/defaultservice/order.go b/pkg/defaultservice/order.go
index 8ab714d..fbd339d 100644
--- a/pkg/defaultservice/order.go
+++ b/pkg/defaultservice/order.go
@@ -332,7 +332,7 @@ func (s *Service) Order1(req *api.OrderRequest) (string, error) {
chainTX := &api.BlockChainTX{
Processor: api.TXFulfillRequest,
SenderID: nodeID,
- RecipientID: []string{s.MasterFiduciaryNodeID(), nodeID},
+ RecipientID: []string{s.MasterFiduciaryNodeID()},
Payload: marshaledRequest,
}
//curl --data-binary '{"jsonrpc":"2.0","id":"anything","method":"broadcast_tx_commit","params": {"tx": "YWFhcT1hYWFxCg=="}}' -H 'content-type:text/plain;' http://localhost:26657
@@ -430,7 +430,7 @@ func (s *Service) Order2(req *api.FulfillOrderResponse) (string, error) {
chainTX := &api.BlockChainTX{
Processor: api.TXOrderSecretResponse,
SenderID: nodeID,
- RecipientID: []string{s.MasterFiduciaryNodeID(), nodeID},
+ RecipientID: []string{s.MasterFiduciaryNodeID()},
Payload: marshaledRequest,
Tags: map[string]string{"reference": updatedOrder.Reference},
}
@@ -501,7 +501,7 @@ func (s *Service) OrderSecret1(req *api.OrderSecretRequest) (string, error) {
chainTX := &api.BlockChainTX{
Processor: api.TXFulfillOrderSecretRequest,
SenderID: nodeID,
- RecipientID: []string{s.MasterFiduciaryNodeID(), nodeID},
+ RecipientID: []string{s.MasterFiduciaryNodeID()},
Payload: marshaledRequest,
}
//curl --data-binary '{"jsonrpc":"2.0","id":"anything","method":"broadcast_tx_commit","params": {"tx": "YWFhcT1hYWFxCg=="}}' -H 'content-type:text/plain;' http://localhost:26657
@@ -556,7 +556,7 @@ func (s *Service) OrderSecret2(req *api.FulfillOrderSecretResponse) (string, err
chainTX := &api.BlockChainTX{
Processor: api.TXOrderSecretResponse,
SenderID: nodeID,
- RecipientID: []string{s.MasterFiduciaryNodeID(), nodeID},
+ RecipientID: []string{s.MasterFiduciaryNodeID()},
Payload: marshaledRequest,
}
//curl --data-binary '{"jsonrpc":"2.0","id":"anything","method":"broadcast_tx_commit","params": {"tx": "YWFhcT1hYWFxCg=="}}' -H 'content-type:text/plain;' http://localhost:26657
diff --git a/pkg/tendermint/json.go b/pkg/tendermint/json.go
index 8270db5..d5e56e7 100644
--- a/pkg/tendermint/json.go
+++ b/pkg/tendermint/json.go
@@ -8,26 +8,31 @@ package tendermint
import "encoding/json"
+//UnmarshalChainQuery -
func UnmarshalChainQuery(data []byte) (ChainQuery, error) {
var r ChainQuery
err := json.Unmarshal(data, &r)
return r, err
}
+//Marshal -
func (r *ChainQuery) Marshal() ([]byte, error) {
return json.Marshal(r)
}
+//ChainQuery -
type ChainQuery struct {
Jsonrpc string `json:"jsonrpc"`
ID string `json:"id"`
Result Result `json:"result"`
}
+//Result -
type Result struct {
Response Response `json:"response"`
}
+//Response -
type Response struct {
Log string `json:"log"`
Key string `json:"key"`
diff --git a/pkg/tendermint/tendermint.go b/pkg/tendermint/tendermint.go
index 3d34f36..ab162bf 100644
--- a/pkg/tendermint/tendermint.go
+++ b/pkg/tendermint/tendermint.go
@@ -67,7 +67,7 @@ func PostToChain(tx *api.BlockChainTX, method string) (string, error) {
return "", err
}
defer resp.Body.Close()
- fmt.Printf("POST TO CHAIN: METHOD:%s CALLS:%s - TXID:%s", method, tx.Processor, TXIDhex)
+ fmt.Printf("POST TO CHAIN: METHOD:%s CALLS:%s - TXID:%s\n", method, tx.Processor, TXIDhex)
return TXIDhex, nil
}
@@ -77,7 +77,8 @@ func HandleChainTX(myID string, tx string) error {
if err != nil {
return err
}
- err = callNextTX(blockChainTX)
+ panic(nil)
+ err = callNextTX(blockChainTX, "5556")
if err != nil {
return err
}
@@ -111,7 +112,7 @@ func decodeTX(payload string) (*api.BlockChainTX, string, error) {
return tx, hash, nil
}
-func callNextTX(tx *api.BlockChainTX) error {
+func callNextTX(tx *api.BlockChainTX, listenPort string) error {
// recipient := tx.RecipientID
// sender := tx.SenderID
//payloadJSON := tx.Payload
@@ -122,7 +123,7 @@ func callNextTX(tx *api.BlockChainTX) error {
return nil
}
- desintationURL := fmt.Sprintf("http://localhost:5556/%s", tx.Processor)
+ desintationURL := fmt.Sprintf("http://localhost"+listenPort+"/%s", tx.Processor)
body := strings.NewReader(payloadString)
req, err := http.NewRequest("POST", os.ExpandEnv(desintationURL), body)
@@ -147,7 +148,7 @@ func callNextTX(tx *api.BlockChainTX) error {
return nil
}
-//Decode the Payload into JSON and displays the entire Blockchain TX unencoded
+//DumpTX - Decode the Payload into JSON and displays the entire Blockchain TX unencoded
func DumpTX(bctx *api.BlockChainTX) {
f := colorjson.NewFormatter()
f.Indent = 4
@@ -162,6 +163,7 @@ func DumpTX(bctx *api.BlockChainTX) {
fmt.Println(string(s))
}
+//DumpTXID -
func DumpTXID(txid string) {
value, raw := QueryChain(txid)
println(value)
@@ -170,6 +172,7 @@ func DumpTXID(txid string) {
println()
}
+//ProcessTransactionID -
func ProcessTransactionID(txid string) {
_, payload := QueryChain((txid))
err := HandleChainTX("", payload)
diff --git a/pkg/tendermint/websockets.go b/pkg/tendermint/websockets.go
index 145374e..1e21a12 100644
--- a/pkg/tendermint/websockets.go
+++ b/pkg/tendermint/websockets.go
@@ -15,7 +15,7 @@ import (
)
//Subscribe - Connect to the Tendermint websocket to collect events
-func Subscribe(logger *logger.Logger, nodeID string) error {
+func Subscribe(logger *logger.Logger, nodeID string, listenPort string) error {
//tmlogger := log2.NewTMLogger(log.NewSyncWriter(os.Stdout))
@@ -53,6 +53,11 @@ func Subscribe(logger *logger.Logger, nodeID string) error {
break
}
+ //check if this node is Sender
+ if payload.SenderID == nodeID {
+ break
+ }
+
//check is receipient
isRecipient := false
for _, v := range payload.RecipientID {
@@ -74,7 +79,7 @@ func Subscribe(logger *logger.Logger, nodeID string) error {
if payload.Processor == "NONE" {
DumpTX(&payload)
} else {
- callNextTX(&payload)
+ callNextTX(&payload, listenPort)
}
//print(blockchainTX)
diff --git a/r1 b/r1
new file mode 100755
index 0000000..44fe3ff
--- /dev/null
+++ b/r1
@@ -0,0 +1,5 @@
+GO111MODULE=on go build -o target/milagro github.com/apache/incubator-milagro-dta/cmd/service
+export MILAGRO_HOME=~/.milagro1
+target/milagro daemon
+
+
diff --git a/r2 b/r2
new file mode 100755
index 0000000..a619211
--- /dev/null
+++ b/r2
@@ -0,0 +1,5 @@
+GO111MODULE=on go build -o target/milagro github.com/apache/incubator-milagro-dta/cmd/service
+export MILAGRO_HOME=~/.milagro2
+target/milagro daemon
+
+
diff --git a/r3 b/r3
new file mode 100755
index 0000000..350d822
--- /dev/null
+++ b/r3
@@ -0,0 +1,5 @@
+GO111MODULE=on go build -o target/milagro github.com/apache/incubator-milagro-dta/cmd/service
+export MILAGRO_HOME=~/.milagro3
+target/milagro daemon
+
+