Skip to content

Commit

Permalink
Adding personhood service
Browse files Browse the repository at this point in the history
The personhood service is a first example of how to use pop-tokens and pop-coins. For the first two services, we chose a messaging and a questionnaire service.
  • Loading branch information
ineiti committed Sep 11, 2018
1 parent 268fe15 commit 89f6e29
Show file tree
Hide file tree
Showing 25 changed files with 2,014 additions and 216 deletions.
4 changes: 2 additions & 2 deletions Makefile
Expand Up @@ -9,10 +9,10 @@ EXCLUDE_LINT = "should be.*UI|_test.go"
# for more than once in Travis. Change `make test` in .travis.yml # for more than once in Travis. Change `make test` in .travis.yml
# to `make test_playground`. # to `make test_playground`.
test_playground: test_playground:
cd omniledger/simulation; \ cd personhood; \
for a in $$( seq 100 ); do \ for a in $$( seq 100 ); do \
# if DEBUG_TIME=true go test -v -race > log.txt 2>&1; then \ # if DEBUG_TIME=true go test -v -race > log.txt 2>&1; then \
if DEBUG_TIME=true go test -v -race; then \ if DEBUG_TIME=true go test -v -race > log.txt 2>&1; then \
echo Successfully ran \#$$a at $$(date); \ echo Successfully ran \#$$a at $$(date); \
else \ else \
echo Failed at $$(date); \ echo Failed at $$(date); \
Expand Down
2 changes: 1 addition & 1 deletion conode/setup-then-start.sh
Expand Up @@ -4,4 +4,4 @@ if [ ! -f /conode_data/private.toml ]; then
./conode setup --non-interactive ./conode setup --non-interactive
fi fi


./conode -debug 3 server ./conode -debug 2 server
Expand Up @@ -29,11 +29,13 @@ class CalypsoTest {
class Pair<A, B> { class Pair<A, B> {
A a; A a;
B b; B b;

Pair(A a, B b) { Pair(A a, B b) {
this.a = a; this.a = a;
this.b = b; this.b = b;
} }
} }

private OmniledgerRPC ol; private OmniledgerRPC ol;
private CreateLTSReply ltsReply; private CreateLTSReply ltsReply;
private Darc testDarc; private Darc testDarc;
Expand Down Expand Up @@ -103,9 +105,9 @@ void testDecryptKey() throws Exception {
} }


Pair<WriteRequest, WriterInstance> createWriterInstance(String secret) throws Exception { Pair<WriteRequest, WriterInstance> createWriterInstance(String secret) throws Exception {
WriteRequest wr = new WriteRequest(secret, 16, genesisDarc.getId()); WriteRequest wr = new WriteRequest(secret, 16, testDarc.getId());
WriterInstance w = new WriterInstance(ol, Arrays.asList(admin), genesisDarc.getId(), ltsReply, wr); WriterInstance w = new WriterInstance(ol, Arrays.asList(testSigner), testDarc.getId(), ltsReply, wr);

Proof p = ol.getProof(w.getInstance().getId()); Proof p = ol.getProof(w.getInstance().getId());
assertTrue(p.matches()); assertTrue(p.matches());


Expand Down
1 change: 0 additions & 1 deletion identity/api_test.go
Expand Up @@ -152,7 +152,6 @@ func TestIdentity_DataNewCheck(t *testing.T) {
defer l.CloseAll() defer l.CloseAll()


c1 := createIdentity(l, services, roster, "one") c1 := createIdentity(l, services, roster, "one")

data2 := c1.Data.Copy() data2 := c1.Data.Copy()
kp2 := key.NewKeyPair(tSuite) kp2 := key.NewKeyPair(tSuite)
data2.Device["two"] = &Device{kp2.Public} data2.Device["two"] = &Device{kp2.Public}
Expand Down
89 changes: 56 additions & 33 deletions identity/db.go
Expand Up @@ -9,58 +9,81 @@ import (
"github.com/dedis/kyber/sign/anon" "github.com/dedis/kyber/sign/anon"
"github.com/dedis/kyber/util/key" "github.com/dedis/kyber/util/key"
"github.com/dedis/onet" "github.com/dedis/onet"
"github.com/dedis/onet/log"
"github.com/dedis/onet/network" "github.com/dedis/onet/network"
"github.com/dedis/protobuf" "github.com/dedis/protobuf"
) )


// DB-versioning, allows propoer passage from one version to another. This example
// shows how to handle the case where there was no previous versioning in the
// database, and we already have two possible incompatible versions out there,
// version 0a and 0b. Version 1 will be the correct one.
//
// loadVersion starts trying to get version 1, but only if the database returns
// the correct version. If the version is 0 (or nonexistant), then it calls first
// updateFrom0a, if that fails it tries updateFrom0b and if all fails it returns an error.
//
// In case of a future incompatible change, one would have to add `updateFrom1` which
// would call `updateFrom0` if the version < 1. `updateFrom1` would return `storage2`.
// And the `Service` structure would use `storage2` for the up-to-date storage
// version.

const dbVersion = 1 const dbVersion = 1


var storageKey = []byte("storage") var storageKey = []byte("storage")
var versionKey = []byte("version")


func loadVersion(l onet.ContextDB) (*storage1, error) { func init() {
vers, err := l.LoadVersion() network.RegisterMessage(&storage1{})
}

// saves all data.
func (s *Service) save() error {
s.storageMutex.Lock()
defer s.storageMutex.Unlock()
err := s.Save(storageKey, s.Storage)
if err != nil {
log.Error("Couldn't save data:", err)
}
return nil
}

// Tries to load the configuration and updates the data in the service
// if it finds a valid config-file.
func (s *Service) tryLoad() error {
s.Storage = &storage1{}
defer func() {
if s.Storage.Identities == nil {
s.Storage.Identities = make(map[string]*IDBlock)
}
if s.Storage.Auth == nil {
s.Storage.Auth = &authData1{}
}
if len(s.Storage.Auth.Pins) == 0 {
s.Storage.Auth.Pins = map[string]bool{}
}
if len(s.Storage.Auth.Nonces) == 0 {
s.Storage.Auth.Nonces = map[string]bool{}
}
if s.Storage.Auth.Sets == nil {
s.Storage.Auth.Sets = []anonSet1{}
}
if s.Storage.Auth.AdminKeys == nil {
s.Storage.Auth.AdminKeys = []kyber.Point{}
}
}()
ver, err := s.LoadVersion()
if err != nil { if err != nil {
return nil, err return err
} }
if vers < dbVersion { if ver < dbVersion {
storage, err := updateFrom0(l, vers) // There are two version 0s...
s.Storage, err = updateFrom0(s, ver)
if err != nil { if err != nil {
return nil, err return err
} }

if err = s.save(); err != nil {
// TODO: this is really ugly... return err
if c, ok := l.(*onet.Context); ok {
err = c.Save(storageKey, storage)
} }
err = l.SaveVersion(dbVersion) return s.SaveVersion(dbVersion)
return storage, err
} }
sInt, err := l.Load(storageKey) buf, err := s.LoadRaw(storageKey)
if err != nil { if err != nil {
return nil, err return err
} }
if sInt == nil { if len(buf) <= 16 {
return &storage1{}, nil return nil
} }
return sInt.(*storage1), err return protobuf.DecodeWithConstructors(buf[16:], s.Storage,
network.DefaultConstructors(cothority.Suite))
} }


// storage1 holds the map to the storages so it can be marshaled. // storage2 holds the map to the storages so it can be marshaled.
type storage1 struct { type storage1 struct {
Identities map[string]*IDBlock Identities map[string]*IDBlock
// The key that is stored in the skipchain service to authenticate // The key that is stored in the skipchain service to authenticate
Expand Down
4 changes: 2 additions & 2 deletions identity/db_test.go
Expand Up @@ -39,7 +39,7 @@ func TestLoadVersion(t *testing.T) {
require.Nil(t, err) require.Nil(t, err)
ml.data[string(storageKey)] = s0aBuf ml.data[string(storageKey)] = s0aBuf


storage, err := loadVersion(ml) storage, err := updateFrom0(ml, 1)
require.Nil(t, err) require.Nil(t, err)
require.True(t, s0a.SkipchainKeyPair.Public.Equal(storage.SkipchainKeyPair.Public)) require.True(t, s0a.SkipchainKeyPair.Public.Equal(storage.SkipchainKeyPair.Public))
require.Equal(t, s0a.Identities["abc"].Latest.Threshold, require.Equal(t, s0a.Identities["abc"].Latest.Threshold,
Expand Down Expand Up @@ -68,7 +68,7 @@ func TestLoadVersion(t *testing.T) {
ml.data[string(storageKey)] = s0bBuf ml.data[string(storageKey)] = s0bBuf
ml.SaveVersion(0) ml.SaveVersion(0)


storage, err = loadVersion(ml) storage, err = updateFrom0(ml, 1)
require.Nil(t, err) require.Nil(t, err)
require.True(t, s0b.SkipchainKeyPair.Public.Equal(storage.SkipchainKeyPair.Public)) require.True(t, s0b.SkipchainKeyPair.Public.Equal(storage.SkipchainKeyPair.Public))
require.Equal(t, s0b.Identities["abc"].Latest.Threshold, require.Equal(t, s0b.Identities["abc"].Latest.Threshold,
Expand Down
44 changes: 1 addition & 43 deletions identity/service.go
Expand Up @@ -686,9 +686,9 @@ func (s *Service) getIdentityStorage(id ID) *IDBlock {
// setIdentityStorage saves an IdentityStorage // setIdentityStorage saves an IdentityStorage
func (s *Service) setIdentityStorage(id ID, is *IDBlock) { func (s *Service) setIdentityStorage(id ID, is *IDBlock) {
s.storageMutex.Lock() s.storageMutex.Lock()
defer s.storageMutex.Unlock()
log.Lvlf3("%s %x %v", s.Context.ServerIdentity(), id[0:8], is.Latest.Device) log.Lvlf3("%s %x %v", s.Context.ServerIdentity(), id[0:8], is.Latest.Device)
s.Storage.Identities[string(id)] = is s.Storage.Identities[string(id)] = is
s.storageMutex.Unlock()
s.save() s.save()
} }


Expand All @@ -709,52 +709,10 @@ func (s *Service) verifySkipchainAuth() kyber.Scalar {
return nil return nil
} }


// saves the actual identity
func (s *Service) save() {
log.Lvl3("Saving service")
err := s.Save(storageKey, s.Storage)
if err != nil {
log.Error("Couldn't save file:", err)
}
}

func (s *Service) clearIdentities() { func (s *Service) clearIdentities() {
s.Storage.Identities = make(map[string]*IDBlock) s.Storage.Identities = make(map[string]*IDBlock)
} }


// Tries to load the configuration and updates if a configuration
// is found, else it returns an error.
func (s *Service) tryLoad() error {
var err error
s.Storage, err = loadVersion(s)
if err != nil {
return err
}
if s.Storage == nil {
s.Storage = &storage1{}
}
if s.Storage.Identities == nil {
s.Storage.Identities = make(map[string]*IDBlock)
}
if s.Storage.Auth == nil {
s.Storage.Auth = &authData1{}
}
if len(s.Storage.Auth.Pins) == 0 {
s.Storage.Auth.Pins = map[string]bool{}
}
if len(s.Storage.Auth.Nonces) == 0 {
s.Storage.Auth.Nonces = map[string]bool{}
}
if s.Storage.Auth.Sets == nil {
s.Storage.Auth.Sets = []anonSet1{}
}
if s.Storage.Auth.AdminKeys == nil {
s.Storage.Auth.AdminKeys = []kyber.Point{}
}
log.Lvl3("Successfully loaded")
return nil
}

func newIdentityService(c *onet.Context) (onet.Service, error) { func newIdentityService(c *onet.Context) (onet.Service, error) {
s := &Service{ s := &Service{
ServiceProcessor: onet.NewServiceProcessor(c), ServiceProcessor: onet.NewServiceProcessor(c),
Expand Down
11 changes: 5 additions & 6 deletions omniledger/contracts/coins.go
Expand Up @@ -101,11 +101,6 @@ func ContractCoin(cdb ol.CollectionView, inst ol.Instruction, c []ol.Coin) (sc [
} }
case "transfer": case "transfer":
// transfer sends a given amount of coins to another account. // transfer sends a given amount of coins to another account.
err = ci.SafeSub(coinsArg)
if err != nil {
return
}

target := inst.Invoke.Args.Search("destination") target := inst.Invoke.Args.Search("destination")
var ( var (
v []byte v []byte
Expand All @@ -125,6 +120,10 @@ func ContractCoin(cdb ol.CollectionView, inst ol.Instruction, c []ol.Coin) (sc [
if err != nil { if err != nil {
return nil, nil, errors.New("couldn't unmarshal target account: " + err.Error()) return nil, nil, errors.New("couldn't unmarshal target account: " + err.Error())
} }
err = ci.SafeSub(coinsArg)
if err != nil {
return
}
err = targetCI.SafeAdd(coinsArg) err = targetCI.SafeAdd(coinsArg)
if err != nil { if err != nil {
return return
Expand All @@ -134,7 +133,7 @@ func ContractCoin(cdb ol.CollectionView, inst ol.Instruction, c []ol.Coin) (sc [
return nil, nil, errors.New("couldn't marshal target account: " + err.Error()) return nil, nil, errors.New("couldn't marshal target account: " + err.Error())
} }


log.Lvlf3("transferring %d to %x", coinsArg, target) log.Lvlf1("transferring %d to %x", coinsArg, target)
sc = append(sc, ol.NewStateChange(ol.Update, ol.NewInstanceID(target), sc = append(sc, ol.NewStateChange(ol.Update, ol.NewInstanceID(target),
ContractCoinID, targetBuf, did)) ContractCoinID, targetBuf, did))
case "fetch": case "fetch":
Expand Down
111 changes: 111 additions & 0 deletions omniledger/ol/lib/config.go
@@ -0,0 +1,111 @@
package lib

import (
"fmt"
"io/ioutil"
"os"
"path/filepath"

"github.com/dedis/cothority"
"github.com/dedis/cothority/omniledger/darc"
ol "github.com/dedis/cothority/omniledger/service"
"github.com/dedis/cothority/skipchain"
"github.com/dedis/onet"
"github.com/dedis/onet/network"
"github.com/dedis/protobuf"
)

// ConfigPath points to where the files will be stored by default.
var ConfigPath = "."

// Config is the structure used by ol to save its configuration. It holds everything
// necessary to talk to an omniledger instance. The GenesisDarc and AdminIdentity
// can change over the time of an omniledger.
type Config struct {
Roster onet.Roster
OmniledgerID skipchain.SkipBlockID
GenesisDarc darc.Darc
AdminIdentity darc.Identity
}

// LoadKey returns the signer of a given identity. It searches it in the ConfigPath.
func LoadKey(id darc.Identity) (*darc.Signer, error) {
// Find private key file.
fn := fmt.Sprintf("key-%s.cfg", id)
fn = filepath.Join(ConfigPath, fn)
return LoadSigner(fn)
}

// LoadSigner loads a signer from a file given by fn.
func LoadSigner(fn string) (*darc.Signer, error) {
buf, err := ioutil.ReadFile(fn)
if err != nil {
return nil, err
}

var signer darc.Signer
err = protobuf.DecodeWithConstructors(buf, &signer,
network.DefaultConstructors(cothority.Suite))
return &signer, err
}

// SaveKey stores a signer in a file.
func SaveKey(signer darc.Signer) error {
os.MkdirAll(ConfigPath, 0755)

fn := fmt.Sprintf("key-%s.cfg", signer.Identity())
fn = filepath.Join(ConfigPath, fn)

// perms = 0400 because there is key material inside this file.
f, err := os.OpenFile(fn, os.O_RDWR|os.O_CREATE, 0400)
if err != nil {
return fmt.Errorf("could not write %v: %v", fn, err)
}

buf, err := protobuf.Encode(&signer)
if err != nil {
return err
}
_, err = f.Write(buf)
if err != nil {
return err
}
return f.Close()
}

// SaveConfig stores the config in the ConfigPath directory. It returns the
// pathname of the stored file.
func SaveConfig(cfg Config) (string, error) {
os.MkdirAll(ConfigPath, 0755)

fn := fmt.Sprintf("ol-%x.cfg", cfg.OmniledgerID)
fn = filepath.Join(ConfigPath, fn)

buf, err := protobuf.Encode(&cfg)
if err != nil {
return fn, err
}
err = ioutil.WriteFile(fn, buf, 0644)
if err != nil {
return fn, err
}

return fn, nil
}

// LoadConfig returns a config read from the file and an initialized omniledger
// Client that can be used to communicate with omniledger.
func LoadConfig(file string) (cfg Config, cl *ol.Client, err error) {
var cfgBuf []byte
cfgBuf, err = ioutil.ReadFile(file)
if err != nil {
return
}
err = protobuf.DecodeWithConstructors(cfgBuf, &cfg,
network.DefaultConstructors(cothority.Suite))
if err != nil {
return
}
cl = ol.NewClient(cfg.OmniledgerID, cfg.Roster)
return
}

0 comments on commit 89f6e29

Please sign in to comment.