nLockTime
e OP_CHECKLOCKTIMEVERIFY
(o CLTV) sono solo una faccia dell'equazione del timelock. Dall'altra parte ci sono nSequence
e OP_CHECKSEQUENCEVERIFY
, che possono essere utilizzati per controllare i tempi relativi piuttosto che i tempi assoluti.
⚠️ AVVISO VERSIONE: CSV è diventato disponibile con Bitcoin Core 0.12.1, nella primavera del 2016.
Ogni input in una transazione ha un valore nSequence
(o se preferisci sequence
). È stato uno strumento primario per le espansioni di Bitcoin come discusso in precedenza nel Capitolo 5.2 Rinviare le Transazioni con RBF e nel Capitolo 8.1 Inviare una Transazione con Blocco temporale, dove è stato utilizzato per segnalare RBF e nLockTime
, rispettivamente. Tuttavia, c'è un altro uso per nSequence
, descritto da BIP 68: puoi usarlo per creare un timelock relativo su una transazione.
Un timelock relativo è un blocco che viene posto su un input specifico di una transazione e che viene calcolato in relazione alla data di mining dell'UTXO utilizzato nell'input. Ad esempio, se un UTXO è stato minato al blocco #468260 e una transazione è stata creata dove l'input per quell'UTXO è stato dato un nSequence
di 100, allora la nuova transazione non potrebbe essere minata fino almeno al blocco #468360.
Facile!
ℹ️ NOTA — SEQUENCE: Questo è il terzo utilizzo del valore
nSequence
in Bitcoin. Qualsiasi valorenSequence
senza il 32° bit impostato (1<<31), quindi da 0x00000001 a 0x7ffffffff, sarà interpretato come un timelock relativo senVersion ≥ 2
(che è il valore predefinito a partire da Bitcoin Core 0.14.0). Dovresti fare attenzione per garantire che i timelock relativi non confliggano con gli altri due usi dinSequence
, per segnalarenTimeLock
e RBF.nTimeLock
di solito imposta un valore di 0xffffffff-1, dove un timelock relativo è disattivato; e RBF di solito imposta un valore di "1", dove un timelock relativo è irrilevante, perché definisce un timelock di 1 blocco.
In generale, ricorda: con un valore
nVersion
di 2, un valorenSequence
da 0x00000001 a 0x7fffffff consente timelock relativi, RBF enTimeLock
; un valorenSequence
da 0x7fffffff a 0xffffffff-2 consente RBF enTimeLock
; un valorenSequence
di 0xffffffff-1 consente solonTimeLock
; un valorenSequence
di 0xffffffff non consente nessuno; enVersion
può essere impostato a 1 per disabilitare i timelock relativi per qualsiasi valore dinSequence
. Uff!
Il formato per utilizzare nSequence
per rappresentare i timelock relativi è definito in BIP 68 ed è leggermente più complesso del semplice inserimento di un numero, come hai fatto per nTimeLock
. Invece, le specifiche BIP dividono il numero a quattro byte in tre parti:
- I primi due byte vengono utilizzati per specificare un locktime relativo.
- Il 23° bit viene utilizzato per segnalare positivamente se il lock si riferisce a un tempo anziché a un'altezza di blocco.
- Il 32° bit viene utilizzato per segnalare positivamente se i timelock relativi sono disattivati.
Detto ciò, la costruzione di un timelock relativo basato su blocchi è ancora abbastanza semplice, perché i due bit segnalati sono impostati a 0
, quindi imposti semplicemente nSequence
a un valore tra 1 e 0xffff (65535). La nuova transazione può essere minata quel numero di blocchi dopo che l'UTXO associato è stato minato.
Puoi invece impostare nSequence
come un tempo relativo, dove il lock dura per 512 secondi moltiplicato per il valore di nSequence
.
Per fare ciò:
- Decidi quanto in avanti impostare il tuo timelock relativo.
- Converti quel tempo in secondi.
- Dividi per 512.
- Arrotonda quel valore in su o in giù e impostalo come
nSequence
. - Imposta il 23° bit a true.
Per impostare un tempo 6 mesi nel futuro, devi prima calcolare come segue:
$ seconds=$((6*30*24*60*60))
$ nvalue=$(($seconds/512))
Poi, trasformalo in hex:
$ hexvalue=$(printf '%x\n' $nvalue)
Infine, esegui un'operazione bitwise-or sul 23° bit nel valore hex che hai creato:
$ relativevalue=$(printf '%x\n' $((0x$hexvalue | 0x400000)))
$ echo $relativevalue
4224679
Se converti nuovamente, vedrai che 4224679 = 10000000111011010100111. Il 23° bit è impostato a "1"; nel frattempo, i primi 2 byte, 0111011010100111, si convertono in 76A7 in hex o 30375 in decimale. Moltiplicalo per 512 e ottieni 15,55 milioni di secondi, che sono effettivamente 180 giorni.
Quindi vuoi creare una semplice transazione con un timelock relativo? Tutto ciò che devi fare è emettere una transazione dove il nSequence
in un input è impostato come mostrato sopra: con il nSequence
per quell'input impostato in modo che i primi due byte definiscano il timelock, il 23° bit definisca il tipo di timelock e il 32° bit sia impostato a falso.
Emetti la transazione e vedrai che non può essere legalmente minata fino a quando non saranno passati abbastanza blocchi o abbastanza tempo oltre il momento in cui l'UTXO è stato minato.
Tranne che praticamente nessuno lo fa. Le definizioni di BIP 68 per nSequence
sono state incorporate in Bitcoin Core allo stesso tempo di BIP 112, che descrive l'opcode CSV, l'equivalente di nSequence
dell'opcode CLTV. Proprio come CLTV, CSV offre capacità aumentate. Quindi, quasi tutto l'uso dei timelock relativi è stato con l'opcode CSV, non con il valore grezzo nSequence
da solo.
Timelock Assoluto | Timelock Relativo | |
---|---|---|
Blocco Transazione | nTimeLock | nSequence |
Blocco Output | OP_CHECKLOCKTIMEVERIFY | OP_CHECKSEQUENCEVERIFY |
OP_SEQUENCEVERIFY
negli Script Bitcoin funziona praticamente come OP_LOCKTIMEVERIFY
.
Potresti richiedere che un UTXO sia mantenuto per cento blocchi dopo il suo mining:
100 OP_CHECKSEQUENCEVERIFY
Oppure potresti fare un calcolo più complesso per richiedere che un UTXO sia mantenuto per sei mesi, nel qual caso finirai con un numero più complesso:
4224679 OP_CHECKSEQUENCEVERIFY
In questo caso useremo una scorciatoia:
<+6Months> OP_CHECKSEQUENCEVERIFY
⚠️ AVVISO: Ricorda che un timelock relativo è un intervallo di tempo dal mining dell'UTXO utilizzato come input. Non è un intervallo di tempo dopo che crei la transazione. Se utilizzi un UTXO che è già stato confermato cento volte e applichi un timelock relativo di 100 blocchi, sarà idoneo per il mining immediatamente. I timelock relativi hanno alcuni usi molto specifici, ma probabilmente non si applicano se il tuo unico obiettivo è determinare un tempo specifico nel futuro.
CSV ha molte delle stesse sottigliezze nell'uso di CLTV:
- Il campo
nVersion
deve essere impostato a 2 o più. - Il campo
nSequence
deve essere impostato a meno di 0x80000000. - Quando CSV viene eseguito, ci deve essere un operando sullo stack che sia compreso tra 0 e 0xf0000000-1.
- Sia l'operando dello stack che
nSequence
devono avere lo stesso valore nel 23° bit. - Il
nSequence
deve essere maggiore o uguale all'operando dello stack.
Proprio come con CLTV, quando stai spendendo nuovamente un UTXO con un CSV nelle sue condizioni di blocco, devi impostare nSequence
per abilitare la transazione. Di solito lo imposterai al valore esatto nello script di blocco.
Proprio come OP_CHECKLOCKTIMEVERIFY
, OP_CHECKSEQUENCEVERIFY
include un implicito OP_VERIFY
e lascia i suoi argomenti sullo stack, richiedendo un OP_DROP
quando hai finito.
Uno script che bloccherebbe i fondi fino a sei mesi dopo il mining dell'input e che richiederebbe quindi una firma in stile P2PKH standard sarebbe il seguente:
<+6Months> OP_CHECKSEQUENCEVERIFY OP_DROP OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
Quando codifichi uno script CSV, fai attenzione a come codifichi il valore intero per il timelock relativo. Dovrebbe essere passato come un intero a 3 byte, il che significa che stai ignorando il byte superiore, che potrebbe disattivare il timelock relativo. Poiché è un intero, assicurati di convertirlo in little-endian.
Questo può essere fatto con lo script integer2lehex.sh
dalla capitolo precedente.
Per un tempo relativo di 100 blocchi:
$ ./integer2lehex.sh 100
Integer: 100
LE Hex: 64
Length: 1 bytes
Hexcode: 0164
Anche se dovrebbe essere completato a 000064
, richiedendo un codice di 03000064
.
Per un tempo relativo di 6 mesi:
$ ./integer2lehex.sh 4224679
Integer: 4224679
LE Hex: a77640
Length: 3 bytes
Hexcode: 03a77640
Per spendere un UTXO bloccato con uno script CSV, devi impostare il nSequence
di quell'input a un valore maggiore del requisito nello script, ma inferiore al tempo tra l'UTXO e il blocco presente. Sì, questo significa che devi conoscere il requisito esatto nello script di blocco... ma hai una copia del redeemScript
, quindi se non conosci i requisiti, lo deserializzi e poi imposti il nSequence
al numero mostrato lì.
nSequence
e CSV offrono un'alternativa a nLockTime
e CLTV dove blocchi una transazione basata su un tempo relativo da quando l'input è stato minato, anziché basare il blocco su un tempo stabilito nel futuro. Funzionano quasi in modo identico, a parte il fatto che il valore nSequence
è codificato in modo leggermente diverso dal valore nLockTime
, con bit specifici che significano cose specifiche.
🔥 Qual è il potere di CSV? CSV non è solo un modo pigro per bloccare, quando non vuoi calcolare un tempo nel futuro. Invece, è un paradigma totalmente diverso, un blocco che useresti se fosse importante creare una durata minima specifica tra quando una transazione è minata e quando i suoi fondi possono essere spesi nuovamente. L'uso più ovvio è (ancora una volta) per un escrow, quando vuoi un tempo preciso tra l'input dei fondi e il loro output. Tuttavia, ha possibilità molto più potenti nelle transazioni off-chain, inclusi i canali di pagamento. Queste applicazioni sono per definizione basate su transazioni che non sono effettivamente inserite nella blockchain, il che significa che se sono successivamente inserite nella blockchain, un intervallo di tempo forzato può essere molto utile. Contratti Hashed Timelock sono stati una di queste implementazioni, potenziando la rete di pagamenti Lightning. Sono discussi nelCapitolo 13.3: Potenziare Bitcoin con Scripts.
Avanza attraverso "Bitcoin Scripting" col Capitolo 12: Ampliando Scripts di Bitcoin.