8000 Add example by bun919tw · Pull Request #38 · getamis/alice · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add example #38

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
5D39
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can move send() and connect() to pm.go? only peer manager needs these two methods.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I put these two functions in node.go because I think they are related to p2p.

//
// 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