Permalink
Switch branches/tags
Nothing to show
Find file Copy path
83ef47c Oct 2, 2016
SergioDemianLerner P2WSH
375 lines (275 sloc) 28.6 KB
  BIP: R10 (internal number, not officially assigned)
  Title: Drivechain using OP_COUNT_ACKS
  Author: Sergio Demian Lerner 
  Status: Draft
  Type: Standards Track
  Created: 2016-09-30
  Version: 1.2

Abstract

This BIP describes the new opcode OP_COUNT_ACKS that adds Bitcoin drivechain capabilities as a soft-fork. A drivechain is practical and low-complexity extension method to add user-defined functionality executed in a secondary blockchain to Bitcoin, by means of a 2-way-peg. The drivechain extension proposed allows the creation of flexible two-pay pegs, user-defined acceptance and rejection thresholds, and hybrid solutions such as combining a drivechain with a set of notary signatures.

Motivation

Bitcoin aims to be both a decentralized settlement/payment system (the network) and a store of value (the currency). The Bitcoin network works 24/7 to keep safe billions of dollars. Therefore, there is little room for experimentation and ground-breaking changes in the protocol: improving Bitcoin (the network) has been compared to repairing a plane during flight.

This has not prevented some innovation within the Bitcoin community. Nevertheless, most of the new ideas must wait until there is a clear use case. There is little economic incentive to develop a new use case if it will depend on a new feature, so there is a chicken-and-egg problem. Finally most new ideas end up being captured by alt-coins with lower probability of success.

The Sidechain method was proposed to improve Bitcoin with low impact in its security, allowing adding functionality to Bitcoin (the currency) but isolating the Bitcoin network from potential vulnerabilities in the sidechain. However, adding generic sidechain integration to Bitcoin is complex and no generic proposal has been published. The only existing sidechain implementation works only for blockchains which have a block and transaction structure similar to Bitcoin. In the particular case that the sidechain is merge-mined, and there is high engagement in merge-mining, sidechains do not provide more security than "algorithmic proxy custody" by miners, as defined below.

We define algorithmic proxy custody as the automatic custody of cryptocurrency by a set of parties, where the release of cryptocurrency in custody is at least partially controlled by approval signals generated by programs run by these parties, and where programs base their approvals on the observation of a consensus for the release in another secondary blockchain, and the secondary blockchain has authoritative responsibility to command the release. Once the command is produced, it is fully authoritative and proxy custodians must obey.

Therefore there is algorithmic proxy custody when there are a set of proxy consensus programs. Algorithmic custody also implies that programs cannot decide approvals based on any other information, such as identity, reputation, source or destination of the funds.

Algorithmic proxy custody can also be partial: the transaction to release the funds in custody may require additional signers, such as notaries.

When algorithmic proxy custody is carried out by blockchain miners, and when miners use the primary blockchain as a means to distribute messages to manage the approval process, this has been called a drivechain.

In a drivechain miners mark blocks with small data tags to publish that they acknowledge that the secondary blockchain has commanded a release of funds. If the number of acknowledge tags is over a pre-defined threshold, a specific transaction related to the funds release is allowed to be included in a block. The scriptSig of the transaction may require additional restrictions, which are out of the control of the miners.

A miner must also issue a nack when a transaction has been proposed but the miner has not received a command by the secondary chain to release the funds using that transaction candidate.

We propose a soft-fork that defines a new opcode (redefining a NOP opcode) as the OP_COUNT_ACKS using the segwit script versioning system (e.g. version 1 scripts).

Specification

An ack-poll is the process which miners acknowledge the existence of a command authored by a secondary blockchain that orders the release of funds for a certain transaction. At any time there can be zero or more active ack-polls. After a pre-defined number of blocks, an ack-poll deactivates. Each ack-poll is associated with a transaction candidate. A transaction is a candidate while there is an active ack-poll related to it. There can be only one authentic ack-poll related to a transaction candidate. It can be the case that two different secondary blockchains specify the same transaction candidate, but one of them will clearly be unauthentic. A transaction remains a candidate until it is either discarded by the protocol (because it did not represent an authentic command created by the secondary blockchain at the time of expiry) or be included in a block. Miners always try to acknowledge the transactions candidates they have been commanded to. The only reason why a miner may not acknowledge a candidate is due to lack of space to include the proper ack tag in a block, or due to an operative problem. In case miners do not reach the threshold required to enable the transaction to be included in a block, a new ack-poll can be started for the same transaction candidate. If a maximum period elapses and an enabled transaction is not included in a block, the transaction is disabled and a new ack-poll must take place. To ack for one or more transaction candidates, miners embed the message tag “ACK:” followed by a serialized list of elements. Each element is itself a list of acks for an specific secondary blockchain. The data structure following the "ACK:" tag is of type FULL_ACK_LIST. The grammar of FULL_ACK_LIST is the following:

FULL_ACK_LIST: { CHAIN_ACK_LIST... }
CHAIN_ACK_LIST: { secondary_chain_id ACK_LIST }
ACK_LIST: { ACK... }
ACK: tx_hash_prefix [ tx_hash_preimage ]

In this grammar:

  • { x... } is interpreted as a list of items of type x. Every item in a list has the same format, and only one format is expected for each item. Therefore, the parser can distinguish between individual items and lists of items.
  • [ x ] is interpreted as an optional argument x. Optional arguments can only appear at the tail of a list.

The data is serialized in the following format:

  • A serialized list begins with a compact Uint specifying the list length in bytes (including all list payload), followed by the serialized items. A length of zero means no items in the list.
  • An serialized item begins with a compact Uint specifying the item length in bytes, followed by the payload.

The tag and tag payload are stored in the coinbase field of their coinbase transactions. Therefore the first field after the "ACK:" string is a compactSize uint specifying the tag payload. To find the ACK tag, the coinbase field is scanned from start to end. Only the first occurrence of the tag "ACK:" is analysed for correctness. If the script that follows is invalid (any compact uint size greater than available space) then the whole tag is considered invalid and no data following the tag is processed. The maximum size of the payload of a ACK tag is 100 bytes (this is enforced because the maximum size of the coinbase field is 100 bytes). The secondary_chain_id cannot be repeated in a tag. If repeated, it is ignored. The same proposal cannot be ack-ed twice (identified by the chain id and the hash prefix) even if the prefixes are different but refer to the same candidate. If the same proposal is ack-ed more than once, then the additional acks are ignored.

  • secondary_chain_id is blob that identifies the secondary chain.
  • tx_hash_prefix is the transaction ID (double SHA256 hash) or a prefix of the transaction ID for the transaction that is proposed (in the secondary chain) to spend the locked bitcoins.
  • tx_hash_preimage is the single SHA256 pre-image of the tx_hash_prefix. If the pre-image has already been shown in a previous ack (when the candidate is created), this field should be left out. This is for preventing miners DoS-ing the ack-poll process by creating proposals that match another proposal prefix, and therefore force the remaining miners to use full transactions hashes instead of short pre-fixes. If the pre-image is given, then the tx_hash_prefix must be empty. Nodes must compute the SHA256 hash of tx_hash_prefix to obtain tx_hash. This saves space in the coinbase.

Note that the miner that acks a transaction indirectly pays an extra amount in fees because of the block space consumed by the proposal (e.g. approximately 33 additional bytes for a new proposal, but can be as low as a 10 bytes for an ack). However, this extra fee is currently so low and can be ignored. By not including an ack for any proposal but including the secondary_chain_id means that all proposal for that secondary_chain_id receive a negative ack.

Example 1

The following coinbase tags embedded in successive blocks create 5 different proposals:

1) ACK: {{ DRVCOIN {{{} 0x101010....10}}}} pre-image of 0xbaa501b37267c06d8d20f316622f90a3e343e9e730771f2ce2e314b794e31853 
2) ACK: {{ DRVCOIN {{{} 0x202020....20}}}} pre-image of 0x85e7eac2862f1cbd85bc18769c75172c3fdcd899ab468b9e973d59ec620d9991
3) ACK: {{ DRVCOIN {{{} 0x303030....30}}}} pre-image of 0x84e0c0eafaa95a34c293f278ac52e45ce537bab5e752a00e6959a13ae103b65a
4) ACK: {{ YCOIN   {{{} 0x404040....40}}}} pre-image of 0x92b7eb5290d8d6e3ac79215cb4bdb07fe89629ee720be4332b3daa842b7ec80a
5) ACK: {{ XCOIN   {{{} 0x505050....50}}}} pre-image of 0xb37361a0be8af8905de1f4384e701365ece4313dd5e064d375eb2851c043ba68

(First element is secondary_chain_id, second element is transaction hash proposal (empty) and third element is transaction hash proposal pre-image)

The following block contains the tag:

6) ACK: { { DRVCOIN {{0xba} {0x84e0}} } { XCOIN {{0xff}}} }

This last tag acks for the proposal 1, for proposal 3, against the proposal 2, against the proposal 5 (because the ack does not have a candidate) and ignores the proposal 4 (for YCOIN). The ack for proposal 3 is not using the minimum possible prefix (0x84), but it is still a valid ack.

Using transaction prefixes reduces coinbase space consumption. If a miner is performing "SPV mining" and does not know the contents of the previous block coinbase field, and wants to ack for a proposal that has not been published before the last block, it should include the full ack transaction hash (32 bytes) plus the pre-image (32 bytes). However miners must not include the pre-image if they are ack-ing for a pre-existent proposal, because by doing so they are flagging that a new ack-poll may start at that point due to the sliding-window nature of the ack-ing process. Miners SHOULD also include an ack tag for a sidechain_id with an empty list of acks to announce they are ready to ack for that secondary chain, but there is no active ack-poll (e.g. ACK: {{DRVCOIN {}}}).

There can be many active proposals for the same drivechain, and a miner can ack for many of them simultaneously adding more items to ACK_LIST.

Specification details

The opcode NOP? is redefined as OP_COUNT_ACKS. This opcode scans a number of past coinbase fields and counts acks for a certain spending transaction proposal.

The opcode has the following arguments:

  • secondary_chain_id
  • ack_period (in blocks)
  • liveness_period (in blocks)

Description of arguments:

  • secondary_chain_id is a blob that identifies the drivechain (e.g "PrivateBitcoin" for a drivechain that implements a anonymous cryptocurrency protocol).
  • ack_period represents the number of blocks after the proposal is published where acks are counted. After this number of blocks, any ack for the proposal is discarded. ack_period valid range is [1..144].
  • liveness_period represents the number of blocks after the ack_period ends when the transaction specified by the proposal is valid. Liveness_period range is [100..144]. Therefore the spending transaction cannot be included before 100 blocks after the ack-ing period ends. The 100 block forced confirmation gap is required so the maturity of a transaction consuming an output using a script that contains the COUNT_ACKS opcode is equal or higher than the maturity of coinbase outputs.

OP_COUNT_ACKS performs two stages of computation:

  1. Opcode arguments validation. Arguments are validated against pre-established bounds. if not in range, the script is aborted.
  2. Miner's ack counting.

If both stages are performed successfully, the input arguments are popped from the stack and following values are pushed in the stack:

  1. positive_acks
  2. negative_acks

Opcode arguments validation Stage

All the following conditions on opcode arguments must be met for the execution to be able to continue. If not, then the script execution is aborted (and the script does not verify):

  • secondary_chain_id blob with length in [1..20]
  • ack_period (in blocks) integer in [1..max_ack_period]. max_ack_period is 144.
  • liveness_period (in blocks) integer in [1..max_liveness_period]. max_liveness_period is 144.
  • n-liveness_period-ack_period>=0 (there must be enough blocks for the poll)

Miner's Ack Counting Stage

Let secondary_chain_id be the chain id that is being evaluated. Let A be a vector containing (key,pos_acks,neg_acks) triple, where key is a blob specifying the transaction hash and ack values are uint32. Let spend_tx_hash be the hash of the transaction that is used to spend the output that contains the OP_COUNT_ACKS being executed.

The following pseudo-code specifies ack-counting algorithm and returns (miner_positive_acks,miner_negative_acks):

1. Let poll_start :=n-liveness_period-ack_period
2. For i :=poll_start to poll_start+ack_period-1 do
2.1. C := GetCoinBaseFieldOfBlock(i)
2.2. Find tag "ACK:" in C.
2.3. if not (C contains valid "ACK:" tag and payload) then continue
2.4. Extract the FULL_ACK_LIST into L.
2.5. For j :=0 to Length(L)-1 do
2.5.1. if (L[j][0]=secondary_chain_id ) then
2.5.1.1. ack_list :=L[j][1]
2.5.1.2. new_acks :=[] // set of integers corresponding to acks indexes
2.5.1.3. For k :=0 to Length(ack_list)-1 do
2.5.1.3.1. ack :=ack_list[k]
2.5.1.3.2. tx_hash :=ack[0]
2.5.1.3.3. tx_hash_preimage :=ack[1]
2.5.1.3.4. valid :=((Length(tx_hash)<=32) AND (length(tx_hash_preimage)=0)) OR ((Length(tx_hash)=32) AND (length(tx_hash_preimage)=32) AND (SHA256(tx_hash_preimage)=tx_hash))  /// Chenge this to allow empty tx_hash in proposals
2.5.1.3.5. if not valid then
2.5.1.3.5.1. continue 
2.5.1.3.6. if not (tx_hash is a prefix of any key in A) then
2.5.1.3.6.1. if length(tx_hash_preimage)=32 then
2.5.1.3.6.1.1. A.Append(tx_hash,0) // tx_hash is key, 0 is initial ack count (decremented later)
2.5.1.3.6.1.2. new_acks.add(Length(A)-1)
2.5.1.3.6.2. else
2.5.1.3.6.2.1. if not (tx_hash is a prefix of spend_tx_hash) then // an optimization to reduce new_ack size
2.5.1.3.6.2.1.1. continue
2.5.1.3.6.2.2. Let t be the first index in A such as tx_hash is a prefix of A[t].key
2.5.1.3.6.2.3. new_acks.Add(t)
2.5.1.4. For k :=0 to Length(A)-1 do
2.5.1.4.1. if (k in new_acks) then
2.5.1.4.1.1. A[k].pos_acks :=A[k].pos_acks+1
2.5.1.4.2. else
2.5.1.4.2.1. if (allow_negative_acks) then
2.5.1.4.2.1.1. A[k].neg_acks :=A[k].neg_acks+1
2.5.1.5. break
3. If there is no index t so that A[t].key = spend_tx_hash then return 0, and exit
4. Let t be the first index where A[t].key = spend_tx_hash.
5. Return (A[t].pos_acks, A[t].neg_acks)

The sliding-window nature of this ack-ing system means that miners should only stop ack-ing positively when the candidate transaction is finally accepted in a block or when the poll liveness period from the last (re)proposal has elapsed. Miners should stop nack-ing when the liveness period of the last proposal has elapsed. Step 2.5.1.3.6.2.1 is an optimization step. If included, then acks for spend_tx_hash will be counted correctly, but acks for other candidates will not.

Ack de-serialization pseudo-code

ReadElement(string source) -> (string result,string tail)

1. (len,rest) :=ReadCompactUint(source); // if invalid CompactUInt, raise exception
2. if (len>length(rest)) then raise exception
3. result :=copy(rest,0,len) // from index 0, len bytes
4. tail :=copy(rest,len,Length(result)-len)


ReadAcks(string s) -> (ACK_LIST)
 
1. Let s be the coinbase field from the end of the "ACK:" string to the end of the field
2. (r,t) :=ReadElement(s); 
3. i :=0
4. while(Length(s)>0) do
5.1. (Li,r) :=ReadElement(r); // Li = { chainID { ... } }
5.2. (chainId,t) :=ReadElement(Li) // t = { {v1 p1} {v2 p2}... }
5.3. CHAIN_ACK_LIST :=new List()
5.4. L.Append(CHAIN_ACK_LIST)
5.5. CHAIN_ACK_LIST.Append(chainId)
5.6. ACK_LIST  :=new List()
5.7. CHAIN_ACK_LIST.Append(ACK_LIST)
5.8. (x,y) :=ReadElement(t) // x = {v1 p2} , {v2 p2} ...
5.9. If (Length(y)>0) then raise exception
5.3. j :=0
5.4. While (Length(y)>0)
5.4.1. (a,y) :=ReadElement(y) // v = {v1 p2} , y = {v2 p2} ...
5.4.2. ACK :=new List()
5.4.3. ACK_LIST.Append(ACK)
5.4.4. (a0,a) :=ReadElement(a)
5.4.5. ACK.Append(a0)
5.4.6. if (Length(a)>0) then
5.4.6.1. (a1,a) :=ReadElement(a)
5.4.6.2. ACK.Append(a1)
5.4.6.3. if (length(a)>0) then raise exception
5.4.7. inc(j)
5.5. inc(i)

Examples

Let the blockchain have only the following tags (line format: block-number,  tag):
101, ACK: {{ XCOIN {{{} 0x101010....10}}}} // pre-image of 0xbaa501b37267c06d8d20f316622f90a3e343e9e730771f2ce2e314b794e31853 
102, ACK: {{ XCOIN {{0xba}} }} // 2nd positive vote
... block 103..200 having the same tag as block 102..
201, ACK: {{ XCOIN {{ }} }}  // negative vote
... block 201..225 having the same tag as block 201..

Let the script be executed on a transaction included in block 370. Then the poll starts at block 82 and ends at block 225 (included).

scriptSig: 
	58434f494e	("XCOIN")
	144
	144
	OP_COUNT_ACKS    // Results in a stack that contains: 100 25
	OP_2DUP	   // duplicate ack counts
	OP_GREATERTHAN   // more positive than negative acks ?
	OP_VERIFY	   // abort if not
	OP_SUB		   // compute positive minus negative, push result into stack
	72		   // difference (positive-negative) acks required	
	OP_GREATERTHAN   // More than 50% positive difference, put 1 on stack, else put 0	
scriptPub: <empty>

Rationale

The system was designed with the following properties in mind:

  1. Interoperability with scripting system
  2. Zero risk of invalidating a block
  3. No additional computation during blockchain management and re-organization
  4. No change in Bitcoin security model
  5. Bounded computation of poll results
  6. Strong protection from DoS attacks
  7. Minimum block space consumption
  8. Zero risk of cross-secondary chain invalidation

We show how these properties are verified.

Interoperability

Compared to other drivechain designs, COUNT_ACKS opcode allow the combination of a drivechain with any other feature of the scripting system. For example, the COUNT_ACKS opcode allows to bootstrap a merged-mining two-way pegged cryptocurrency from an initial state when is has no merge-mining engagement to a state where it has a high merge-mining engagement, providing security notary acks in during the initial period. When a high merge-mining engagement is reached, the notaries can cease to sign or they can continue to contribute to the security of the drivechain, depending on the design choices of the secondary chain creators. Initially, if there is no merge-mining engagement, the notaries provide acks to release the locked funds, but the scriptPub can be parametrized such that a threshold of signatures is required to release them, so that still no individual notary has control.

Zero risk of block invalidation

The opcode and miner's ack-ing algorithm was designed such that acks in the coinbase field can never invalidate a block. Even if the ack field is filled with garbage, this will not invalidate the Bitcoin block. This prevents attacks against pools from malicious or faulty merge-mining plug-ins and also reduces the risk for miners not implementing the soft-fork.

No computation during blockchain management

There is no ack counting happening when a new block is added to the blockchain. The objetive is two-fold: it reduces to zero the impact of the drivechain system when there are no active drivechains and also it allows for testing the new opcode much more easily by building a single test blockchain and then executing different scripts with different opcode arguments.

No change in Bitcoin security model

By forcing the poll liveness period to be equal or higher than 100 blocks, any consequence of the poll result is only reflected in the blockchain at least 100 blocks after the poll is over. This bound makes the drivechain respect the same maturity rule as coinbases. It must be noted that even though the drivechain does not change the security model of Bitcoin, any blockchain that uses the bitcoin unit of account and holds a high amount of bitcoins does indeed affect the security of Bitcoin. Also merge-mining can modify the incentives of Bitcoin miners, and those incentives should be analysed.

Bounded computation of poll results

The liveness period and ack period limits reduces the depth to which the COUNT_ACKS opcode retrieves coinbase fields. This has two benefits: first sets a bound to the running time of the opcode and, second, it allows tags in blocks older than the compound a limit to be forget and so COUNT_ACKS is compatible with blockchain pruning.

Strong protection from DoS attacks

Polls created for unknown secondary chains can be safely ignored by miners. Unknown or fake transaction candidates created by malicious miners do interfere with honest candidates nor not they require honest miners to add any special information to the ack tags, since any candidate that is omitted from the tag is negatively acknowledged, when the secondary chain id is included.

Minimum block space consumption

By allowing miners to refer to transaction candidates by transaction id prefixes, the space consumption for a single ack can be as low as 2 bytes. Also by requiring a pre-image of the candidate transaction id to be specified by the miner that proposes the candidate we exponentially increase the cost of malicious miners proposing fake transaction ids in order to force the remaining miners to consume more coinbase space. Another possibility to further reduce this risk is to allow miners to scramble their tags with a explicit or implicit bit mask that is used as a key to a lightweight encryption function on transaction candidate ids. But this requires all active candidates to be re-scrambled each block, with increases the processing cost.

Zero risk of cross-secondary chain invalidation

By specifying list sizes as sizes in bytes instead of the number of elements in the for tag serialization, the list of acks corresponding to a tag of an specific secondary blockchain can be skipped if it is malformed. This allows a miner to collect tags from several secondary chains by means of plug-ins and join them together (adding the appropriate field sizes) without the risk that a malformed tag coming from a secondary blockchain affects the tags provided by the remaining secondary blockchains.

Backwards Compatibility

This BIP represents a soft-fork since it is based on Segwit script versioning system. Transactions containing the COUNT_ACKS opcode are non-standard to old implementations, which will (typically) not relay them nor include them in blocks. Pay-to-witness-script-hash (P2WSH) addresses can be used to allow the propagation of transactions that use COUNT_ACKS.

Miners that do not soft-fork and do not include non-standard transactions are not affected, since no consensus rule is added to the block header or coinbase validation. Miners that do not soft-fork but include non-standard transactions that can be delivered by external (possibly malicious) users can be attacked so that their blocks are not accepted by the majority of miners.

This BIP will be deployed using a standard majority threshold (as used in previous soft-forks) and will use the version bits to mark miners acks (as defined in BIPn).

If a majority of hashing power does not support the new validation rules, then roll-out will be postponed (or rejected if it becomes clear that a majority will never be achieved).

Broadcasting a transaction containing OP_ACK_COUNT

Transactions containing the OP_ACK_COUNT in scriptPubs are non-standard and should not be broadcast. Secondary chain designers should use P2WSH addresses, so that miners can include the scriptPub scripts in ScriptSig scripts. Transactions consuming outputs whose scriptPubs require OP_ACK_COUNT are currently also non-standard, and are included in blocks by the same miners that participate in the ack-poll process.

Security

The security parameters of a specific secondary chain are defined by the secondary chain designers. Any user wishing to lock bitcoins in order to move them to the secondary chain should use the parameter set specified by the secondary chain designers. This is generally done by the secondary chain providing a pay-to-witness-script-hash (P2WSH) address that contains the hash of a script which specifies the arguments. If bitcoins are locked for a secondary chain using a different set of parameters, there is no guarantee the secondary chain will accept the transfer and use the locked output in the future to unlock bitcoins. Those bitcoins therefore can be locked forever. Therefore transactions for transfers to secondary chains should either use P2WSH or be automated by applications and not crafted by hand.

There COUNT_ACKS opcode can not be used as a vector to perform a denial-of-service by exhausting CPU nor exhausting memory since:

  • The maximum number of blocks processed is 144 (max_ack_period)
  • The maximum number of different candidates that can be created per block is 3 (100 bytes/33 bytes=3).
  • The maximum number of acks that can be included per block is 50 (100 bytes/2 bytes).
  • The maximum number of different acks that can be created in total is 144.
  • The size consumed in memory by each stored candidate is approximately 50 bytes.
  • The maximum memory consumed by the ack counting algorithm is 7.2K bytes.
  • The maximum number of hash prefix comparisons while counting acks is 144*50=7200.
  • The maximum number of candidate hashes that need to be performed is 3*144 = 432.

In comparison, a script can use up to 400*10K bytes of stack, totalling 4M bytes.

Computational Cost

The cost of the COUNT_ACKS opcode in terms of sigops is set to be 2. The rationale of this selection is the following: Performing the ack counting requires fetching at most 144 recent generation transactions. The maximum amount of information that has to be fetched is 7.2K bytes. Assuming the most recent 288 coinbase fields can be kept cached in-memory (either by the OS or by the application), then coinbase fetching CPU cost is comparable to the cost of a single signature check. Assuming no cache, and a 10 msec per coinbase fetching time, the fetching cost becomes prohibitive, unless transaction verification is amortized by parallelization. Therefore, the Bitcoin implementation should cache the coinbase fields of generation transactions. The maximum cost in hashing of tx_hash_preimage values to obtain the corresponding tx_hash values is 432 hash digests, each of a message of size 32. This is comparable to the cost of a single signature verifications. Therefore, the accumulated maximum cost is comparable to 2 signature verifications.

Reference Implementation

An open-source reference implementation of COUNT_ACKS drivechain based on segwit, including the coinbase cache system is provided in the following github repository:

https://github.com/rootstock/bitcoin/tree/op-count-acks_devel (branch op-count-acks_devel)

This implementation is still incomplete to be a soft-fork. The following changes are required:

  • Implement soft-fork threshold using VersionBitsState() in ConnectBlock()
  • Define witness script version 1 ( SIGVERSION_WITNESS_V1 = 2)
  • Define constants SCRIPT_VERIFY_DRIVECHAIN and Consensus::DEPLOYMENT_DRIVECHAIN.
  • Add argument witversion to CScript::GetSigOpCount()so it can count the drivechain opcode as 2 signatures.
  • Replace most occurrences of "(witversion == 0)" with "((witversion == 0) || (witversion == 1))"
  • Replace occurrences of "(sigversion == SIGVERSION_WITNESS_V0)" with "((sigversion == SIGVERSION_WITNESS_V0) || (sigversion == SIGVERSION_WITNESS_V1))"

See Also

  • ... todo ...