Skip to content
Switch branches/tags
Go to file
Cannot retrieve contributors at this time
  BIP: R11 (internal number, not officially assigned)
  Title: CountAcks Drivechain
  Author: Sergio Demian Lerner 
  Status: Draft
  Type: Standards Track
  Created: 2016-09-30
  Version: 1.3


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.


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.

Sidechains (or SPV sidechains[1]) were proposed[2] to improve Bitcoin with low impact in its security, by extending the features to Bitcoin (the currency) but providing the new functionality in a parallel blockchain, and therefore isolating the Bitcoin network from potential vulnerabilities in the sidechain. However, adding generic SPV sidechain integration to Bitcoin is complex and no generic proposal has been published. The only existing patch to Bitcoin[3] that enables SPV sidechains works only for blockchains which have a block and transaction structure similar to Bitcoin. In the particular case that the SPV sidechain is merge-mined, and there is high engagement in merge-mining, sidechains do not provide more security than a Drivechain.

A Drivechain is a system that has capabilities of establishing script conditions on signals provided onchain through mined blocks, where these signals represent the commands of the consensus systems on sidechains. We first define a Consensus Subordination System, as generic system that emits these signals, to make clear that this functionality may be applied to other scenarios.

Consensus Subordination System (CSS)

A Consensus Subordination System (CSS) is defined as an automated system that extracts commands generated by the consensus protocol of a sidechain and executes them in a mainchain. The sidechain consensus has authoritative responsibility for the commands. Once the command is created, it is fully authoritative and the CSS must obey [5]. The commands received can represent data to be stored in the mainchain: this data is embedded in some univocal part of a mainchain block. Generally this data represents a "signal". A CSS should not act basing on any other information external related to the data (such as identity). The data is generally opaque to the CSS. A CSS may also broadcast or include in a block a transactions on the mainchain by order of the sidechain node, but this does not differ from the functionality of any standard full node.

Miners generally do not know what they have been commanded, because the command may only contain a hash of the data. The CSS also communicates with a sidechain, and informs a sidechain node about the signals produced by other CSSs. A sidechain node may take actions based on this information, such as commanding the CSS to include in a block a transaction.

In this proposal we implement a CSS with also the capability of differentiate commands sources from different external consensus systems, and the capability to compress the signals by referring to previous signals with short prefixes, and also to signal the deliberate omission of previous signals.

Using CSSs to build a Drivechain

By adding a specific soft-fork rule to Bitcoin, a transaction can depend on the the number of signals sent by a CSSs, and the also the number of missing signals, during a multi-block interval. Generally such transaction would abort if a pre-defined threshold of signals is not reached, and therefore a transaction would be valid or invalid depending on previous block signals.

The signal-dependent behavior is implemented though a simple opcode. With it we can unlock funds that belong to a sidechain on request by the sidechain. In those cases the funds will be locked in one or more than one proxy addresses (sometimes called "Exodus" addresses) and a subset of the miners will run CSSs. A CSS creates a signal and a miner publish it by adding small data tag to blocks . There is only one type of tag, which is published by request of the CSS which in acts by an acknowledge (ACK) command from the sidechain. The number and distribution of ACKs can enable or disable a condition on a transaction. This the basis for a drivechain[4]. To differentiate this proposal from other drivechain proposals, we'll refer this proposal as the CountAcks drivechain or sidechain.

To ease understanding, from now on we'll use non-generic nomenclature, and focus on the drivechain use case. From now, a signal is a data tag which represents an acknowledge of a reference to a Release Transaction Candidate (RTC) by its ID. A non-signal is a negative-acknowledge of a RTC. The sidechain designer would create addresses containing a P2SH or P2WSH scriptPub so that an RTC trying to consume this input would be valid if the number of acknowledges is higher than a pre-defined threshold. The scriptSig of the RTC may require additional restrictions. The additional restrictions are out of the control of the described system, and therefore the sidechain must provide data that satisfies them, generally within the well-formed transaction. For instance, this could be additional signatures required by a CHECHMULTISIG.

Every now and then, a sidechain will emit a command to add an ACK for a Release Transaction Candidate (RTC). The CSS will compress this ACK: if the ACK for the same transaction has already been signaled in a certain blockchain interval, the CSS will request the miner to simply add a new compressed ACK tag. If it has not, the CSS will create a first ACK (called Proposal) that contains additional information to allow further compression. If a tag that references an RTC, is not a proposal itself, and doesn't have a prior proposal for the same ID, then it is an invalid tag, and it's ignored. Transparently, every proposal that is not ACKed is NACKed (negative acknowledge). NACK signals don't require space as they are not explicitly signaled.

CountAcks drivechain is based on a soft-fork that defines a NOP opcode as the OP_COUNT_ACKS opcode using the segwit script versioning system (e.g. version 1 scripts). This opcode scans pasts blocks of the blockchain, counting specific ACKS and NAKS, and push into the script stack the results. The opcode does not invalidate the transaction, but is the responsibility of the script to verify the output of the opcode and establish the necessary restrictions.

An ack-poll is the process which CSSs acknowledge the reception of a command authored by a sidechain consensus that mandates the release of funds for a certain transaction. The ack-poll will start with a proposal. The state of the ack-poll process is queried by transactions through a new OP_COUNT_ACKS opcode, although this opcode has now way to know the status of the ack-poll outside a certain interval of blocks. A query finds active ack-poll for an specific ID using a sliding-window approach, starting at a past block, scanning a certain amount of blocks and counting ACKS and NACKS. As counting only begins with the first proposal of a new ack-poll, ACKS prior a proposal will be ignored. At any time there can be zero or more active ack-polls for different transactions. After a pre-defined number of blocks, an ack-poll deactivates. Each ack-poll is associated with a Release Transaction Candidate and a specific sidechain. A transaction is considered a Release Transaction Candidate (RTC) while there is an active ack-poll that refers to it. At a certain block the conditions the RTC requires on the ack-poll query may be satisfied, but the RTC won't become immediately valid as there is a delay restrictions to include it. Therefore CSSs must continue the ack-poll of a RTC until the ack-poll period is over. When the ack-poll is over, CSSs will know if the RTC has been approved (i.e. by running in private the validation scripts, without the delay requirement). The RTC will become either an Approved Transaction (AT) or nothing at all. CSSs should not re-propose an Approved transaction. After the ack-poll is over, there may be a window of blocks where the Approved Transaction becomes valid for the network (this is the expected behavior but this may not be the case if the transaction is malformed or invalid by other script restrictions). The first block where the Approved Transaction becomes valid may not be mined by the miners performing the proxy custody of the related sidechain, so the RTC may be included in following block over the validity interval. Proxy custody miners should include in their blocks the approved and valid transactions they know about. Note that due to the sliding window nature of the ack-poll process, a poll can be re-opened before the approved transaction is included. This however does not affect the result of the first ack-poll, so it doesn't change the validity of the approved transaction. Miners must always try to acknowledge the RTCs they have been commanded to. The only reason why a miner may not acknowledge a RTC is due to lack of space to include the proper ack tag in a block, or due to an operative problem. However, there is no penalization as being part of the proxy custody set of any sidechain is optional. In case miners do not reach the threshold required to approve the transaction to be included in a block, a new ack-poll can be started for the same RTC. If a maximum period elapses and an approved transaction is not included in a block, the transaction is automatically invalidated and a new ack-poll must take place. To acknowledge one or more transaction candidates, miners embed the message tag “ACK:” followed by a serialized list of elements (the tag payload). Each element is itself a list of acks for a specific secondary blockchain.


The coinbase field of the transaction can contain the "ACK:" tag, following by a binary object of type FULL_ACK_LIST. The grammar of FULL_ACK_LIST is the following:

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 the payload), followed by the serialized items. A length of zero means there are 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 must be stored in the coinbase field of the coinbase transaction, after any other data that is part of the consensus protocol. 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 data that follows crosses the script field boundary (the first compact uint size is greater than the available space) then the whole tag is considered invalid and no data following the tag is processed. For any other Uint, crossing a field boundary only invalidates the sidechain (CHAIN_ACK_LIST) that the invalid UInt is contained in. This is to allow mining softwares to receive the full ack data in a serialized format from an external application, without the need to parse it. 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 sidechain_id cannot be repeated in a tag. If repeated, the CHAIN_ACK_LIST record of the second repeatition is ignored. Within the same CHAIN_ACK_LIST, the same proposal cannot be ack-ed twice (identified by the 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.

The identification of Release Transaction Candidates is based on transaction ID prefixes. This is to reduce the space consumed by acks.

  • sidechain_id is a 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 transaction referred by 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. The tx_hash_preimage field 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, as the RTC id can be dynamically computed as the SHA256 hash of tx_hash_prefix. This is to save space in the coinbase field.

Miners should choose a transaction prefix not to collide with a different RTC. The fist time a RTC is referenced in a tag is called the Proposal, the proposal must contain the tx_hash_preimage field. Other tags, even if not proposals, may also contain such field. Note that if the tx_hash_preimage is must be validated in consensus.

Note that the miner that acks a RTC indirectly pays an extra amount in fees because of the block space consumed by the tag (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 a RTC but including the sidechain_id means that all unreferenced active RTCs for that sidechain_id receive a negative ack. This is to prevent a DoS attack by a miners creating many ack-polls for unauthentic proposals. It's very cheap to NACK, but more expensive to ACK.

Example 1

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

1) ACK: {{ DRVCOIN {{{} 0x101010....10}}}}  
2) ACK: {{ DRVCOIN {{{} 0x202020....20}}}} 
3) ACK: {{ DRVCOIN {{{} 0x303030....30}}}} 
4) ACK: {{ YCOIN   {{{} 0x404040....40}}}} 
5) ACK: {{ XCOIN   {{{} 0x505050....50}}}} 


"...." means the repetition of the same pattern until completing 64 hex chars.

  1. 0x101010....10 is the pre-image of 0xbaa501b37267c06d8d20f316622f90a3e343e9e730771f2ce2e314b794e31853

  2. 0x202020....20 is the pre-image of 0x85e7eac2862f1cbd85bc18769c75172c3fdcd899ab468b9e973d59ec620d9991

  3. 0x303030....30 is the pre-image of 0x84e0c0eafaa95a34c293f278ac52e45ce537bab5e752a00e6959a13ae103b65a

  4. 0x404040....40 is the pre-image of 0x92b7eb5290d8d6e3ac79215cb4bdb07fe89629ee720be4332b3daa842b7ec80a

  5. 0x505050....50 is the pre-image of 0xb37361a0be8af8905de1f4384e701365ece4313dd5e064d375eb2851c043ba68

(First element is sidechain_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: { { DRVCHAIN {{0xba} {0x84e0}} } { XCHAIN {{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 YNET). 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 still he wants to ack a proposal that has known it has not been published before the last block, it should include the full ack transaction hash (32 bytes) plus the pre-image (32 bytes). Repeating the hash pre-image for a RTC is allowed. However miners must not include the pre-image if they are ack-ing for a pre-existent and known 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: {{DRVCHAIN {}}}).

There can be many active proposals for the same sidechain, and a miner can ack for many of them simultaneously adding more items to the 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 (first argument is the first pushed on stack):

  • poll_start_blocknum
  • sidechain_id
  • ack_period (in blocks)
  • delay_period (in blocks)
  • liveness_period (in blocks)

Description of arguments:

  • poll_start_blocknum is the block number where the poll starts. This must in range [N-12960-288,N-100], where N is the current block height.
  • sidechain_id is a blob that identifies the sidechain (e.g "PrivateBitcoin" for a sidechain 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..288].
  • delay_period represents the number of blocks after the ack_period that delay the beginning of the liveness_period. The valid delay_period range is [100..12960] (approximate maximum is 3 months). his range implies that the RTC cannot be included before 100 blocks after the ack-ing period ends. The 100 block forced delay 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.
  • liveness_period represents the number of blocks after the delay_period ends when the transaction specified by the proposal is valid. The valid Liveness_period range is [1..288].

OP_COUNT_ACKS performs four steps:

  1. Opcode arguments popped from stack. If not enough arguments are present, the transaction is aborted.
  2. Opcode arguments validation. Arguments are validated against pre-established bounds. if not in range, the script is aborted and the transaction is invalid.
  3. Ack counting.
  4. Push results in the stack.

If the first three steps are performed successfully, the last step pushes in the stack and following computed values:

  1. positive_acks
  2. negative_acks

Opcode arguments validation step

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):

  • poll_start_blocknum in [N-12960-288,N-100]. where N is the current block height
  • sidechain_id blob with length in [1..20]
  • ack_period (in blocks) integer in [1..max_ack_period]. max_ack_period is 288.
  • delay_period in [100..12960]
  • liveness_period (in blocks) integer in [1..max_liveness_period]. max_liveness_period is 288.
  • N-liveness_period-delay_periof-ack_period>=0 (there must be enough blocks for the poll)

Ack counting step

Let sidechain_id be the chain id that is being evaluated. Let ActivePolls be a vector containing (key,pos_acks,neg_acks) triples, where key is a blob specifying the transaction hash and ack value type is 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 (positive_acks,negative_acks):

Function Poll()
	Let poll_start :=n-liveness_period-ack_period
	For i :=poll_start to poll_start+ack_period-1 do
		C := GetCoinBaseFieldOfBlock(i)
		Find tag "ACK:" in C.
		if not (C contains valid "ACK:" tag and payload) then 
		Extract the FULL_ACK_LIST into L. Invalid CHAIN_ACK_LIST will be empty.
	If there is no index t so that (ActivePoll[t].key = spend_tx_hash) then return 0, and exit
    Let t be the first index where (ActivePoll[t].key = spend_tx_hash).
	Return (ActivePoll[t].pos_acks, ActivePoll[t].neg_acks) 

Function Process_FULL_ACK_LIST(L)
	For j :=0 to Length(L)-1 do
		if (L[j][0]=sidechain_id) then
			ack_list :=L[j][1]

Function Process_CHAIN_ACK_LIST(ack_list)
    new_acks :=[] // set of integers corresponding to acks indexes
	For k :=0 to Length(ack_list)-1 do
		ack :=ack_list[k]
		tx_hash :=ack[0]
		tx_hash_preimage :=ack[1]
		valid_NoProposal := (Length(tx_hash)<=32) AND (length(tx_hash_preimage)=0)
         valid_Proposal  :=  (Length(tx_hash)=32) AND 
         					(length(tx_hash_preimage)=32) AND
		valid := valid_Proposal OR valid_NoProposal  
		if (not valid)
		if not (tx_hash is a prefix of any key in ActivePolls) then
		For k :=0 to Length(ActivePolls)-1 do
			if (k in new_acks) then
Function NewPoll(tx_hash,in/out new_acks)
	if length(tx_hash_preimage)=32 then // new poll
		ActivePolls.Append(tx_hash,0) // tx_hash is key, 0 is initial ack count (dec later)
		lastPollIndex =Length(ActivePolls)-1

Function ExistingPoll(tx_hash,in/out new_acks)
		Let t be the first index in ActivePolls such as tx_hash is a prefix of ActivePolls[t].key

Ack de-serialization pseudo-code

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

ReadAcks(string s) -> (ACK_LIST)
	Let s be the coinbase field from the end of the "ACK:" string to the end of the field
	(r,t) :=ReadElement(s); 
	i :=0
	while(Length(s)>0) do
		(Li,r) :=ReadElement(r); // Li = { chainID { ... } }
		(chainId,t) :=ReadElement(Li) // t = { {v1 p1} {v2 p2}... }
		CHAIN_ACK_LIST :=new List()
		ACK_LIST  :=new List()
		(x,y) :=ReadElement(t) // x = {v1 p2} , {v2 p2} ...
		If (Length(y)>0) then raise exception
		j :=0
		While (Length(y)>0)
			(a,y) :=ReadElement(y) // v = {v1 p2} , y = {v2 p2} ...
			ACK :=new List()
			(a0,a) :=ReadElement(a)
			if (Length(a)>0) then
				(a1,a) :=ReadElement(a)
				if (length(a)>0) then raise exception

The transaction must be built such as the poll_start_blocknum is provided by the inputs consuming the locked funds. It is better if it is segregated (in the segwit stack) than being in the scriptSig. In any case it should not alter the transaction ID.


This example shows how the opcode works. For simplicity it uses non-standard scripts, although a realistic use case would use P2WSH. Let the blockchain have only the following tags (line format: block-number, tag):

101, ACK: {{ XCHAIN {{{} 0x101010....10}}}} // Proposal and ack 
102, ACK: {{ XCHAIN {{0xba}} }} // 2nd positive ack

... block 103..200 having the same tag as block 102, totaling 100 positive ACKs

201, ACK: {{ XCHAIN {{ }} }}  // negative ack

... block 201..225 having the same tag as block 201, totaling 25 NACKs. 

Where 0x101010....10 is the pre-image of 0xbaa501b37267c06d8d20f316622f90a3e343e9e730771f2ce2e314b794e31853

Let the script be executed on a transaction included in block 1101. Then the poll starts at block 101 and ends at block 244 (included).

	58 4e 45 54	("XNET")
	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	
scriptSig: 101


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.


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 occurs when a new block is added to the blockchain. The objective 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.

Incentive compatibility

The sidechain pays for every cycle of computation and space required by the Bitcoin blockchain, as every OP_COUNT_ACKS execution is associated with a single sidechain. Also an economic model for "blind drivechains" (similar to blind merge-mining), could be implemented.

No change in Bitcoin security model

By forcing the delay 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. Generally the delay period will be much higher (in the order of months), this gives time for the community to discuss and implement a soft-fork in the extreme case that miners attack a sidechain to steal its funds.

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 analyzed.

Last, each sidechain designers can choose between long pre-inclusion delays or long post-inclusion covenants, as the method to alert the involved parties in case of the appearance of malicious or erroneous tags in blocks.

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.


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 288 (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 288 recent generation transactions. The maximum amount of information that has to be fetched is 14.4K bytes. This cost assumes 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. However, the cache for a maximum delay of three months of blocks cannot grow over 1.3 Mbytes. The maximum cost in hashing of tx_hash_preimage values to obtain the corresponding tx_hash values is 864 hash digests, each of a message of size 32. This is comparable to the cost of a single signature verification. 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: (branch op-count-acks_devel)

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

  • The ack/liveness ranges have not been expanded from the previous release of the BIP.
  • The delay_ack argument has not yet been implemented.
  • Implement soft-fork threshold using VersionBitsState() in ConnectBlock()
  • Define witness script version 1 ( SIGVERSION_WITNESS_V1 = 2)
  • 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 ...


[6] The term "sidechain" is now used in generic form (see, so we will refer to the original sidechain definition as "SPV sidechain".


[3] The patch can be extracted from the Elements Sidechain project (


[5] It is certainly possible that owners of CSS are automatically punished economically by the sidechain if they don't act according to the commands, but the incentives should be carefully analyzed.