Skip to content

Commit 33f461a

Browse files
authored
Merge pull request #33 from Bit-Nation/develop
[dapp] first version of the DApp engine
2 parents e2c60fd + 688bed6 commit 33f461a

26 files changed

+1213
-53
lines changed

Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ list:
44
@$(MAKE) -pRrq -f $(lastword $(MAKEFILE_LIST)) : 2>/dev/null | awk -v RS= -F: '/^# File/,/^# Finished Make data base/ {if ($$1 !~ "^[#.]") {print $$1}}' | sort | egrep -v -e '^[^[:alnum:]]' -e '^$@$$' | xargs
55
proto:
66
protoc --go_out=. api/pb/*.proto
7+
protoc --go_out=. dapp/registry/pb/*.proto
78
deps:
89
go get github.com/whyrusleeping/gx
910
go get github.com/whyrusleeping/gx-go

api/api.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ type UpStream interface {
2121
// Create new api with given client
2222
func New(client UpStream) *API {
2323
return &API{
24-
lock: sync.Mutex{},
25-
requests: map[string]chan*Response{},
26-
client: client,
24+
lock: sync.Mutex{},
25+
requests: map[string]chan *Response{},
26+
client: client,
2727
}
2828
}
2929

api/api_test.go

+28-29
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,10 @@ package api
33
import (
44
"testing"
55
"time"
6-
6+
77
pb "github.com/Bit-Nation/panthalassa/api/pb"
8-
require "github.com/stretchr/testify/require"
98
proto "github.com/golang/protobuf/proto"
10-
9+
require "github.com/stretchr/testify/require"
1110
)
1211

1312
type testUpStream struct {
@@ -23,59 +22,59 @@ func TestAPI_addAndCutRequestWorks(t *testing.T) {
2322

2423
req := pb.Request{}
2524
req.RequestID = "hi"
26-
25+
2726
// api
2827
api := New(&testUpStream{})
29-
28+
3029
// make sure request doesn't exist
3130
_, exist := api.requests["hi"]
3231
require.False(t, exist)
33-
32+
3433
api.addRequest(&req)
35-
34+
3635
// make sure request does exist
3736
_, exist = api.requests["hi"]
3837
require.True(t, exist)
39-
38+
4039
// now cut request our of the stack and make sure it was removed
4140
api.cutRequest("hi")
4241
_, exist = api.requests["hi"]
4342
require.False(t, exist)
44-
43+
4544
}
4645

47-
func TestRequestResponse(t *testing.T) {
48-
46+
func TestRequestResponse(t *testing.T) {
47+
4948
dataChan := make(chan string)
50-
49+
5150
var receivedRequestID string
52-
51+
5352
// api
5453
api := New(&testUpStream{
5554
sendFn: func(data string) {
5655
dataChan <- data
5756
},
5857
})
59-
58+
6059
go func() {
6160
select {
62-
case data := <-dataChan:
63-
req := &pb.Request{}
64-
if err := proto.Unmarshal([]byte(data), req); err != nil {
65-
panic(err)
66-
}
67-
receivedRequestID = req.RequestID
68-
out := api.Respond(req.RequestID, &pb.Response{
69-
RequestID: req.RequestID,
70-
}, nil, time.Second)
71-
if out != nil {
72-
panic("expected nil but got: " + out.Error())
73-
}
61+
case data := <-dataChan:
62+
req := &pb.Request{}
63+
if err := proto.Unmarshal([]byte(data), req); err != nil {
64+
panic(err)
65+
}
66+
receivedRequestID = req.RequestID
67+
out := api.Respond(req.RequestID, &pb.Response{
68+
RequestID: req.RequestID,
69+
}, nil, time.Second)
70+
if out != nil {
71+
panic("expected nil but got: " + out.Error())
72+
}
7473
}
7574
}()
76-
75+
7776
resp, err := api.request(&pb.Request{}, time.Second)
7877
require.Nil(t, err)
7978
require.Equal(t, resp.Msg.RequestID, receivedRequestID)
80-
81-
}
79+
80+
}

api/doc.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@ package api
1010
// to the request and response protobufs
1111
// you can then extend the api struct
1212
// if you e.g. would like to implement the DHT CRUD you can create a new file
13-
// called `dht.go` in the api folder and start to implement the requests
13+
// called `dht.go` in the api folder and start to implement the requests

crypto/aes/utils_test.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ package aes
33
import (
44
"crypto/hmac"
55
"crypto/sha256"
6-
"github.com/kataras/iris/core/errors"
7-
"github.com/stretchr/testify/require"
6+
"errors"
87
"testing"
8+
9+
require "github.com/stretchr/testify/require"
910
)
1011

1112
func TestVersionOneOfMac(t *testing.T) {

dapp/dapp.go

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package dapp
2+
3+
import (
4+
"encoding/hex"
5+
"fmt"
6+
7+
module "github.com/Bit-Nation/panthalassa/dapp/module"
8+
logger "github.com/op/go-logging"
9+
otto "github.com/robertkrimen/otto"
10+
)
11+
12+
type DApp struct {
13+
vm *otto.Otto
14+
logger *logger.Logger
15+
app *JsonRepresentation
16+
closeChan chan<- *JsonRepresentation
17+
}
18+
19+
// close DApp
20+
func (d *DApp) Close() {
21+
d.vm.Interrupt <- func() {
22+
d.logger.Info(fmt.Sprintf("shutting down: %s (%s)", hex.EncodeToString(d.app.SignaturePublicKey), d.app.Name))
23+
d.closeChan <- d.app
24+
}
25+
}
26+
27+
func (d *DApp) ID() string {
28+
return hex.EncodeToString(d.app.SignaturePublicKey)
29+
}
30+
31+
// will start a DApp based on the given config file
32+
//
33+
func New(l *logger.Logger, app *JsonRepresentation, vmModules []module.Module, closer chan<- *JsonRepresentation) (*DApp, error) {
34+
35+
// check if app is valid
36+
valid, err := app.VerifySignature()
37+
if err != nil {
38+
return nil, err
39+
}
40+
if !valid {
41+
return nil, InvalidSignature
42+
}
43+
44+
// create VM
45+
vm := otto.New()
46+
vm.Interrupt = make(chan func(), 1)
47+
48+
// register all vm modules
49+
for _, m := range vmModules {
50+
if err := m.Register(vm); err != nil {
51+
return nil, err
52+
}
53+
}
54+
55+
dApp := &DApp{
56+
vm: vm,
57+
logger: l,
58+
app: app,
59+
closeChan: closer,
60+
}
61+
62+
go func() {
63+
_, err := vm.Run(app.Code)
64+
if err != nil {
65+
l.Error(err)
66+
closer <- app
67+
}
68+
}()
69+
70+
return dApp, nil
71+
}

dapp/dapp_representation.go

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package dapp
2+
3+
import (
4+
"bytes"
5+
"encoding/json"
6+
"errors"
7+
8+
mh "github.com/multiformats/go-multihash"
9+
ed25519 "golang.org/x/crypto/ed25519"
10+
)
11+
12+
var InvalidSignature = errors.New("failed to verify signature for DApp")
13+
14+
// JSON Representation of published DApp
15+
type JsonRepresentation struct {
16+
Name string `json:"name"`
17+
Code string `json:"code"`
18+
SignaturePublicKey []byte `json:"signature_public_key"`
19+
Signature []byte `json:"signature"`
20+
}
21+
22+
// hash the published DApp
23+
func (r JsonRepresentation) Hash() ([]byte, error) {
24+
25+
buff := bytes.NewBuffer([]byte(r.Name))
26+
27+
if _, err := buff.Write([]byte(r.Code)); err != nil {
28+
return nil, err
29+
}
30+
31+
if _, err := buff.Write(r.SignaturePublicKey); err != nil {
32+
return nil, err
33+
}
34+
35+
multiHash, err := mh.Sum(buff.Bytes(), mh.SHA3_256, -1)
36+
if err != nil {
37+
return nil, err
38+
}
39+
40+
return multiHash, nil
41+
42+
}
43+
44+
// verify if this published DApp
45+
// was signed with the attached public key
46+
func (r JsonRepresentation) VerifySignature() (bool, error) {
47+
48+
hash, err := r.Hash()
49+
if err != nil {
50+
return false, err
51+
}
52+
53+
return ed25519.Verify(r.SignaturePublicKey, hash, r.Signature), nil
54+
55+
}
56+
57+
func (r JsonRepresentation) Marshal() ([]byte, error) {
58+
return json.Marshal(r)
59+
}

dapp/dapp_representation_test.go

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package dapp
2+
3+
import (
4+
"bytes"
5+
"crypto/rand"
6+
"golang.org/x/crypto/ed25519"
7+
"testing"
8+
9+
mh "github.com/multiformats/go-multihash"
10+
require "github.com/stretchr/testify/require"
11+
)
12+
13+
func TestDAppRepresentationHash(t *testing.T) {
14+
15+
pub, _, err := ed25519.GenerateKey(rand.Reader)
16+
require.Nil(t, err)
17+
18+
rep := JsonRepresentation{
19+
Name: "Send / Receive Money",
20+
Code: `var wallet = "0x930aa9a843266bdb02847168d571e7913907dd84"`,
21+
SignaturePublicKey: pub,
22+
}
23+
24+
// calculate hash manually
25+
// name + code + signature public key
26+
buff := bytes.NewBuffer([]byte(rep.Name))
27+
28+
_, err = buff.Write([]byte(rep.Code))
29+
require.Nil(t, err)
30+
31+
_, err = buff.Write([]byte(rep.SignaturePublicKey))
32+
require.Nil(t, err)
33+
34+
expectedHash, err := mh.Sum(buff.Bytes(), mh.SHA3_256, -1)
35+
require.Nil(t, err)
36+
37+
// calculate hash
38+
calculateHash, err := rep.Hash()
39+
require.Nil(t, err)
40+
41+
// check if hashes match
42+
require.Equal(t, string(expectedHash), string(calculateHash))
43+
44+
}
45+
46+
func TestDAppVerifySignature(t *testing.T) {
47+
48+
pub, priv, err := ed25519.GenerateKey(rand.Reader)
49+
require.Nil(t, err)
50+
51+
rep := JsonRepresentation{
52+
Name: "Send / Receive Money",
53+
Code: `var wallet = "0x930aa9a843266bdb02847168d571e7913907dd84"`,
54+
SignaturePublicKey: pub,
55+
}
56+
57+
// validate signature
58+
// should be invalid since it doesn't exist
59+
valid, err := rep.VerifySignature()
60+
require.Nil(t, err)
61+
require.False(t, valid)
62+
63+
// hash the representation
64+
calculatedHash, err := rep.Hash()
65+
require.Nil(t, err)
66+
67+
// sign representation
68+
rep.Signature = ed25519.Sign(priv, calculatedHash)
69+
70+
// validate signature
71+
valid, err = rep.VerifySignature()
72+
require.Nil(t, err)
73+
require.True(t, valid)
74+
75+
}

0 commit comments

Comments
 (0)