
بیت کوین هیچ نقص مشخص و قابل مشاهدهای ندارد و مجهز به چندین قفل زمانی (time lock) مختلف است. قفل زمانی به شما امکان میدهد تا شرایط مبتنی بر زمان را مشخص کنید که تراکنشها تحت این شرایط معتبر باشند. با استفاده از قفل زمانی میتوانید اکنون تراکنش ایجاد کنید و هفته بعد پرداخت تراکنش را انجام دهید، مدت انتظار اجباری برای کوین تعیین کنید، قراردادهای هوشمند پیچیده ایجاد کنید که در چندین تراکنش در جریان هستند و یا تصادفا کوینهای خود را برای قرنها مسدود کنید.
اکثر قفلهای زمانی ، اخیرا به بیت کوین اضافه شده و وارد ساختار تراکنشها شدهاند. پروپوزالهای بهبود و ارتقای بیت کوین (BIPها) بسیار شگفتانگیز و پرجزییات هستند؛ اما دانش پیشزمینه بسیار زیادی نیاز دارند. در این مقاله به جمعآوری اطلاعات مربوط به انواع قفل زمانی و توضیح دقیق آنها پرداختهایم.
طبقهبندی انواع قفل زمانی
قبل از آنکه به توضیح قفلهای زمانی بپردازیم، نحوه عملکرد آنها را بیان میکنیم. قفلهای زمانی ۳ ویژگی مهم دارند که عبارتند از:
- مکان (location)
- هدفگذاری (targeting)
- معیار (metric)
مکان: تراکنش در مقابل اسکریپت
انواع قفل زمانی را میتوان در خود تراکنش و یا ورودیهای پرداخت به هش اسکریپت (P2SH) به دست آورد. هر تراکنش دارای چندین حوزه قفل زمانی است. از طرف دیگر، اسکریپتها میتوانند بدون قفل زمانی باشند یا قفلهای زمانی بسیار زیادی داشته باشند. از لحاظ کارایی، قفلهای زمانی در سطح تراکنش و در سطح اسکریپت تقریبا یکسان هستند، اما عملکرد بسیار متفاوتی دارند.
قفل زمانی در سطح تراکنش باعث میشود علیرغم معتبر بودن امضاها و اسکریپتها، تراکنش تا زمان مورد نظر نامعتبر باشد. قفلهای زمانی در سطح اسکریپت باعث خواهند شد تا ارزیابی اسکریپت صورت نگیرد، مگر در صورتی که تراکنش نیز مسدود شده باشد. عدم ارزیابی اسکریپت باعث میشود که تراکنش نامعتبر شود. به طور خلاصه، قفل زمان سطح تراکنش تعیین میکند چه زمانی تراکنش تایید شود، در حالی که قفلهای سطح اسکریپت تعیین میکنند که آیا امضای اسکریپت معتبر است یا خیر.
تفاوت عمومی بین این دو دقیقا در همان چیزی است که مسدود میکنند؛ قفل زمانی سطح تراکنش حاوی فقط یک تراکنش مشخص است. قفلهای سطح تراکنش را همانند یک چک با تاریخ آینده در نظر بگیرید.
ممکن است برای شما یک چک نوشته باشیم که بعداً معتبر و قابل نقد کردن باشد؛ اما روز تاریخ مورد نظر فقط برای آن چک اعمال میشود و میتوان چک را به روشهای دیگری نقد کرد که ندانیم. قفلهای سطح اسکریپت شرایطی را برای تمام تراکنشهایی ایجاد میکند که خروجی را خرج میکنند.
به عبارت دیگر، قفلهای سطح تراکنش، کارهایی که میتوانید پس از ایجاد شدن تراکنش بر روی آن انجام دهید را تحت تاثیر قرار میدهند؛ اما قفلهای سطح اسکریپت تعیین میکنند که چه تراکنشهایی میتوانند ایجاد شوند.
قفل زمانی تراکنش آن چنان که فکر میکنید مفید و کاربردی نیست. این قفلها، کوینها را کنترل نمیکنند، بلکه فقط خرج کردنها را اداره میکنند. برای همین است که کارهای جالبی که میتوان انجام داد به OP_CLTV و OP_CSV نیاز دارند. با استفاده از قفلهای سطح اسکریپت و منطق شرطی (OP_IF) میتوانیم اسکریپتهای پیچیدهای ایجاد کنیم که برای مثال میتوانند خرج کردنهای چندامضایی یا خرج کردنهای تک امضایی پس از گذشت زمان مشخص را امکانپذیر سازند. این موضوع، کاربردهای بسیار زیادی را برای تراکنشهای P2SH فراهم میکند.
قفلهای زمانی سطح اسکریپت به حضور قفل زمانی سطح تراکنش نیاز دارند. قفلهای سطح اسکریپت برای اجرا شدن به قفلهای سطح تراکنش متکی هستند. قفلهای سطح اسکریپت به جای بررسی زمان موجود در اسکریپت، قفل زمانی تراکنش را بررسی میکنند. این موضوع، نکتهای بسیار ظریف و مقرون به صرفه و در عین حال اندکی غیرملموس است. اسکریپت بررسی میکند که تراکنش حداقل در مسیر اسکریپت قرار داشته باشد و قفل زمانی تراکنش را به عنوان تضمینی در نظر میگیرد که زمان مورد نظر گذشته است.
هدفگذاری: مطلق در برابر نسبی
هنگامی که قفل زمانی بر روی کوینها اعمال میکنیم، در واقع زمان عرضه آنها را هدفگذاری میکنیم. قفلهای مطلق این هدف را از لحاظ زمان تعیین شده تعریف میکنند. این قفلها، زمان دقیق را برای منقضی شدن قفل انتخاب میکنند. قفلهای زمانی نسبی این هدف را به عنوان زمان سپری شده از تایید خروجی قبلی تعریف میکنند. تفاوت این دو همانند این است که بگوییم “در ساعت ۱۵ شما را ملاقات خواهم کرد” و “۴ ساعت بعد شما را ملاقات خواهم کرد.”
تراکنشهایی که در یک زمان مطلق مسدود شدهاند، تا هنگامی که به زمان مورد نظر نرسیم نامعتبر خواهند بود. این موضوع بدان معنا است که میتوان تراکنشی برای چند سال بعد ایجاد کرد، آن را امضا کرد، به اشتراک گذاشت و حتی با تضمین آن که تا زمان منقضی شدن قفل تایید نخواهد شد، آن را به طور عمومی منتشر کرد. میتوان از قفل زمانی مطلق برای ارسال پول به فرزندان یا ایجاد حساب پسانداز استفاده کرد که میتوان به آن واریز انجام داد، اما نمیتوان تا زمان مورد نظر سرمایه آن را برداشت کرد.
از طرف دیگر، قفل زمانی نسبی تا زمانی که مدت زمان مشخصی سپری نشود، از تایید تراکنشها جلوگیری میکند. این مورد یک ویژگی قدرتمند و دقیق است. نکته جالب در خصوص قفل زمانی نسبی، ایجاد قفلهای نسبی برای تراکنشهای انتشار نیافته یا تاییدنشده است. پس از تایید شدن تراکنش، همواره میتوانیم قفل زمانی مطلق در آینده ایجاد کنیم؛ اما برای انجام این کار، باید منتظر تایید شدن تراکنش و دریافت زمان تایید آن باشیم.
قفل زمانی نسبی را میتوان برای تراکنشهای تاییدنشده ایجاد کرد. این موضوع بدان معنا است که میتوانید پیشاپیش یک قرارداد هوشمند چندمرحلهای ایجاد و امضا کنید و مطمئن باشید که تراکنش مورد نظر بر اساس خواسته شما تایید خواهد شد.
معیار: بلاکها در برابر ثانیهها
در شبکه بیت کوین، زمان یک فرضیه بر اساس اجماع است و زمان عرضه هرگز سر نمیرسد. تراکنشها نمیتوانند به ساعت خود نگاه کنند؛ بنابراین ما باید تعیین کنیم که “زمان” چیست.
بیت کوین دو روش برای سنجش زمان دارد: شماره بلاک و برچسب زمانی بلاک. این روشها برای هر قفل زمانی پیادهسازی میشوند. میتوانید شماره بلاک یا ثانیه مشخصی را برای قفل زمانی تعیین کنید. هر دوی این روشها پیچیدگیهای خود را دارند و هر دوی این معیارها برای کاربردهای واقعی به حد کافی دقیق هستند. اما شناخت تفاوتهای آنها مهم است.
ما اغلب میگوییم که بلاکها از توزیع پویسون (Poisson Distribution) پیروی میکنند. انتظار میرود که بلاکها هر ۱۰ دقیقه یکبار ایجاد شوند. اما این موضوع کاملا درست نیست؛ هنگامی که توان هش افزایش مییابد، بلاکها زودتر ایجاد میشوند و هنگامی که توان هش کاهش مییابد، سرعت تولید بلاکها نیز کمتر میشود. سختی شبکه در هر ۲۰۱۶ بلاک تنظیم میشود تا زمان ۱۰ دقیقه مورد نظر حاصل شود؛ اما به دلیل شرایط شبکه یا احتمالات تصادفی، ممکن است این زمان تغییر کند.
برچسبهای زمانی بسیار دقیق هستند. همانطور که میدانید، زمان در بیت کوین همیشه رو به جلو حرکت نمیکند. به دلیل قوانین اجماع برای برچسبهای زمانی بلاکها، زمان گاهی اوقات میتواند یک یا دو بلاک برگردد و یا برای یک دقیقه متوقف شود.
این موضوع دلایل خوبی دارد. برچسبهای زمانی همواره در محدوده چند ساعتی نسبت به زمان واقعی حفظ میشوند. برای آن که قفلهای مبتنی بر برچسب زمانی معتبر شوند، از روش “میانگین زمان سپری شده” (MTP) استفاده میشود.
قفل زمانی مبتنی بر برچسب زمانی، به جای استفاده از برچسب زمانی بلاک فعلی، از برچسب زمانی میانگین ۱۱ بلاک قبلی استفاده میکند. این موضوع، پیشروی زمان را هموار میکند و تضمین میدهد که زمان هرگز به عقب بازنگردد.
انواع قفل زمانی
اکنون که مشخص شده است درباره چه موضوعی صحبت میکنیم، به توضیح خود ابزارها میپردازیم. در حال حاضر ۴ نوع قفل زمانی وجود دارد که عبارتند از:
- nLocktime
- nSequence
- (OP_CHECKLOCKTIMEVERIFY (OP_CLTV
- (OP_CHECKSEQUENCEVERIFY (OP_CSV
دو مورد از این قفلها در سطح اسکریپت و دو مورد در سطح تراکنش هستند.
قفل زمانی nLocktime
قفل nLocktime یک قفل زمانی مطلق و در سطح تراکنش است. این قفل همچنین تنها قفلی است که بخشی از چشمانداز اصلی ساتوشی ناکاموتو بود.
تراکنش یک ساختار داده ساده است که شامل نسخه، ورودیها، خروجیها و چند مورد دیگر است. قفل زمانی nLocktime مولفه lock_time را دارد که مخصوص به خود است. این مولفه، شماره بلاک یا برچسب زمانی را مشخص میکند.
تراکنش تا زمانی که زمان مورد نظر سپری نشده باشد، معتبر نمیشود. تراکنشهای ایجاد شده توسط هسته بیت کوین به طور پیشفرض دارای مولفه lock_time برای بلاک فعلی هستند تا از کاهش کارمزد جلوگیری شود.
زمانها به صورت عدد صحیح ۳۲ بیتی امضانشده بیان میشوند. اگر lock_time برابر با صفر باشد، رد میشود. اگر برابر با ۵۰۰,۰۰۰,۰۰۰ یا بیشتر باشد، به عنوان برچسب زمانی یونیکس در نظر گرفته میشود. بنابراین، قفل nLocktime میتواند با استفاده از شماره بلاکها، تراکنشها را تا ۹۵۰۰ سال مسدود کند.
نکته جالب این است که اگر تمام ورودیها دارای عدد متوالی 0xFFFFFFFF باشند، مولفه lock_time کاملا کنار گذاشته میشود. سیگنالهای RBF در BIP 125 تعریف شدهاند. استفاده از sequence_no در سیگنال، از نسخه قفل زمانی ساتوشی به جا مانده است.
در این مقطع برای تغییر این شرایط باید هاردفورک بزنیم. قفل nLocktime و اعداد متوالی ورودی، اساسا برای ایجاد مکانیزم بهروزرسانی تراکنش ایجاد شدهاند. ایده اصلی به این صورت بود که بتوانید تراکنشی با قفل زمانی ایجاد کنید و با ارسال نسخه جدید با حداقل یک عدد متوالی بیشتر جایگزین کنید.
اینطور برنامهریزی شده بود که ماینرها، تراکنشهایی با عدد متوالی کمتر را از ممپول کنار بگذارند. اگر تمام ورودیها دارای عدد متوالی حداکثری باشد، بدان معنا است که هیچ بهروزرسانی بیشتری امکانپذیر نیست و فارغ از قفل زمانی ، میتوان تراکنش را پاک کرد.
این ایده هرگز به طور کامل پیادهسازی نشد و بعدا کنار گذاشته شد. در اتفاقی عجیب، ساتوشی متصور شده بود که تمام ماینرها رفتار صادقانهای از خود نشان میدهند، اما این موضوع در مورد بیت کوین منطقی نبود. تضمین این مورد که ماینرها تراکنشهای بهروزرسانی شده را مشاهده کنند و در صورت مشاهده نسخه جدید تراکنشها، نسخه قدیمیتر را کنار بگذارند، غیرممکن است. ماینرها به جای جدیدترین نسخه، سودآورترین نسخه تراکنش را استخراج خواهند کرد.
مثالی از قفل nLocktime:
# Most of the transaction is omitted. Using decimal for human readability.
# Using hex for sequence numbers due to the presence of flags.
# Transaction is invalid until block 499999999 (this is a Bad Idea)
tx_1:
lock_time: 49999999
# Transaction is invalid until the MTP is 1514764800 (1/1/2018 0:00:00 GMT)
tx_2:
lock_time: 1514764800
# No lock time. Transaction is valid immediately.
tx_3:
lock_time: 0
# nLocktime lock is not in effect, because all sequence numbers are set to 0xFFFFFFFF
tx_4:
lock_time: 3928420
input_1:
sequence_no: 0xFFFFFFFFnSequence
قفل زمانی nSequence:
قفل زمانی nSequence یک قفل زمانی نسبی در سطح تراکنش است. این قفل، مولفه sequence_no قدیمی هر ورودی را مجددا هدفگذاری میکند تا تراکنشهای بر اساس زمان سپری شده، تایید خروجیهای قبلی را نامعتبر کند. قفلهای nSequence در BIP 68 معرفی شدند و توسط سافت فورکی در اواسط سال ۲۰۱۶ فعال شدند.
اعداد متوالی از ابتدا وجود داشتهاند. اما از آنجایی که جایگزینی تراکنش هرگز پیادهسازی نشد، بلااستفاده ماندند. به مدت چندین سال، تنها کاری که این اعداد میتوانستند انجام دهند، غیرفعال کردن قفل nLocktime بود. اکنون، اعداد متوالی برای اعمال کردم قفلهای زمانی نسبی در سطح تراکنش مورد استفاده قرار میگیرند.
قفلهای nSequence بر روی هر ورودی تعیین میشوند و بر اساس خروجی که هر ورودی مصرف میکند سنجیده میشوند. این موضوع بدان معنا است که چندین شرط متفاوت قفل زمانی ، میتوانند در یک تراکنش حضور داشته باشند. به منظور آن که تراکنشی معتبر شود، تمام شرایط باید محقق شود. اگر حتی یک قفل متوالی بر اساس شرایط نباشد، تمام تراکنش رد خواهد شد.
توسعهدهندگان بیت کوین در استفاده مجدد از موارد بلااستفاده بسیار ماهر هستند و شما گاهی اوقات با مشکلاتی مواجه میشوید. از آنجایی که قفلهای زمانی nSequence، مولفه sequence_no را مجددا هدفگذاری میکنند، اختلافهایی به وجود میآید.
حوزه متوالی ۳۲ بیتی است، اما نمیتوانیم از تمام آن استفاده کنیم؛ زیرا با قفل nLocktime و RBF تداخل ایجاد خواهد کرد. به علاوه، sequence_no یکی از معدود جاهایی است که فرصت ایجاد تغییرات آتی را داریم. به منظور ایجاد توازن در این تقاضاها، قفل nSequence ایجاد شده تا فقط از ۱۸ بیت از ۳۲ بیت موجود استفاده کند. در نتیجه ۱۴ بیت برای استفادههای آتی باقی میماند.
دو بیت نشانههایی هستند، که به نود میگویند چگونه در مولفه sequence_no مداخله کند. مهمترین بیت، نشانه غیرفعالسازی است. اگر نشانه غیرفعالسازی اعمال شود، قفلهای nSequence غیرفعال میشوند. اگر نشانه غیرفعالسازی اعمال نشود، باقی مولفه sequence_no به عنوان قفل زمانی نسبی تعریف میشود. بیت بیست و دوم، نشانه نوع قفل است؛ اگر این نشانه اعمال شده باشد، قفل در ثانیهها وجود دارد. اگر اعمال نشده باشد، قفل در بلاکها وجود دارد.
کم اهمیتترین ۱۶ بیت sequence_no، برای رمزگشایی زمان هدف مورد استفاده قرار میگیرد. برخلاف nLocktime، قفل nSequence فقط از ۱۶ بیت برای رمزگشایی قفل زمانی استفاده میکند. این موضوع بدان معنا است که قفلهای زمانی nSequence به ۶۵۵۳۵ واحد محدود هستند. این شرایط، مسدودسازی تراکنش را برای ۴۵۵ روز امکانپذیر میسازد، اما بر حسب ثانیه، فقط ۱۸ ساعت را امکانپذیر میکند. به منظور بهبود این شرایط، قفل nSequence بر حسب ثانیه سنجیده نمیشود و در عوض، از بستههای ۵۱۲ ثانیهای استفاده میشود. اگر نشانه نوع تراکنش اعمال شده باشد، قفل زمانی برای ۱۶ واحد تعیین میشود و ورودی تا سپری شدن ۱۶ * ۵۱۲ ثانیه مسدود خواهد بود.
تراکنشهایی که توسط هسته بیت کوین ایجاد میشوند، به طور پیشفرض دارای sequence_no هستند که برای هر ورودی بر روی 0xFFFFFFFE تعیین شده است. این موضوع به قفل nLocktime امکان میدهد تا کاهش کارمزد و جایگزینی با کارمزد (Replace-By-Fee) را غیرفعال کند.
تراکنشهای جایگزینی با کارمزد، معمولا دارای sequence_no هستند که برای هر ورودی بر روی 0xFFFFFFFD تعیین شده است. این نکته قابل ذکر است که RBF یک تغییر در پروتکل نیست، بلکه تغییر در سیاست پیشفرض ماینینگ است. هر چند از آنجایی که باید sequence_no کمتر از 0xFFFFFFFD باشد تا قفلهای nSequence معنادار باشند، تمام تراکنشهای مسدودشده nSequence به سمت RBF متمایل میشوند.
مثالی از قفل nSequence:
# Most of the transaction is omitted. Using decimal for human readability.
# Using hex for sequence numbers due to the presence of flags.
# This transaction is locked for 4096 second. Just over 1 hour.
tx_1:
input_1:
sequence_no: 0x00400008
# Disable flag is not set, type flag is set. Input locked for 8 * 512 seconds.
# This transaction is not nSequence locked, but may be nLocktime locked, and allows RBF.
tx_2:
input_1:
sequence_no: 0xFEDC3210
# Disable flag is set. nSequence locking disabled.
# This transaction is invalid until 16 blocks have elapsed since input_1’s prevout confirms.
tx_3:
input_1:
sequence_no: 0x00000010
# Disable flag is not set, type flag not set. This input locked for 16 blocks.
input_2:
sequence_no: 0xFFFFFFFF
# Disable flag is set.
# This transaction is not time locked, but has opted to allow Replace-By-Fee.
tx_4:
lock_time: 0
input_1:
sequence_no: 0xFFFFFFFE
# nSequence is disabled, nLocktime is enabled, RBF is not signaled.
input_2:
sequence_no: 0xFFFFFFFD
# nSequence is disabled, nLocktime is enabled, RBF is signaled.
# This transaction is not valid until block 506221
# It is also not valid until 87040 seconds have passed since the confirmation of input_1’s previous output
tx_5:
lock_time: 506221
input_1:
sequence_no: 0x004000AA
قفل زمانی CLTV
قفل زمانی (OP_CHECKLOCKTIMEVERIFY (OP_CLTV یک قفل زمانی مطلق در سطح اسکریپت است. این قفل در BIP 65 تعریف شده و در اواخر سال ۲۰۱۵ با سافت فورک وارد شبکه اصلی شده است. قفل OP_CLTV، قراردادهای هش شده دارای قفل زمانی را فعال کرده و در نتیجه، یکی از الزامات ضروری نسخه اول کانالهای لایتنینگ است.
سورس این قفل ساده و دقیق است و شامل کمتر از ۲۰ خط کد است. به عبارت سادهتر میتوان گفت که قفل OP_CLTV، آیتم برتر را با قفل زمانی nLocktime مقایسه میکند. این قفل بررسی میکند که آیتم برتر بر حسب ثانیه و بلاک معتبر باشد و خود تراکنش، حداقل متناسب با قفل زمانی مسدود شده باشد. بدین ترتیب، قفل OP_CLTV بررسی میکند که تراکنش قبل از زمان مشخص شده، تایید نشود.
قفل OP_CHECKLOCKTIMEVERIFY باعث میشود که ارزیابی اسکریپت در پنج موقعیت زیر امکانپذیر نباشد:
۱- استک (stack) خالی باشد. (هیچ زمان هدفی برای بررسی توسط OP_CLTV مشخص نشده باشد).
۲- آیتم برتر استک کمتر از صفر باشد. (قفل زمانی منفی بیمعنی است).
۳- قفل nLocktime بر حسب بلاک باشد و آیتم برتر استک از ثانیه استفاده کند و برعکس.
۴- آیتم برتر استک بزرگتر از قفل زمانی تراکنش باشد. (زمان کافی سپری نشده باشد).
۵- مولفه nSequence آید ورودی بر روی 0xFFFFFFFF تعیین شده باشد.
قفل OP_CLTV جایگزین OP_NOP2 میشود که هیچ کاری نمیکند. طراحی OP_CLTV برای جایگزین شدن OP_NOP2 نکته جالبی را به همراه دارد؛ OP_CLTV باید استک را دقیقا همانگونه که پیدا کرده است رها کند. به همین دلیل، OP_CLTV آیتم استک را میخواند، اما آن را مصرف نمیکند. OP_CLTV قفل زمانی را بررسی میکند، اما سپس زمان هدف را رها میکند. بدین ترتیب، OP_CLTV همواره پس از OP_DROP میآید.
مقایسه قفل زمانی تعیین شده در اسکریپت یا قفل زمانی تراکنش، نکتهای بسیار هوشمندانه است؛ زیرا زمان فقط به طور غیرمستقیم بررسی میشود. OP_CLTV کار را با عهده قوانین اجماع nLocktime میسپرد، در حالی که همچنان به اسکریپتها امکان میدهد تا چندین شرایط قفل زمانی متفاوت را تعیین کنند و بررسی اعتبار امضای اسکریپت را در هر زمانی امکانپذیر میسازد.
نکته منفی این است که اگر OP_CLTV در اسکریپت استفاده شود، قفل زمانی باید در تراکنش تعیین شود و sequence_no کمتر از 0xFFFFFFFF باید در ورودی وجود داشته باشد.
مثالی از OP_CLTV:
# Most of the transaction is omitted. Using decimal for human readability.
# Using hex for sequence numbers due to the presence of flags.
# Anyone can spend, at or after block 506391
tx_1:
lock_time: 506391
input_1:
sequence_no: 0xFFFFFFFE
script:
506391 OP_CHECKLOCKTIMEVERIFY OP_DROP
# This transaction is invalid:
# The lock_time is in blocks, and the CLTV is in seconds
# The sequence_no is 0xFFFFFFFF
tx_2:
lock_time: 506391
input_1:
sequence_no: 0xFFFFFFFF
script:
1514764800 OP_CHECKLOCKTIMEVERIFY OP_DROP
# This transaction is invalid
# The top stack item is greater than the lock_time
tx_3:
lock_time: 506391
input_1:
sequence_no: 0xFFFFFFFE
script:
600000 OP_CHECKLOCKTIMEVERIFY OP_DROP
# This transaction is valid at block 512462, but only if at least 32 * 512 seconds have passed since its previous output confirmed.
# A separate transaction could be constructed to spend the coins between 506391 and 512462
tx_4:
lock_time: 512462
input_1:
sequence_no: 0x00400020
script:
506391 OP_CHECKLOCKTIMEVERIFY OP_DROP
# This transaction becomes valid at block 506321
# The script allows an alternate execution path using 2-of-2 multisig.
# A separate transaction can be created that will not be time locked.
tx_5:
lock_time: 506321
input_1:
sequence_no: 0xFFFFFFFE
scriptsig:
OP_TRUE
script:
OP_IF
506321 OP_CHECKLOCKTIMEVERIFY OP_DROP
OP_ELSE
OP_2 <pubkey_1> <pubkey_2> OP_2 OP_CHECKMULTISIG
OP_ENDIF
# This is a variation of an HTLC.
# This transaction is valid at block 507381 assuming:
# 1. The secret for input_2’s script matches the expected secret hash
# 2. Valid signatures and pubkeys are provided for input_2
# 3. input_2’s nSequence time-lock is respected.
tx_6:
lock_time: 507381
input_1:
sequence_no: 0xFFFFFFFE
script:
507381 OP_CHECKLOCKTIMEVERIFY OP_DROP
input_2:
sequence_no: 0x000000A0
scriptsig:
<signature> <pubkey> <secret>
script
OP_HASH160 <secret hash> OP_EQUALVERIFY
OP_DUP OP_HASH160 <pub keyhash> OP_EQUALVERIFY OP_CHECKSIGOP_CSV
قفل زمانی CSV
قفل زمانی (OP_CHECKSEQUENCEVERIFY (OP_CSV یک قفل زمانی نسبی در سطح اسکریپت است. این قفل در BIP 112 تعریف شده و همراه با nSequence و MTP در اواسط ۲۰۱۶ با سافت فورک وارد شبکه شده است.
قفل OP_CSV از نظر عملکرد به شدت مشابه با OP_CLTV است. OP_CSV به جای بررسی زمان، آیتم برتر استک را با sequence_no ورودی مقایسه میکند. OP_CSV همانگونه به تجزیه و بررسی آیتمهای استک میپردازد که nSequence قفلهای زمانی را تفسیر میکند. OP_CSV در شرایط زیر با خطا مواجه میشود:
۱. استک (stack) خالی باشد. (هیچ زمان هدفی برای بررسی توسط OP_CLTV مشخص نشده باشد).
۲. آیتم برتر استک کمتر از صفر باشد. ( قفل زمانی منفی بیمعنی است).
۳. نشان غیرفعالسازی آیتم برتر استک تعیین نشده باشد و حداقل یکی از موارد زیر وجود داشته باشد:
- نسخه تراکنش کمتر از ۲ باشد (تراکنش از OP_CSV پشتیبانی نکند).
- نشان غیرفعالسازی sequence_no ورودی اعمال شده باشد ( قفل زمانی نسبی غیرفعال باشد).
- نشان نوع آیتم برتر استک و sequence_no ورودی مشابه نباشند (از یک معیار بهره نبرند).
- طول مدت ۱۶ بیتی آیتم برتر استک بیشتر از مدت زمان sequence_no ورودی باشد.
قفل OP_CSV جایگزین OP_NOP3 میشود و هنگامی که اجرا میشود، نباید در استک تغییری دهد تا پشتیبانی از کلاینتهای قدیمی را حفظ کند. این قفل زمانی ، آیتم برتر استک را میخواند؛ اما از آن استفاده نمیکند. بنابراین مجددا با OP_DROP جفتسازی میشود. اگر نشان غیرفعالسازی آیتم برتر تعیین شود، OP_CSV همانند OP_NOP3 عمل میکند.
همانطور که در بخش قفل زمانی نسبی گفتیم، قفل زمانی OP_CSV ابزاری بسیار مناسب برای اتصال زنجیرهای از تراکنشهاست. اگر به جای آن از OP_CLTV استفاده کنیم، کل زنجیره تراکنشها دارای تاریخ انقضای مطلق میشود. قفل OP_CSV به ما امکان میدهد تا تاریخ انقضای متناسب با اولین انتشار تراکنش را تعیین کنیم.
تراکنشها پس از تایید نمیتوانند بدون سازماندهی مجدد زنجیره لغو شوند؛ اما به صورت زنجیره در آوردن تراکنشها با قفل زمانی OP_CSV، به ما امکان میدهد تا اسکریپتی ایجاد کنیم که تقریبا میتواند این ویژگی را به وجود بیاورد.
با استفاده از OP_IF میتوانیم چندین تراکنش ایجاد کنیم که خروجی یکسانی را خرج کنند و اطمینان حاصل شود که یک قفل زمانی نسبی دارند؛ سپس، اگر نسخه قفلگذاریشده تراکنش طی مدت قفل زمانی منتشر شود، نسخه بدون قفل ابتدا تایید میشود و کوینها را خرج میکند. این موضوع بدان معنا است که میتوانیم برای تراکنشهای خاصی اولویت قائل شویم و اجرای قراردادهای هوشمند پیچیده را کنترل کنیم. شبکه لایتنینگ استفاده زیادی از این موضوع میکند.
مثالی از قفل OP_CSV:
# Most of the transaction is omitted. Using decimal for human readability.
# Using hex for sequence numbers due to the presence of flags.
# Anyone can spend, 255 blocks after the previous output confifrms.
tx_1:
lock_time: 0
input_1:
sequence_no: 0x000000FF
script:
0x000000FF OP_CHECKSEQUENCEVERIFY OP_DROP
# Anyone can spend, so long as both of the following are true:
# a) 16,384 seconds have passed since input_1’s previous output was confirmed
# b) 255 blocks have passed since input_2’s previous output was confirmed
tx_2:
lock_time: 0
input_1:
sequence_no: 0x00400020
script:
0x00400020 OP_CHECKSEQUENCEVERIFY OP_DROP
input_2:
sequence_no: 0x000000FF
script:
0x000000FF OP_CHECKSEQUENCEVERIFY OP_DROP
# Anyone can spend, so long as 256 blocks have passed since input_1’s previous output.
# Note that a separate transaction can be created to spend these coins.
# The alternate path would specify a lock_time of at least 506321.
# The script allows either an absolute or relative time lock, whichever is shorter.
tx_3:
lock_time: 0
input_1:
sequence_no: 0x00000100
scriptsig:
OP_FALSE
script:
OP_IF
506321 OP_CHECKLOCKTIMEVERIFY
OP_ELSE
0x00000100 OP_CHECKSEQUENCEVERIFY
OP_ENDIF
OP_DROP
# This transaction is invalid until 1/1/2020,
# AND until 31457280 seconds after the previous output confirmed.
# It also specifies a single approved spender by their pubkey.
tx_4:
lock_time: 1577836800
input_1:
sequence_no: 0x0004F000 # type flag is set
scriptsig:
<signature> <pubkey>
script:
1577836800 OP_CHECKLOCKTIMEVERIFY OP_DROP
0x0004F000 OP_CHECKSEQUENCEVERIFY OP_DROP
OP_DUP OP_HASH160 <pubkey hash> OP_EQUALVERIFY
OP_CHECKSIGVERIFY
# This transaction is invalid 3 ways:
# 1) input_1’s script fails because the stack item’s 16-bit lock duration is greater than specified in the sequence_no.
# 2) input_2’s script fails because the sequence_no’s type flag is not set, while the stack item’s type flag is set.
# 3) input_3’s script fails because the stack is not empty at the end.
tx_5:
lock_time: 0
input_1:
sequence_no: 0x0004F000
script:
0x0004FFFF OP_CHECKSEQUENCEVERIFY OP_DROP
input_2:
sequence_no: 0x0000FFFF
script:
0x0004FFFF OP_CHECKSEQUENCEVERIFY OP_DROP
input_3:
sequence_no: 0x00000001
script:
0x00000001 OP_CHECKSEQUENCEVERIFYReview