موضوع بلاک چین نه تنها منبعی برای انواع تبلیغات، بلکه ایده هایی است که از نقطه نظر فناوری بسیار ارزشمند هستند. بنابراین، از ساکنان شهر آفتابی عبور نکرد. مردم به دقت نگاه می کنند، مطالعه می کنند، سعی می کنند تخصص خود را در زمینه امنیت اطلاعات سنتی به سیستم های بلاک چین منتقل کنند. تا اینجای کار، یکی از توسعههای Rostelecom-Solar میتواند امنیت نرمافزار مبتنی بر بلاک چین را بررسی کند. و در طول مسیر، برخی از افکار در مورد حل مشکلات کاربردی جامعه بلاک چین مطرح می شود. یکی از این هکهای زندگی - نحوه تعیین آدرس قرارداد هوشمند قبل از استقرار با استفاده از CREATE2 - امروز میخواهم با شما به اشتراک بگذارم.
اپکد CREATE2 در 28 فوریه سال جاری در هارد فورک قسطنطنیه اضافه شد. همانطور که در EIP بیان شده است، این اپکد در درجه اول برای کانال های دولتی معرفی شده است. با این حال، ما از آن برای حل یک مشکل متفاوت استفاده کردیم.
کاربرانی با موجودی در صرافی وجود دارند. ما باید به هر کاربر یک آدرس اتریوم ارائه دهیم که هر کسی بتواند به آن توکن بفرستد و از این طریق حساب خود را دوباره پر کند. بیایید این آدرس ها را «کیف پول» بنامیم. هنگامی که توکن ها وارد کیف پول می شوند، باید آنها را به یک کیف پول (هات کیف) ارسال کنیم.
در بخشهای بعدی، گزینههایی را برای حل این مشکل بدون CREATE2 تحلیل میکنم و به شما میگویم که چرا آنها را رها کردیم. اگر فقط به نتیجه نهایی علاقه دارید، می توانید آن را در بخش "راه حل نهایی" پیدا کنید.
آدرس های اتریوم
ساده ترین راه حل، ایجاد آدرس های جدید اتریوم برای کاربران جدید است. این آدرس ها کیف پول خواهند بود. برای انتقال توکن ها از کیف پول به کیف پول داغ، باید تراکنش را با فراخوانی تابع امضا کنید منتقل کردن() با کلید خصوصی کیف پول از باطن.
این رویکرد دارای مزایای زیر است:
- ساده است
- هزینه انتقال توکن ها از کیف پول به کیف پول داغ برابر با هزینه فراخوانی تابع است منتقل کردن()
با این حال، ما تصمیم به مخالفت با این روش گرفتیم، زیرا یک اشکال عمده دارد: شما باید کلیدهای خصوصی را در جایی ذخیره کنید. نه تنها ممکن است آنها گم شوند، بلکه باید دسترسی به این کلیدها را نیز به دقت مدیریت کنید. اگر حداقل یکی از آنها به خطر بیفتد، توکن های یک کاربر خاص به کیف پول داغ نمی رسد.
برای هر کاربر یک قرارداد هوشمند جداگانه ایجاد کنید
استقرار یک قرارداد هوشمند جداگانه برای هر کاربر به شما این امکان را می دهد که از ذخیره کلیدهای خصوصی کیف پول در سرور خودداری کنید. صرافی این قرارداد هوشمند را برای انتقال توکن ها به کیف پول داغ فراخوانی می کند.
ما همچنین این راه حل را رها کردیم، زیرا نمی توان آدرس کیف پول خود را بدون استقرار یک قرارداد هوشمند به کاربر نشان داد (این در واقع امکان پذیر است، اما به روشی نسبتاً پیچیده با سایر معایب که در اینجا به آنها اشاره نمی کنیم). در صرافی، کاربر می تواند به تعداد مورد نیاز حساب ایجاد کند و هر کدام به کیف پول خود نیاز دارند. این بدان معنی است که ما باید برای استقرار یک قرارداد پول خرج کنیم بدون اینکه حتی مطمئن باشیم کاربر از این حساب استفاده خواهد کرد.
Opcode CREATE2
برای رفع مشکل روش قبلی تصمیم گرفتیم از اپکد CREATE2 استفاده کنیم. CREATE2 به شما امکان می دهد تا آدرسی را که قرارداد هوشمند در آن مستقر می شود، از قبل تعیین کنید. آدرس با استفاده از فرمول زیر محاسبه می شود:
keccak256 (0xff ++ address ++ salt ++ keccak256 (init_code)) [12:]
، جایی که:
- نشانی - آدرس قرارداد هوشمند که با CREATE2 تماس می گیرد
- نمک - مقدار تصادفی
- init_code - بایت کد قرارداد هوشمند برای استقرار
این تضمین می کند که آدرسی که به کاربر ارائه می دهیم در واقع حاوی بایت کد مورد نظر است. علاوه بر این، این قرارداد هوشمند می تواند هر زمان که ما نیاز داشته باشیم مستقر می شود. به عنوان مثال، زمانی که کاربر تصمیم می گیرد برای اولین بار از کیف پول خود استفاده کند.
علاوه بر این، می توانید آدرس قرارداد هوشمند را هر بار به جای ذخیره آن محاسبه کنید زیرا:
- نشانی در فرمول ثابت است، زیرا این آدرس کارخانه کیف پول ما است
- نمک - hash user_id
- init_code ثابت است زیرا ما از یک کیف پول استفاده می کنیم
پیشرفت های بیشتر
راه حل قبلی هنوز یک اشکال دارد: برای استقرار قرارداد هوشمند باید هزینه پرداخت کنید. با این حال، می توانید از شر آن خلاص شوید. برای این کار می توانید تابع را فراخوانی کنید منتقل کردن()و بعد خود تخریبی() در سازنده کیف پول و سپس گاز برای استقرار قرارداد هوشمند برگردانده می شود.
برخلاف تصور رایج، میتوانید یک قرارداد هوشمند را چندین بار با کد عملیاتی CREATE2 در یک آدرس مستقر کنید. این به این دلیل است که CREATE2 بررسی می کند که هیچ آدرس هدف صفر باشد (مقدار "1" در ابتدای سازنده به آن اختصاص داده شده است). در این مورد، تابع خود تخریبی() هر بار آدرس های غیر عادی را بازنشانی می کند. بنابراین اگر دوباره CREATE2 را با همان آرگومان ها فراخوانی کنید، چک nonce پاس می شود.
لطفا توجه داشته باشید که این راه حل مشابه گزینه آدرس اتریوم است، اما بدون نیاز به ذخیره کلیدهای خصوصی. هزینه انتقال پول از کیف به کیف پول تقریباً برابر با هزینه فراخوانی یک تابع است منتقل کردن()، از آنجایی که ما برای استقرار قرارداد هوشمند هزینه ای نمی پردازیم.
تصمیم نهایی
تهیه شده توسط:
- عملکرد دریافت نمک توسط USER_ID
- یک قرارداد هوشمند که کد عملیاتی CREATE2 را با نمک مناسب فراخوانی می کند (یعنی کارخانه کیف پول)
- بایت کد کیف پول مربوط به قرارداد با سازنده زیر:
constructor () {
address hotWallet = 0x…;
address token = 0x…;
token.transfer (hotWallet, token.balanceOf (address (this)));
selfdestruct (address (0));
}
برای هر کاربر جدید، آدرس کیف پول او را با محاسبه نشان می دهیم
keccak256 (0xff ++ address ++ salt ++ keccak256 (init_code)) [12:]
هنگامی که یک کاربر توکن ها را به آدرس کیف پول مربوطه منتقل می کند، باطن ما یک رویداد انتقال با پارامتر را می بیند. _به، برابر با آدرس کیف پول است. در این مرحله، امکان افزایش موجودی کاربر در صرافی قبل از استقرار کیف پول وجود دارد.
وقتی یک آدرس کیف پول تعداد کافی توکن را جمع آوری می کند، می توانیم همه آنها را یکباره به کیف پول داغ منتقل کنیم. برای انجام این کار، backend تابع کارخانه قرارداد هوشمند را فراخوانی می کند که اقدامات زیر را انجام می دهد:
function deployWallet (соль uint256) {
bytes memory walletBytecode =…;
// invoke CREATE2 with wallet bytecode and salt
}
بنابراین، سازنده قرارداد هوشمند کیف پول نامیده می شود که تمام توکن های خود را به آدرس کیف پول انتقال می دهد و سپس خود تخریب می شود.
کد کامل را می توان یافت
نویسنده پاول کوندراتنکوف، متخصص اتریوم
منبع: www.habr.com