Skip to content

Commit

Permalink
Merge branch 'develop' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
dessaya committed Oct 2, 2020
2 parents 7347484 + 2dd69a7 commit d1173fb
Show file tree
Hide file tree
Showing 48 changed files with 523 additions and 379 deletions.
18 changes: 12 additions & 6 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Done
- [x] wasp node dashboard: show structure of committee, which SCs are running, etc

Pending
- [ ] wwallet: Allow more than one instance of same SC
- [ ] wwallet: separate binaries for admin/client operations
- [ ] dwf: allow withdrawing colored tokens
- [ ] BufferedKVStore: Cache DB reads (which should not change in the DB during
the BufferedKVStore lifetime)
Expand All @@ -29,11 +29,17 @@ Pending
- [ ] Add authentication to web api calls

To discuss/RFC
- [ ] optimize SC ledger database. Currently key/value is stored twice: in the virtual state and in the batch which
last updated the value. For small virtual states it is OK. For big ones (data Oracle) it would be better
to for virtual state keep reference to the last updating mutatation in the batch/state update
- [ ] identity system for nodes
- [ ] secure access to API, to SC admin functions
- [ ] refactor 'request code' from uint16 value to string
- [ ] smart contract state access from outside. The current approach is to provide universal node API to query state.
The alternatives would be to expose access functions (like view in Solidity) from the smart contract code itself.
Another approach can be expose data schema + generic access
- [ ] Merkle proofs of smart contract state elements
- [ ] Merkle proofs of smart contract state elements The idea is to have relatively short (logoarithmically) proof
of some data element is in the virtual state. Currently proof is the whole batch chain, i.e. linear.
- [ ] Standard subscription mechanisms for events: (a) VM events (NanoMsg, ZMQ, MQTT)
and (b) smart contract events (signalled by request to subscriber smart contract)
- [ ] balance sheet metaphor in the smart contract state. Ownership concept of BS "liability+equity" items
Expand All @@ -44,14 +50,14 @@ for each committee member with its public key. Option 2: move request data off-t
Functional testing
- [ ] test fault-tolerance
- [ ] test access node function
- [ ] test several concurrent/interacting contracts
- [ ] test random confirmation delays (probably not needed if running on Pollen)
- [X] test several concurrent/interacting contracts
- [X] test random confirmation delays (probably not needed if running on Pollen)
- [ ] test big committees (~100 nodes)
- [ ] test overlapping committees
- [X] test overlapping committees

Future
- [ ] rewrite DKG
- [ ] `Oracle Data Bulletin Board` description. Postponed
- [ ] `Oracle Data Bulletin Board` specs. Postponed
- [ ] enable and test 1 node committees
- [ ] test quorum == 1
- [ ] optimize logging
Expand Down
8 changes: 4 additions & 4 deletions articles/intro/dwf.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ In the future all smart contract programs will be run on wasm VM)_

The common practice is to display the donation address on a web page for anyone wanting to send us a donation,
for example with their Trinity wallet.
What if we also want each donor to attach some feedback text to the donation? For example,
What if we also want each donor to attach some feedback/comment text to the donation? For example,
“Here I send you 2 MIOTA because I like your site”?
To support that possibility, we would need some kind of application or an extension of the existing IOTA wallet
with a database for feedback messages behind and so on (of course, there is more than one way to do that, including
To support that possibility, we would need some kind of application, or an extension of the existing IOTA wallet
with a database for comment messages behind and so on (of course, there is more than one way to do that, including
embedding the text right into the transaction).

_DonateWithFeedback_ smart contract takes responsibility to handle both the donation
Expand Down Expand Up @@ -53,7 +53,7 @@ The state of any smart contract consists of two parts:
- The collection of _key-value pairs_ which can be interpreted as variables and their values.
It is an **off-tangle** part of the state. In general, it can contain any data of arbitrary size.
In the _DonateWithFeedback_ smart contract the dashboard displays the generic data of the state in
a SC-specific and user-friendly format:
an SC-specific and user-friendly format:
the statistics of donations and list of feedback messages stored in the log.

(note that we use [Base58 encoding](https://en.bitcoinwiki.org/wiki/Base58) for binary data of fixed size, like
Expand Down
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/iotaledger/wasp/plugins/dashboard"
"github.com/iotaledger/wasp/plugins/database"
"github.com/iotaledger/wasp/plugins/dispatcher"
"github.com/iotaledger/wasp/plugins/examples"
"github.com/iotaledger/wasp/plugins/gracefulshutdown"
"github.com/iotaledger/wasp/plugins/logger"
"github.com/iotaledger/wasp/plugins/nodeconn"
Expand Down Expand Up @@ -41,6 +42,7 @@ func main() {
runvm.Init(),
publisher.Init(),
dashboard.Init(),
examples.Init(),
)

testPlugins := node.Plugins(
Expand Down
4 changes: 2 additions & 2 deletions packages/apilib/deploysc.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,8 @@ func CreateSC(par CreateSCParams) (*address.Address, *balance.Color, error) {
fmt.Fprintf(textout, "checking program metadata: FAILED: %v\n", err)
return nil, nil, err
}
fmt.Fprintf(textout, "checking program metadata: OK. location: '%s', VMType: '%s', description: '%s'\n",
md.Location, md.VMType, md.Description)
fmt.Fprintf(textout, "checking program metadata: OK. VMType: '%s', description: '%s'\n",
md.VMType, md.Description)

// generate distributed key set on committee nodes
scAddr, err := GenerateNewDistributedKeySet(par.CommitteeApiHosts, par.N, par.T)
Expand Down
82 changes: 36 additions & 46 deletions packages/apilib/progmdata.go → packages/apilib/program.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,58 +5,57 @@ import (
"encoding/json"
"errors"
"fmt"
"net/http"
"time"

"github.com/iotaledger/wasp/packages/hashing"
"github.com/iotaledger/wasp/packages/progmeta"
"github.com/iotaledger/wasp/packages/registry"
"github.com/iotaledger/wasp/packages/util/multicall"
"github.com/iotaledger/wasp/plugins/webapi/admapi"
"github.com/iotaledger/wasp/plugins/webapi/misc"
"net/http"
"time"
)

// PutProgramMetadata calls node to write ProgramMetadata record
func PutProgramMetadata(host string, md registry.ProgramMetadata) error {
data, err := json.Marshal(&admapi.ProgramMetadataJsonable{
ProgramHash: md.ProgramHash.String(),
Location: md.Location,
Description: md.Description,
// PutProgramMetadata calls node to write program code and ProgramMetadata record
func PutProgram(host string, vmType string, description string, code []byte) (*hashing.HashValue, error) {
data, err := json.Marshal(&admapi.PutProgramRequest{
ProgramMetadata: admapi.ProgramMetadata{
VMType: vmType,
Description: description,
},
Code: code,
})
if err != nil {
return err
return nil, err
}
url := fmt.Sprintf("http://%s/adm/putprogrammetadata", host)
url := fmt.Sprintf("http://%s/adm/program", host)
resp, err := http.Post(url, "application/json", bytes.NewBuffer(data))
if err != nil {
return err
return nil, err
}

var result misc.SimpleResponse
var result admapi.PutProgramResponse
err = json.NewDecoder(resp.Body).Decode(&result)
if err != nil {
return err
return nil, err
}
if result.Error != "" {
err = errors.New(result.Error)
return nil, errors.New(result.Error)
}
return err
}

// GetProgramMetadata calls node to get ProgramMetadata by program hash
func GetProgramMetadata(host string, progHash *hashing.HashValue) (*progmeta.ProgramMetadata, error) {
data, err := json.Marshal(&admapi.GetProgramMetadataRequest{
ProgramHash: progHash.String(),
})
hash, err := hashing.HashValueFromBase58(result.ProgramHash)
if err != nil {
return nil, err
}
url := fmt.Sprintf("http://%s/adm/getprogrammetadata", host)
resp, err := http.Post(url, "application/json", bytes.NewBuffer(data))
return &hash, nil
}

// GetProgramMetadata calls node to get ProgramMetadata by program hash
func GetProgramMetadata(host string, progHash *hashing.HashValue) (*registry.ProgramMetadata, error) {
url := fmt.Sprintf("http://%s/adm/program/%s", host, progHash.String())
resp, err := http.Get(url)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("response status %d", resp.StatusCode)
if resp.StatusCode == http.StatusNotFound {
return nil, nil
}
var dresp admapi.GetProgramMetadataResponse
err = json.NewDecoder(resp.Body).Decode(&dresp)
Expand All @@ -66,27 +65,21 @@ func GetProgramMetadata(host string, progHash *hashing.HashValue) (*progmeta.Pro
if dresp.Error != "" {
return nil, errors.New(dresp.Error)
}
if !dresp.ExistsMetadata {
return nil, nil
}
ph, err := hashing.HashValueFromBase58(dresp.ProgramHash)
if err != nil {
return nil, err
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("response status %d", resp.StatusCode)
}
return &progmeta.ProgramMetadata{
ProgramHash: ph,
Location: dresp.Location,
VMType: dresp.VMType,
Description: dresp.Description,
CodeAvailable: dresp.ExistsCode,
return &registry.ProgramMetadata{
ProgramHash: *progHash,
VMType: dresp.VMType,
Description: dresp.Description,
}, nil
}

// CheckProgramMetadata checks if metadata exists in hosts and is consistent
// return program meta data from the first host if all consistent, otherwise nil
func CheckProgramMetadata(hosts []string, progHash *hashing.HashValue) (*progmeta.ProgramMetadata, error) {
func CheckProgramMetadata(hosts []string, progHash *hashing.HashValue) (*registry.ProgramMetadata, error) {
funs := make([]func() error, len(hosts))
mdata := make([]*progmeta.ProgramMetadata, len(hosts))
mdata := make([]*registry.ProgramMetadata, len(hosts))
for i, host := range hosts {
var err error
h := host
Expand All @@ -110,7 +103,7 @@ func CheckProgramMetadata(hosts []string, progHash *hashing.HashValue) (*progmet
}

// consistentProgramMetadata does not check if code exists
func consistentProgramMetadata(md1, md2 *progmeta.ProgramMetadata) bool {
func consistentProgramMetadata(md1, md2 *registry.ProgramMetadata) bool {
if md1 == nil || md2 == nil {
return false
}
Expand All @@ -123,8 +116,5 @@ func consistentProgramMetadata(md1, md2 *progmeta.ProgramMetadata) bool {
if md1.Description != md2.Description {
return false
}
if md1.Location != md2.Location {
return false
}
return true
}
2 changes: 1 addition & 1 deletion packages/committee/consensus/eventproc.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func (op *operator) EventStateTransitionMsg(msg *committee.StateTransitionMsg) {
progHashStr := progHash.String()
op.processorReady = processor.CheckProcessor(progHashStr)
if !op.processorReady {
processor.LoadProcessorAsync(progHashStr, func(err error) {
processor.LoadProcessorAsync(progHash, func(err error) {
if err == nil {
op.committee.ReceiveMessage(committee.ProcessorIsReady{
ProgramHash: progHashStr,
Expand Down
9 changes: 9 additions & 0 deletions packages/dashboard/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ import (
"time"
)

const maxLength = 150

func Trim(s string) string {
if len(s) > maxLength {
return s[0:maxLength] + "..."
}
return s
}

func FormatTimestamp(ts interface{}) string {
t, ok := ts.(time.Time)
if !ok {
Expand Down
51 changes: 0 additions & 51 deletions packages/progmeta/medatada.go

This file was deleted.

39 changes: 39 additions & 0 deletions packages/registry/programcode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package registry

import (
"fmt"

"github.com/iotaledger/wasp/packages/hashing"
"github.com/iotaledger/wasp/plugins/database"
"github.com/iotaledger/wasp/plugins/publisher"
)

func dbkeyProgramCode(progHash *hashing.HashValue) []byte {
return database.MakeKey(database.ObjectTypeProgramCode, progHash[:])
}

// TODO save program code in the smart contract state
func GetProgramCode(progHash *hashing.HashValue) ([]byte, error) {
db := database.GetRegistryPartition()
data, err := db.Get(dbkeyProgramCode(progHash))
if err != nil {
return nil, err
}
hash := hashing.HashData(data)
if *hash != *progHash {
return nil, fmt.Errorf("program code is corrupted. Expected: %s. Got: %s", progHash.String(), hash.String())
}
return data, nil
}

func SaveProgramCode(programCode []byte) (ret hashing.HashValue, err error) {
progHash := hashing.HashData(programCode)
db := database.GetRegistryPartition()
if err = db.Set(dbkeyProgramCode(progHash), programCode); err != nil {
return
}
ret = *progHash

defer publisher.Publish("programcode", progHash.String())
return
}
Loading

0 comments on commit d1173fb

Please sign in to comment.