Skip to content
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

mamgoiota commit #28

Closed
wants to merge 3 commits into from
Closed
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
141 changes: 141 additions & 0 deletions mamgoiota/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# mamgoiota

Small project to implement Masked Authenticated Messaging on the IOTA tangle with Golang.

This project is still under construction (see TODO) with the aim to get IoT sensors and devices to send MAMs.

## Install

It is assumed that you have Golang installed. You also need to install the Go library API for IOTA which you can download at:

```javascript
go get -u github.com/iotaledger/giota
```

After that you can download the mamgoiota package.

```javascript
go get -u github.com/habpygo/mamgoiota
```

To be able to do testing and assertions you have to install the `stretchr` package

```javascript
go get -u github.com/stretchr/testify
```


## Sending MAMs to the IOTA tangle with Go

### API

#### Create a new Connection
```go
import "github.com/iotaledger/mamgoiota"

func main(){
c, err := mamgoiota.NewConnection("someNodeURL", "yourSeed")
if c != nil && err == nil{
fmt.Println("Connection is valid")
}
}
```
If you don't have a nodeURL try out one from: http://iotasupport.com/lightwallet.shtml

If you don't have a seed yet, follow the description here: https://iota.readme.io/docs/securely-generating-a-seed

Please keep in mind that you may NEVER loose this seed nor give it to anybody else, because the seed is the connection to your funds!

WARNING: Nodes have a nasty habit to go on/off line without warning or notice. If this happens try to find another one.


#### Send a MAM to the IOTA tangle
```go
import "github.com/iotaledger/mamgoiota"

func main(){
c, err := mamgoiota.NewConnection("someNodeURL", "yourSeed")
if err != nil{
panic(err)
}
id, err := Send("the receiving address", 0, "your stringified message", c)
if err != nil{
panic(err)
}
fmt.Printf("Send to the Tangle. TransactionId: %v\n", id)
}
```
After sending, you find your transaction here https://thetangle.org giving the TransactionId

If you want to transfer value aswell (here 100 IOTA) call the send method like this: ```Send("the receiving address", 100, "your stringified message", c)```.

#### Read data from the IOTA tangle
Reading all transaction received by a certain adress:
```go
import "github.com/iotaledger/mamgoiota"

func main(){
c, err := NewConnection("someNodeURL", "")
if err != nil{
panic(err)
}

ts, err := ReadTransactions("Receiving Address", c)
if err != nil{
panic(err)
}
for i, tr := range ts {
t.Logf("%d. %v: %d IOTA, %v to %v\n", i+1, tr.Timestamp, tr.Value, tr.Message, tr.Recipient)
}
}
```
The seed can be ommitted here, since reading does not require an account



Reading a special transaction by transactionID:
```go
import "github.com/iotaledger/mamgoiota"

func main(){
c, err := NewConnection("someNodeURL", "")
if err != nil{
panic(err)
}

tx, err := ReadTransaction("Some transactionID", c)
if err != nil{
panic(err)
}
t.Logf("%v: %d IOTA, %v to %v\n", tx.Timestamp, tx.Value, tx.Message, tx.Recipient)
}
```


#### Examples
Check out our [example folder](/example) for a send and a receive example.

To run this, cd into the example folder and edit the `sender/send.go` and `receiver/receive.go` file, set the correct provider and address and you are ready to run.

Start the receiver first: `$ go run receiver/receive.go`. It will check for new messages every 5 seconds, until cancelled.

Then start the sender: `$ go run sender/send.go`.

You can also read all the past transactions, i.e. messages + value, at the address: `go run history/history.go`.

If you pick up the transaction hash from the Terminal output and paste it into the input field on the site https://thetangle.org you find your transaction.

If the Node is offline try another one, mentioned above.

### TODOs
- [ ] GoDoc
- [ ] Travis
- [ ] Make web-app
- [ ] Read sensor data, e.g. RuuVi tag
- [ ] More Read options
- [X] Read by TransactionId





42 changes: 42 additions & 0 deletions mamgoiota/connections/connection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package mamgoiota

import "github.com/iotaledger/giota"

//NewConnection establishes a connection with the given provider and the seed
func NewConnection(provider, seed string) (*Connection, error) {
return &Connection{
api: giota.NewAPI(provider, nil),
seed: seed,
security: 3,
mwm: 15,
}, nil
}

type Connection struct {
api *giota.API
seed string
security int
mwm int64
}

func (c *Connection) SendToApi(trs []giota.Transfer) (giota.Bundle, error) {
seed, err := giota.ToTrytes(c.seed)
if err != nil {
return nil, err
}
_, bestPow := giota.GetBestPoW()
return giota.Send(c.api, seed, c.security, trs, c.mwm, bestPow)
}

func (c *Connection) FindTransactions(req giota.FindTransactionsRequest) ([]giota.Transaction, error) {
found, err := c.api.FindTransactions(&req)
if err != nil {
return nil, err
}
return c.ReadTransactions(found.Hashes)
}

func (c *Connection) ReadTransactions(tIDs []giota.Trytes) ([]giota.Transaction, error) {
found, err := c.api.GetTrytes(tIDs)
return found.Trytes, err
}
57 changes: 57 additions & 0 deletions mamgoiota/connections/connection_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package mamgoiota

import (
"encoding/json"
"testing"
"time"

"github.com/stretchr/testify/assert"
)

func TestConnectionSend(t *testing.T) {
assert := assert.New(t)

c, err := NewConnection("http://node02.iotatoken.nl:14265", "SIERTBRUINSISBEZIGOMEENRONDJESAMENMETWIMAMENTTEMAKENOMZODESUBSIDIERONDTEKRIJGENH9")
assert.Nil(err)

var someJSON struct {
Id int
Message string
Timestamp time.Time
}

someJSON.Id = 12345
someJSON.Message = "Hello world this is a JSON"
someJSON.Timestamp = time.Now()

stringifiedJSON, err := json.Marshal(someJSON)
assert.Nil(err)

id, err := Send("RQP9IFNFGZGFKRVVKUPMYMPZMAICIGX9SVMBPNASEBWJZZAVDCMNOFLMRMFRSQVOQGUVGEETKYFCUPNDDWEKYHSALY", 0, string(stringifiedJSON), c)
assert.Nil(err)

t.Logf("TransactionId: %v\n", id)
}

func TestConnectionReadTransactions(t *testing.T) {
assert := assert.New(t)

c, err := NewConnection("http://node02.iotatoken.nl:14265", "")
assert.Nil(err)

ts, err := ReadTransactions("RQP9IFNFGZGFKRVVKUPMYMPZMAICIGX9SVMBPNASEBWJZZAVDCMNOFLMRMFRSQVOQGUVGEETKYFCUPNDDWEKYHSALY", c)
assert.Nil(err)
for i, tr := range ts {
t.Logf("%d. %v: %d IOTA, %v to %v\n", i+1, tr.Timestamp, tr.Value, tr.Message, tr.Recipient)
}
}
func TestConnectionReadSingleTransaction(t *testing.T) {
assert := assert.New(t)

c, err := NewConnection("http://node02.iotatoken.nl:14265", "")
assert.Nil(err)

tx, err := ReadTransaction("QFLSB9PFUYYCKUJ9JWIIHVQPZOOOQPDXMCGWAZCGLCBTODRJJQHZ9BIUEBGMNDFYOJMFGPQOUKBJ99999", c)
assert.Nil(err)
t.Logf("%v: %d IOTA, %v to %v\n", tx.Timestamp, tx.Value, tx.Message, tx.Recipient)
}
91 changes: 91 additions & 0 deletions mamgoiota/connections/receiver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package mamgoiota

import (
"fmt"
"sort"
"time"

"github.com/giota/mamgoiota/mamutils"

"github.com/iotaledger/giota"
)

type Transaction struct {
Message string
Value int64
Timestamp time.Time
Recipient string
}

type ApiTransactionsFinder interface {
FindTransactions(giota.FindTransactionsRequest) ([]giota.Transaction, error)
}

func ReadTransactions(address string, f ApiTransactionsFinder) ([]Transaction, error) {
iotaAdress, err := giota.ToAddress(address)
if err != nil {
return nil, err
}

req := giota.FindTransactionsRequest{
Addresses: []giota.Address{iotaAdress},
}

foundTx, err := f.FindTransactions(req)
if err != nil {
return nil, err
}

sort.Slice(foundTx, func(i, j int) bool {
return !(foundTx[i].Timestamp.Unix() < foundTx[j].Timestamp.Unix())
})

transactions := make([]Transaction, len(foundTx))
for i, t := range foundTx {
message, err := mamutils.FromMAMTrytes(t.SignatureMessageFragment)
if err != nil {
return nil, err
}
transactions[i] = Transaction{
Message: message,
Value: t.Value,
Timestamp: t.Timestamp,
Recipient: string(t.Address),
}
}

return transactions, nil
}

type ApiTransactionsReader interface {
ReadTransactions([]giota.Trytes) ([]giota.Transaction, error)
}

func ReadTransaction(transactionID string, r ApiTransactionsReader) (Transaction, error) {
tID, err := giota.ToTrytes(transactionID)
if err != nil {
return Transaction{}, err
}

txs, err := r.ReadTransactions([]giota.Trytes{tID})
if len(txs) != 1 {
return Transaction{}, fmt.Errorf("Requested 1 Transaction but got %d", len(txs))
}
if err != nil {
return Transaction{}, err
}

tx := txs[0]
message, err := mamutils.FromMAMTrytes(tx.SignatureMessageFragment)
if err != nil {
return Transaction{}, err
}
transaction := Transaction{
Message: message,
Value: tx.Value,
Timestamp: tx.Timestamp,
Recipient: string(tx.Address),
}

return transaction, nil
}
Loading