مرحبا بالجميع!
В
دعونا نختبر المفكك قليلاً الآن
المرحلة 3. اختبار حساب dApp
ما هي المشاكل التي تقفز إليك على الفور مع أليس؟ DAPP الحساب؟
أولا:
قد يرسل Boob and Cooper أموالاً عن طريق الخطأ إلى عنوان dApp باستخدام النظام العادي تحويل المعاملات وبالتالي لن تكون قادرة على الوصول إليها مرة أخرى.ثانيا:
نحن لا نمنع أليس بأي شكل من الأشكال من سحب الأموال دون موافقة بوب و/أو كوبر. نظرًا لأنه يجب الانتباه للتحقق، فسيتم تنفيذ جميع المعاملات من Alice.
دعونا نصلح المركز الثاني بحظر أليس تحويل المعاملات. دعونا ننشر البرنامج النصي المصحح:

نحن نحاول سحب العملات المعدنية من dApp Alice وتوقيعها. نحصل على خطأ:
دعونا نحاول الانسحاب عبر السحب:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"withdraw",args:[{type:"integer", value: 1000000}]}, payment: []}))
السيناريو يعمل ولقد اكتشفنا النقطة الثانية!
المرحلة 4. إنشاء DAO مع التصويت
لسوء الحظ، لا توفر لغة RIDE حتى الآن القدرة على العمل مع المجموعات (قواميس القواميس، التكرارات، المخفضات، إلخ). ومع ذلك، بالنسبة لأي عمليات ذات مجموعات مسطحة الرئيسية ذات القيمة يمكننا تصميم نظام للعمل مع السلاسل، وفقًا للمفاتيح وفك تشفيرها.
من السهل جدًا ربط السلاسل، حيث يمكن فصل السلاسل باستخدام الفهارس.
دعونا نجمع سلسلة ونحللها كمثال اختباري ونتحقق من مدى تأثير ذلك على نتيجة المعاملة.
لقد توصلنا إلى حقيقة أن Alice لم تتمكن من التوقيع على معاملة النقل، حيث تم حظر هذه القدرة في @verifier لهذا النوع من المعاملات.
دعونا نتدرب على السلاسل ثم نحل هذه المشكلة.
سلاسل ركوب
الصفقة ممكنة مرة أخرى، ونحن نعرف كيفية العمل مع السلاسل.

في المجمل، لدينا كل ما هو ضروري لكتابة منطق معقد تطبيق داو اللامركزي.
معاملات البيانات
معاملات البيانات:
"الحد الأقصى لحجم المفتاح هو 100 حرف، ويمكن أن يحتوي المفتاح على نقاط ترميز Unicode عشوائية بما في ذلك المسافات والرموز الأخرى غير القابلة للطباعة. يبلغ الحد الأقصى لقيم السلسلة 32,768 بايت والحد الأقصى لعدد الإدخالات الممكنة في معاملة البيانات هو 100. بشكل عام، يبلغ الحد الأقصى لحجم معاملة البيانات حوالي 140 كيلو بايت — للإشارة، تقريبًا نفس طول مسرحية شكسبير "روميو وجولييت" "."
نقوم بإنشاء DAO بالشروط التالية:
لكي تحصل الشركة الناشئة على التمويل عن طريق الاتصال الحصول على الأموال () مطلوب دعم ما لا يقل عن 2 من المشاركين - مستثمري DAO. سحب سيكون من الممكن بالضبط بقدر المجموع المشار إليه التصويت أصحاب DAO.
لنقم بإنشاء 3 أنواع من المفاتيح وإضافة منطق للعمل مع الأرصدة في وظيفتين جديدتين: التصويت وgetFunds:
xx… xx_I ل = المستثمرين، الرصيد المتاح (التصويت، الإيداع، الانسحاب)
xx… xx_sv = الشركات الناشئة، عدد الأصوات (التصويت، getFunds)
xx… xx_sf = الشركات الناشئة، عدد الأصوات (التصويت، getFunds)
xx…xx = عنوان عام (35 حرفًا)
يرجى ملاحظة أننا في التصويت كنا بحاجة إلى تحديث عدة حقول مرة واحدة:
WriteSet([DataEntry(key1, value1), DataEntry(key2, value2)]),
يتيح لنا WriteSet إنشاء عدة سجلات مرة واحدة في سجل واحد استدعاء المعاملات.
هذا هو ما يبدو عليه تخزين القيمة الأساسية لـ DAO dApp، بعد تجديد Bob وCooper ia-الودائع:
لقد تغيرت وظيفة الإيداع لدينا قليلاً:
الآن تأتي اللحظة الأكثر أهمية في أنشطة DAO - تصويت للمشاريع التي سيتم تمويلها.
يصوت بوب لصالح مشروع نيلي الذي يتضمن 500000 مويجة:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"vote",args:[{type:"integer", value: 500000}, {type:"string", value: "3MrXEKJr9nDLNyVZ1d12Mq4jjeUYwxNjMsH"}]}, payment: []}))
في مخزن البيانات نرى كافة الإدخالات الضرورية لعنوان نيلي:
صوت كوبر أيضًا لصالح مشروع نيلي.
دعونا نلقي نظرة على رمز الوظيفة getFunds. يجب على Neli جمع صوتين على الأقل حتى تتمكن من سحب الأموال من DAO.
ستقوم نيلي بسحب نصف المبلغ الموكل إليها:
broadcast(invokeScript({dappAddress: address(env.accounts[1]), call:{function:"getFunds",args:[{type:"integer", value: 500000}]}, payment: []}))
لقد نجحت، أي أن DAO يعمل!
لقد نظرنا في عملية إنشاء DAO باللغة RIDE4DAPPS.
في الأجزاء التالية، سنلقي نظرة فاحصة على إعادة هيكلة التعليمات البرمجية واختبار الحالة.
النسخة الكاملة من الكود في
# 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
}
}
المصدر: www.habr.com