Skip to content

Commit

Permalink
Merge pull request #38 from getamis/add_example
Browse files Browse the repository at this point in the history
Add DKG example
  • Loading branch information
bun919tw authored Apr 10, 2020
2 parents 79f7f8b + 0329b68 commit a648212
Show file tree
Hide file tree
Showing 14 changed files with 1,018 additions and 9 deletions.
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ coverage.txt:

PHONY += unit-test
unit-test: coverage.txt
@for d in $$(go list ./...); do \
@for d in $$(go list ./... | grep -v example); do \
set -o pipefail; \
go test -timeout $(GO_UNIT_TEST_TIMEOUT) -v -coverprofile=profile.out -covermode=$(GO_TEST_COVER_MODE) $$d 2>&1; \
if [ $$? -eq 0 ]; then \
Expand All @@ -22,3 +22,7 @@ unit-test: coverage.txt
exit -1; \
fi \
done;

PHONY += tss-example
tss-example:
cd example && go build
12 changes: 12 additions & 0 deletions crypto/tss/message/types/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,18 @@ const (
StateFailed MainState = 20
)

func (m MainState) String() string {
switch m {
case StateInit:
return "Init"
case StateDone:
return "Done"
case StateFailed:
return "Failed"
}
return "Unknown"
}

//go:generate mockery -name=StateChangedListener
type StateChangedListener interface {
OnStateChanged(oldState MainState, newState MainState)
Expand Down
28 changes: 28 additions & 0 deletions example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# TSS example

This example demonstrates a simple p2p application using our TSS library. Let's assume we have 3 nodes where their ranks are all 0. These 3 nodes will interact with each other by using `go-libp2p` library. After each process (DKG, signer, and reshare), the results will be written in files located in `config/`.

## Build
```sh
> make tss-example
```

## Usage
### DKG

First, we run 3 hosts on different terminals. These 3 nodes will try to connect to each other. Once it connects to a peer, it will send the peer message out. After the peer messages are fully transmitted, each node will try to get the result and write it to the respective config file.

On node A,
```sh
> ./example -config config/id-1.yaml
```

On node B,
```sh
> ./example -config config/id-2.yaml
```

On node C,
```sh
> ./example -config config/id-3.yaml
```
68 changes: 68 additions & 0 deletions example/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright © 2020 AMIS Technologies
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main

import (
"io/ioutil"

"gopkg.in/yaml.v2"
)

type Threshold struct {
DKG uint32 `yaml:"dkg"`
Signer uint32 `yaml:"signer"`
Reshare uint32 `yaml:"reshare"`
}

type Pubkey struct {
X string `yaml:"x"`
Y string `yaml:"y"`
}

type DKGResult struct {
Share string `yaml:"share"`
Pubkey Pubkey `yaml:"pubkey"`
BKs map[string]string `yaml:"bks"`
}

type Config struct {
Port int64 `yaml:"port"`
Rank uint32 `yaml:"rank"`
Threshold Threshold `yaml:"threshold"`
Peers []int64 `yaml:"peers"`
DKGResult DKGResult `yaml:"dkgResult"`
}

func readYamlFile(filaPath string) (*Config, error) {
c := &Config{}
yamlFile, err := ioutil.ReadFile(filaPath)
if err != nil {
return nil, err
}
err = yaml.Unmarshal(yamlFile, c)
if err != nil {
return nil, err
}

return c, nil
}

func writeYamlFile(yamlData interface{}, filaPath string) error {
data, err := yaml.Marshal(yamlData)
if err != nil {
return err
}
ioutil.WriteFile(filaPath, data, 0644)
return nil
}
9 changes: 9 additions & 0 deletions example/config/id-1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
port: 10001
rank: 0
threshold:
dkg: 3
signer: 2
reshare: 3
peers:
- 10002
- 10003
9 changes: 9 additions & 0 deletions example/config/id-2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
port: 10002
rank: 0
threshold:
dkg: 3
signer: 2
reshare: 3
peers:
- 10001
- 10003
9 changes: 9 additions & 0 deletions example/config/id-3.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
port: 10003
rank: 0
threshold:
dkg: 3
signer: 2
reshare: 3
peers:
- 10001
- 10002
67 changes: 67 additions & 0 deletions example/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright © 2020 AMIS Technologies
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main

import (
"flag"

"github.com/getamis/sirius/log"
"github.com/libp2p/go-libp2p-core/network"
)

const (
dkgProtocol = "/dkg/1.0.0"
)

func main() {
configPath := flag.String("config", "", "config path")
flag.Parse()
if *configPath == "" {
log.Crit("empty config path")
}

config, err := readYamlFile(*configPath)
if err != nil {
log.Crit("Failed to read config file", "configPath", *configPath, err)
}

// Make a host that listens on the given multiaddress.
host, err := makeBasicHost(config.Port)
if err != nil {
log.Crit("Failed to create a basic host", "err", err)
}

// Create a new peer manager.
pm := newPeerManager(getPeerIDFromPort(config.Port), host)
err = pm.addPeers(config.Peers)
if err != nil {
log.Crit("Failed to add peers", "err", err)
}

// Create a new service.
service, err := NewService(config, pm)
if err != nil {
log.Crit("Failed to new service", "err", err)
}
// Set a stream handler on the host.
host.SetStreamHandler(dkgProtocol, func(s network.Stream) {
service.Handle(s)
})

// Ensure all peers are connected before starting DKG process.
pm.EnsureAllConnected()

// Start DKG process.
service.Process()
}
150 changes: 150 additions & 0 deletions example/node.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
// Copyright © 2020 AMIS Technologies
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main

import (
"context"
"fmt"
"math/rand"

"github.com/getamis/sirius/log"
ggio "github.com/gogo/protobuf/io"
"github.com/golang/protobuf/proto"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p-core/crypto"
"github.com/libp2p/go-libp2p-core/helpers"
"github.com/libp2p/go-libp2p-core/host"
"github.com/libp2p/go-libp2p-core/peer"
"github.com/multiformats/go-multiaddr"
)

// makeBasicHost creates a LibP2P host.
func makeBasicHost(port int64) (host.Host, error) {
sourceMultiAddr, err := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port))
if err != nil {
return nil, err
}

priv, err := generateIdentity(port)
if err != nil {
return nil, err
}

opts := []libp2p.Option{
libp2p.ListenAddrs(sourceMultiAddr),
libp2p.Identity(priv),
}

basicHost, err := libp2p.New(context.Background(), opts...)
if err != nil {
return nil, err
}

return basicHost, nil
}

// getPeerAddr gets peer full address from port.
func getPeerAddr(port int64) (string, error) {
priv, err := generateIdentity(port)
if err != nil {
return "", err
}

pid, err := peer.IDFromPrivateKey(priv)
if err != nil {
return "", err
}
return fmt.Sprintf("/ip4/127.0.0.1/tcp/%d/p2p/%s", port, pid), nil
}

// getPeerIDFromPort gets peer ID from port.
func getPeerIDFromPort(port int64) string {
// For convenience, we set peer ID as "id-" + port
return fmt.Sprintf("id-%d", port)
}

// generateIdentity generates a fixed key pair by using port as random source.
func generateIdentity(port int64) (crypto.PrivKey, error) {
// Use the port as the randomness source in this example.
r := rand.New(rand.NewSource(port))

// Generate a key pair for this host.
priv, _, err := crypto.GenerateKeyPairWithReader(crypto.ECDSA, 2048, r)
if err != nil {
return nil, err
}
return priv, nil
}

// send sends the proto message to specified peer.
func send(ctx context.Context, host host.Host, target string, data proto.Message) error {
// Turn the destination into a multiaddr.
maddr, err := multiaddr.NewMultiaddr(target)
if err != nil {
log.Warn("Cannot parse the target address", "target", target, "err", err)
return err
}

// Extract the peer ID from the multiaddr.
info, err := peer.AddrInfoFromP2pAddr(maddr)
if err != nil {
log.Warn("Cannot parse addr", "addr", maddr, "err", err)
return err
}

s, err := host.NewStream(ctx, info.ID, dkgProtocol)
if err != nil {
log.Warn("Cannot create a new stream", "from", host.ID(), "to", target, "err", err)
return err
}
writer := ggio.NewFullWriter(s)
err = writer.WriteMsg(data)
if err != nil {
log.Warn("Cannot write message to IO", "err", err)
return err
}
err = helpers.FullClose(s)
if err != nil {
log.Warn("Cannot close the stream", "err", err)
return err
}

log.Info("Sent message", "peer", target)
return nil
}

// connect connects the host to the specified peer.
func connect(ctx context.Context, host host.Host, target string) error {
// Turn the destination into a multiaddr.
maddr, err := multiaddr.NewMultiaddr(target)
if err != nil {
log.Warn("Cannot parse the target address", "target", target, "err", err)
return err
}

// Extract the peer ID from the multiaddr.
info, err := peer.AddrInfoFromP2pAddr(maddr)
if err != nil {
log.Error("Cannot parse addr", "addr", maddr, "err", err)
return err
}

// Connect the host to the peer.
err = host.Connect(ctx, *info)
if err != nil {
log.Warn("Failed to connect to peer", "err", err)
return err
}
return nil
}
Loading

0 comments on commit a648212

Please sign in to comment.