Skip to content

Commit

Permalink
MAM handling layer (#119)
Browse files Browse the repository at this point in the history
* started implementation of stateful mam

* mam: refactored state into transmitter

* fixed transmitter

* fixed tests

* implemented MAM receiver

* refactored channel and transmitter

* implemented private and restricted modes

* tidy dependency

* Update mam/v1/receiver.go

Co-Authored-By: Luca Moser <[email protected]>

* Update mam/v1/receiver.go

Co-Authored-By: Luca Moser <[email protected]>

* Update mam/v1/transmitter.go

Co-Authored-By: Luca Moser <[email protected]>

* fixed several small subjects

* updated gitignore

* improved transmitter's set mode method

* fixed bug in receiver
  • Loading branch information
phifty authored and luca-moser committed Sep 23, 2019
1 parent c5a0c53 commit 51b838c
Show file tree
Hide file tree
Showing 15 changed files with 972 additions and 12 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@
*.dylib
*.test
*.out
.experimental/
.experimental/
examples/mam-transmit/transmit.sh
examples/mam-receive/receive.sh
62 changes: 62 additions & 0 deletions examples/mam-receive/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package main

import (
"flag"
"fmt"
"log"
"time"

"github.com/simia-tech/env"

"github.com/iotaledger/iota.go/api"
"github.com/iotaledger/iota.go/mam/v1"
)

var (
endpointURL = env.String("ENDPOINT_URL", "https://nodes.thetangle.org:443")
mode = env.String("MODE", "public", env.AllowedValues("public", "private", "restricted"))
sideKey = env.String("SIDE_KEY", "")
)

func main() {
follow := flag.Bool("f", false, "don't exit and check every second for new messages")
flag.Parse()
root := flag.Arg(0)

cm, err := mam.ParseChannelMode(mode.Get())
if err != nil {
log.Fatal(err)
}

api, err := api.ComposeAPI(api.HTTPClientSettings{
URI: endpointURL.Get(),
})
if err != nil {
log.Fatal(err)
}

receiver := mam.NewReceiver(api)
if err := receiver.SetMode(cm, sideKey.Get()); err != nil {
log.Fatal(err)
}

fmt.Printf("receive root %q from %s channel...\n", root, cm)
loop:
nextRoot, messages, err := receiver.Receive(root)
if err != nil {
log.Fatal(err)
}
for _, message := range messages {
fmt.Println(message)
}
if *follow {
time.Sleep(time.Second)
if len(messages) > 0 {
root = nextRoot
}
goto loop
}
if len(messages) == 0 {
fmt.Println("no messages found")
}
}
56 changes: 56 additions & 0 deletions examples/mam-transmit/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package main

import (
"flag"
"fmt"
"log"

"github.com/simia-tech/env"

"github.com/iotaledger/iota.go/api"
"github.com/iotaledger/iota.go/consts"
"github.com/iotaledger/iota.go/mam/v1"
"github.com/iotaledger/iota.go/pow"
)

var (
endpointURL = env.String("ENDPOINT_URL", "https://nodes.thetangle.org:443")
seed = env.String("SEED", "")
mwm = env.Int("MWM", 9)
mode = env.String("MODE", "public", env.AllowedValues("public", "private", "restricted"))
sideKey = env.String("SIDE_KEY", "")
)

func main() {
flag.Parse()
messages := flag.Args()

cm, err := mam.ParseChannelMode(mode.Get())
if err != nil {
log.Fatal(err)
}

_, powFunc := pow.GetFastestProofOfWorkImpl()

api, err := api.ComposeAPI(api.HTTPClientSettings{
URI: endpointURL.Get(),
LocalProofOfWorkFunc: powFunc,
})
if err != nil {
log.Fatal(err)
}

transmitter := mam.NewTransmitter(api, seed.Get(), uint64(mwm.Get()), consts.SecurityLevelMedium)
if err := transmitter.SetMode(cm, sideKey.Get()); err != nil {
log.Fatal(err)
}

for _, message := range messages {
fmt.Printf("transmit message %q to %s channel...\n", message, cm)
root, err := transmitter.Transmit(message)
if err != nil {
log.Fatal(err)
}
fmt.Printf("transmitted to root %q\n", root)
}
}
7 changes: 5 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,24 @@ go 1.12

require (
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9 // indirect
github.com/apsdehal/go-logger v0.0.0-20190506062552-f85330a4b532 // indirect
github.com/beevik/ntp v0.2.0
github.com/cespare/xxhash v1.1.0
github.com/dgraph-io/badger v1.5.4
github.com/dgryski/go-farm v0.0.0-20190323231341-8198c7b169ec // indirect
github.com/go-stack/stack v1.8.0 // indirect
github.com/golang/snappy v0.0.1 // indirect
github.com/google/go-cmp v0.2.0 // indirect
github.com/onsi/ginkgo v1.8.0
github.com/onsi/gomega v1.5.0
github.com/pkg/errors v0.8.1
github.com/simia-tech/env v0.1.0
github.com/stretchr/testify v1.3.0 // indirect
github.com/tidwall/pretty v1.0.0 // indirect
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c // indirect
github.com/xdg/stringprep v1.0.0 // indirect
go.mongodb.org/mongo-driver v1.0.0
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5 // indirect
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 // indirect
golang.org/x/net v0.0.0-20190311183353-d8887717615a // indirect
golang.org/x/sync v0.0.0-20190423024810-112230192c58 // indirect
gopkg.in/h2non/gock.v1 v1.0.14
)
21 changes: 17 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,28 @@ github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9 h1:HD8gA2tkBy
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/apsdehal/go-logger v0.0.0-20190506062552-f85330a4b532 h1:xTYdKP4GbVSANiKn8bdlBzQp08Nq8I1wlB49Dunh0QA=
github.com/apsdehal/go-logger v0.0.0-20190506062552-f85330a4b532/go.mod h1:U3/8D6R9+bVpX0ORZjV+3mU9pQ86m7h1lESgJbXNvXA=
github.com/beevik/ntp v0.2.0 h1:sGsd+kAXzT0bfVfzJfce04g+dSRfrs+tbQW8lweuYgw=
github.com/beevik/ntp v0.2.0/go.mod h1:hIHWr+l3+/clUnF44zdK+CWW7fO8dR5cIylAQ76NRpg=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgraph-io/badger v1.5.4 h1:gVTrpUTbbr/T24uvoCaqY2KSHfNLVGm0w+hbee2HMeg=
github.com/dgraph-io/badger v1.5.4/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ=
github.com/dgryski/go-farm v0.0.0-20190323231341-8198c7b169ec h1:sElGDs3V8VdCxH5tWi0ycWJzteOPLJ3HtItSSKI95PY=
github.com/dgryski/go-farm v0.0.0-20190323231341-8198c7b169ec/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
Expand All @@ -36,29 +39,39 @@ github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/simia-tech/env v0.1.0 h1:QTq3uAvWT0HUMgH6VWQmOOdb81tjizFKNmaQNOuPu90=
github.com/simia-tech/env v0.1.0/go.mod h1:eVRQ7W5NXXHifpPAcTJ3r5EmoGgMn++dXfSVbZv3Opo=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c h1:u40Z8hqBAAQyv+vATcGgV0YCnDjqSL7/q/JyPhhJSPk=
github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
github.com/xdg/stringprep v1.0.0 h1:d9X0esnoa3dFsV0FG35rAT0RIhYFlPq7MiP+DW89La0=
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
go.mongodb.org/mongo-driver v1.0.0 h1:KxPRDyfB2xXnDE2My8acoOWBQkfv3tz0SaWTRZjJR0c=
go.mongodb.org/mongo-driver v1.0.0/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5 h1:bselrhR0Or1vomJZC8ZIjWtbDmn9OYFLX5Ik9alpJpE=
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd h1:nTDtHvHSdCn1m6ITfMRqtOd/9+7a3s8RBNOZ3eYZzJA=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e h1:nFYrTHrdrAOpShe27kaFHjsqYSEQ0KWqdWLu3xuZJts=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
Expand Down
47 changes: 47 additions & 0 deletions mam/v1/address.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package mam

import (
"github.com/iotaledger/iota.go/address"
"github.com/iotaledger/iota.go/consts"
"github.com/iotaledger/iota.go/curl"
"github.com/iotaledger/iota.go/trinary"
)

func makeAddress(mode ChannelMode, root trinary.Trits, sideKey trinary.Trytes) (trinary.Trytes, error) {
if mode == ChannelModePublic {
return toAddress(root)
}

sideKeyTrits, err := trinary.TrytesToTrits(sideKey)
if err != nil {
return "", err
}

h := curl.NewCurlP81()
if err := h.Absorb(sideKeyTrits); err != nil {
return "", err
}
if err := h.Absorb(root); err != nil {
return "", err
}
hashedRoot, err := h.Squeeze(consts.HashTrinarySize)
if err != nil {
return "", err
}

return toAddress(hashedRoot)
}

func toAddress(root trinary.Trits) (trinary.Trytes, error) {
rootTrytes, err := trinary.TritsToTrytes(root)
if err != nil {
return "", err
}

chkSum, err := address.Checksum(rootTrytes)
if err != nil {
return "", err
}

return rootTrytes + chkSum, nil
}
15 changes: 15 additions & 0 deletions mam/v1/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package mam

import (
"github.com/iotaledger/iota.go/api"
"github.com/iotaledger/iota.go/bundle"
"github.com/iotaledger/iota.go/transaction"
"github.com/iotaledger/iota.go/trinary"
)

// API defines an interface with a subset of methods of `api.API`.
type API interface {
PrepareTransfers(seed trinary.Trytes, transfers bundle.Transfers, opts api.PrepareTransfersOptions) ([]trinary.Trytes, error)
SendTrytes(trytes []trinary.Trytes, depth uint64, mwm uint64, reference ...trinary.Hash) (bundle.Bundle, error)
FindTransactionObjects(query api.FindTransactionsQuery) (transaction.Transactions, error)
}
56 changes: 56 additions & 0 deletions mam/v1/api_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package mam_test

import (
"github.com/pkg/errors"

"github.com/iotaledger/iota.go/api"
"github.com/iotaledger/iota.go/bundle"
"github.com/iotaledger/iota.go/transaction"
"github.com/iotaledger/iota.go/trinary"
)

type fakeAPI struct {
prepareTransfers func(trinary.Trytes, bundle.Transfers, api.PrepareTransfersOptions) ([]trinary.Trytes, error)
sendTrytes func([]trinary.Trytes, uint64, uint64, ...trinary.Hash) (bundle.Bundle, error)
findTransactionObjects func(api.FindTransactionsQuery) (transaction.Transactions, error)
}

func newFakeAPI() *fakeAPI {
return &fakeAPI{
prepareTransfers: func(_ trinary.Trytes, _ bundle.Transfers, _ api.PrepareTransfersOptions) ([]trinary.Trytes, error) {
return nil, errors.New("not implemented")
},
sendTrytes: func(_ []trinary.Trytes, _ uint64, _ uint64, _ ...trinary.Hash) (bundle.Bundle, error) {
return nil, errors.New("not implemented")
},
findTransactionObjects: func(_ api.FindTransactionsQuery) (transaction.Transactions, error) {
return nil, errors.New("not implemented")
},
}
}

func (f *fakeAPI) PrepareTransfers(seed trinary.Trytes, transfers bundle.Transfers, opts api.PrepareTransfersOptions) ([]trinary.Trytes, error) {
return f.prepareTransfers(seed, transfers, opts)
}

func (f *fakeAPI) SendTrytes(trytes []trinary.Trytes, depth uint64, mwm uint64, reference ...trinary.Hash) (bundle.Bundle, error) {
return f.sendTrytes(trytes, depth, mwm, reference...)
}

func (f *fakeAPI) FindTransactionObjects(query api.FindTransactionsQuery) (transaction.Transactions, error) {
return f.findTransactionObjects(query)
}

func err(returns []interface{}) error {
if len(returns) == 0 {
return nil
}
last := returns[len(returns)-1]
if last == nil {
return nil
}
if e, ok := last.(error); ok {
return e
}
return nil
}
42 changes: 42 additions & 0 deletions mam/v1/channel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package mam

import (
"github.com/iotaledger/iota.go/consts"
"github.com/iotaledger/iota.go/trinary"
)

type channel struct {
mode ChannelMode
sideKey trinary.Trytes
nextRoot trinary.Trits
securityLevel consts.SecurityLevel
start uint64
count uint64
nextCount uint64
index uint64
}

func newChannel(securityLevel consts.SecurityLevel) *channel {
return &channel{
mode: ChannelModePublic,
sideKey: consts.NullHashTrytes,
securityLevel: securityLevel,
start: 0,
count: 1,
nextCount: 1,
index: 0,
}
}

func (c *channel) incIndex() {
if c.index == c.count-1 {
c.start += c.nextCount
c.index = 0
} else {
c.index++
}
}

func (c *channel) nextStart() uint64 {
return c.start + c.count
}
Loading

0 comments on commit 51b838c

Please sign in to comment.