
Pozdravljeni vsi!
В delu, v katerem smo podrobno preučili, kako ustvariti dApp (decentralizirano aplikacijo) in delati z njo .
Pa dajmo zdaj malo testirat razstavljenega .
Faza 3. Testiranje računa dApp

Katere težave se vam takoj pojavijo pri Alice? dApp Račun?
Prvič:
Boob in Cooper lahko pomotoma pošljeta sredstva na naslov dApp z običajnim prenos transakcij in tako do njih ne bo mogel nazaj dostopati.Drugič:
Alice na noben način ne omejujemo dvigovanja sredstev brez odobritve Boob in/ali Cooper. Ker bodite pozorni na preverjanje, bodo vse transakcije Alice izvedene.
Popravimo 2. z prepovedjo Alice prenos transakcije. Razmestimo popravljeni skript:


Poskušamo dvigniti kovance iz dApp Alice in njenega podpisa. Dobimo napako:

Poskusimo dvigniti prek dviga:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))Scenarij deluje in izbrskali smo 2. točko!
Faza 4. Ustvarite DAO z glasovanjem
Na žalost jezik RIDE še ne omogoča dela z zbirkami (slovarski slovarji, iteratorji, reduktorji itd.). Vendar pa za vse operacije s ploščatimi zbirkami ključ-vrednost lahko oblikujemo sistem za delo z nizi, temu primerno s ključi in njihovo dešifriranje.
Nize je zelo enostavno povezati; nize je mogoče ločiti z indeksi.
Zberimo in razčlenimo niz kot testni primer in preverimo, kako to vpliva na izid transakcije.
Odločili smo se za dejstvo, da Alice ni mogla podpisati transakcije prenosa, ker je bila ta možnost blokirana v @verifier za to vrsto transakcije.
Vadimo z nizi in nato rešimo to.
RIDE Strune
Transakcija je spet možna, znamo delati z nizi.


Skupaj imamo vse potrebno za pisanje kompleksne logike DAO dApp.
Podatkovne transakcije
Podatkovne transakcije:
»Največja velikost ključa je 100 znakov in ključ lahko vsebuje poljubne kodne točke Unicode, vključno s presledki in drugimi nenatisljivimi simboli. Vrednosti nizov imajo omejitev 32,768 bajtov in največje možno število vnosov v podatkovni transakciji je 100. Na splošno je največja velikost podatkovne transakcije približno 140 kb – za referenco, skoraj natanko dolžina Shakespearove igre 'Romeo in Julija' '.
Ustvarimo DAO z naslednjimi pogoji:
Da bi startup dobil sredstva s klicem getFunds() potrebna je podpora vsaj 2 udeležencev - DAO vlagateljev. Umik možno bo natanko toliko, kot je skupno navedeno na glasovanje Lastniki DAO.
Naredimo 3 vrste ključev in dodamo logiko za delo s stanjem v 2 novih funkcijah vote in getFunds:
xx…xx_ia = vlagatelji, razpoložljivo stanje (glasovanje, polog, dvig)
xx…xx_sv = startupi, število glasov (glasovanje, getFunds)
xx…xx_sf = startupi, število glasov (glasovanje, getFunds)
xx…xx = javni naslov (35 znakov)
Upoštevajte, da smo morali pri Glasovanju posodobiti več polj hkrati:
WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),WriteSet nam omogoča, da naredimo več zapisov hkrati znotraj enega invokeScript transakcije.
Tako je videti v shrambi ključev vrednosti DAO dApp, potem ko sta Bob in Cooper dopolnila ia- depoziti:

Naša depozitna funkcija se je nekoliko spremenila:

Zdaj prihaja najpomembnejši trenutek v dejavnostih DAO – glasovati za projekte, ki se financirajo.
Bob glasuje za Neliin projekt 500000 valčkov:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))
V shrambi podatkov vidimo vse potrebne vnose za naslov Neli:

Za projekt Neli je glasoval tudi Cooper.

Oglejmo si kodo funkcije getFunds. Neli mora zbrati najmanj 2 glasova, da lahko dvigne sredstva iz DAO.

Neli bo dvignila polovico zaupanega zneska:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))
Uspe ji, to je, DAO deluje!
Ogledali smo si postopek ustvarjanja DAO v jeziku RIDE4DAPPS.
V naslednjih delih si bomo podrobneje ogledali preoblikovanje kode in testiranje primerov.
Polna različica kode v
# In this example multiple accounts can deposit their funds to DAO and safely take them back, no one can interfere with this.
# DAO participants can also vote for particular addresses and let them withdraw invested funds then quorum has reached.
# An inner state is maintained as mapping `address=>waves`.
# https://medium.com/waves-lab/waves-announces-funding-for-ride-for-dapps-developers-f724095fdbe1
# You can try this contract by following commands in the IDE (ide.wavesplatform.com)
# Run commands as listed below
# From account #0:
# deploy()
# From account #1: deposit funds
# broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"deposit",args:[]}, payment: [{amount: 100000000, asset:null }]}))
# From account #2: deposit funds
# broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"deposit",args:[]}, payment: [{amount: 100000000, asset:null }]}))
# From account #1: vote for startup
# broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))
# From account #2: vote for startup
# broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))
# From account #3: get invested funds
# broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))
{-# STDLIB_VERSION 3 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}
@Callable(i)
func deposit() = {
let pmt = extract(i.payment)
if (isDefined(pmt.assetId)) then throw("can hodl waves only at the moment")
else {
let currentKey = toBase58String(i.caller.bytes)
let xxxInvestorBalance = currentKey + "_" + "ib"
let currentAmount = match getInteger(this, xxxInvestorBalance) {
case a:Int => a
case _ => 0
}
let newAmount = currentAmount + pmt.amount
WriteSet([DataEntry(xxxInvestorBalance, newAmount)])
}
}
@Callable(i)
func withdraw(amount: Int) = {
let currentKey = toBase58String(i.caller.bytes)
let xxxInvestorBalance = currentKey + "_" + "ib"
let currentAmount = match getInteger(this, xxxInvestorBalance) {
case a:Int => a
case _ => 0
}
let newAmount = currentAmount - amount
if (amount < 0)
then throw("Can't withdraw negative amount")
else if (newAmount < 0)
then throw("Not enough balance")
else ScriptResult(
WriteSet([DataEntry(xxxInvestorBalance, newAmount)]),
TransferSet([ScriptTransfer(i.caller, amount, unit)])
)
}
@Callable(i)
func getFunds(amount: Int) = {
let quorum = 2
let currentKey = toBase58String(i.caller.bytes)
let xxxStartupFund = currentKey + "_" + "sf"
let xxxStartupVotes = currentKey + "_" + "sv"
let currentAmount = match getInteger(this, xxxStartupFund) {
case a:Int => a
case _ => 0
}
let totalVotes = match getInteger(this, xxxStartupVotes) {
case a:Int => a
case _ => 0
}
let newAmount = currentAmount - amount
if (amount < 0)
then throw("Can't withdraw negative amount")
else if (newAmount < 0)
then throw("Not enough balance")
else if (totalVotes < quorum)
then throw("Not enough votes. At least 2 votes required!")
else ScriptResult(
WriteSet([
DataEntry(xxxStartupFund, newAmount)
]),
TransferSet([ScriptTransfer(i.caller, amount, unit)])
)
}
@Callable(i)
func vote(amount: Int, address: String) = {
let currentKey = toBase58String(i.caller.bytes)
let xxxInvestorBalance = currentKey + "_" + "ib"
let xxxStartupFund = address + "_" + "sf"
let xxxStartupVotes = address + "_" + "sv"
let currentAmount = match getInteger(this, xxxInvestorBalance) {
case a:Int => a
case _ => 0
}
let currentVotes = match getInteger(this, xxxStartupVotes) {
case a:Int => a
case _ => 0
}
let currentFund = match getInteger(this, xxxStartupFund) {
case a:Int => a
case _ => 0
}
if (amount <= 0)
then throw("Can't withdraw negative amount")
else if (amount > currentAmount)
then throw("Not enough balance")
else ScriptResult(
WriteSet([
DataEntry(xxxInvestorBalance, currentAmount - amount),
DataEntry(xxxStartupVotes, currentVotes + 1),
DataEntry(xxxStartupFund, currentFund + amount)
]),
TransferSet([ScriptTransfer(i.caller, amount, unit)])
)
}
@Verifier(tx)
func verify() = {
match tx {
case t: TransferTransaction =>false
case _ => true
}
}
Vir: www.habr.com
