Skip to content

Commit e66148c

Browse files
committed
fix db getting corrupt on reorgs because of token data getting lost
1 parent 357dca4 commit e66148c

File tree

5 files changed

+70
-30
lines changed

5 files changed

+70
-30
lines changed

blockchain/chainio.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -666,16 +666,23 @@ func serializeUtxoEntry(entry *UtxoEntry) ([]byte, error) {
666666
return nil, err
667667
}
668668

669+
pkScript := entry.PkScript()
670+
if !entry.tokenData.IsEmpty() {
671+
buf := entry.tokenData.TokenDataBuffer()
672+
buf.Write(pkScript)
673+
pkScript = buf.Bytes()
674+
}
675+
669676
// Calculate the size needed to serialize the entry.
670677
size := serializeSizeVLQ(headerCode) +
671-
compressedTxOutSize(uint64(entry.Amount()), entry.PkScript())
678+
compressedTxOutSize(uint64(entry.Amount()), pkScript)
672679

673680
// Serialize the header code followed by the compressed unspent
674681
// transaction output.
675682
serialized := make([]byte, size)
676683
offset := putVLQ(serialized, headerCode)
677684
putCompressedTxOut(serialized[offset:], uint64(entry.Amount()),
678-
entry.PkScript())
685+
pkScript)
679686

680687
return serialized, nil
681688
}
@@ -710,6 +717,8 @@ func DeserializeUtxoEntry(serialized []byte) (*UtxoEntry, error) {
710717
blockHeight: blockHeight,
711718
packedFlags: 0,
712719
}
720+
entry.pkScript, _ = entry.tokenData.SeparateTokenDataFromPKScriptIfExists(entry.pkScript, 0)
721+
713722
if isCoinBase {
714723
entry.packedFlags |= tfCoinBase
715724
}
@@ -744,6 +753,7 @@ func deserializeUtxoCommitmentFormat(serialized []byte) (*wire.OutPoint, *UtxoEn
744753
pkScript: pkScript,
745754
packedFlags: 0,
746755
}
756+
entry.pkScript, _ = entry.tokenData.SeparateTokenDataFromPKScriptIfExists(entry.pkScript, 0)
747757
if coinbaseFlag > 0 {
748758
entry.packedFlags |= tfCoinBase
749759
}

blockchain/compress.go

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -253,9 +253,25 @@ func isPubKey(script []byte) (bool, []byte) {
253253
return false, nil
254254
}
255255

256+
// isCashTokensScript returns whether or not the script is a
257+
// cashtokens script along with the script itself if it is.
258+
// We can do better compression on this.
259+
func isCashTokensScript(script []byte) (bool, []byte) {
260+
if len(script) > 0 && script[0] == txscript.SPECIAL_TOKEN_PREFIX {
261+
return true, script
262+
}
263+
return false, nil
264+
}
265+
256266
// compressedScriptSize returns the number of bytes the passed script would take
257267
// when encoded with the domain specific compression algorithm described above.
258268
func compressedScriptSize(pkScript []byte) int {
269+
270+
if valid, _ := isCashTokensScript(pkScript); valid {
271+
return serializeSizeVLQ(uint64(len(pkScript)+numSpecialScripts)) +
272+
len(pkScript)
273+
}
274+
259275
// Pay-to-pubkey-hash script.
260276
if valid, _ := isPubKeyHash(pkScript); valid {
261277
return 21
@@ -311,34 +327,38 @@ func decodeCompressedScriptSize(serialized []byte) int {
311327
// handle the number of bytes returned by the compressedScriptSize function or
312328
// it will panic.
313329
func putCompressedScript(target, pkScript []byte) int {
314-
// Pay-to-pubkey-hash script.
315-
if valid, hash := isPubKeyHash(pkScript); valid {
316-
target[0] = cstPayToPubKeyHash
317-
copy(target[1:21], hash)
318-
return 21
319-
}
320330

321-
// Pay-to-script-hash script.
322-
if valid, hash := isScriptHash(pkScript); valid {
323-
target[0] = cstPayToScriptHash
324-
copy(target[1:21], hash)
325-
return 21
326-
}
331+
if valid, _ := isCashTokensScript(pkScript); !valid {
327332

328-
// Pay-to-pubkey (compressed or uncompressed) script.
329-
if valid, serializedPubKey := isPubKey(pkScript); valid {
330-
pubKeyFormat := serializedPubKey[0]
331-
switch pubKeyFormat {
332-
case 0x02, 0x03:
333-
target[0] = pubKeyFormat
334-
copy(target[1:33], serializedPubKey[1:33])
335-
return 33
336-
case 0x04:
337-
// Encode the oddness of the serialized pubkey into the
338-
// compressed script type.
339-
target[0] = pubKeyFormat | (serializedPubKey[64] & 0x01)
340-
copy(target[1:33], serializedPubKey[1:33])
341-
return 33
333+
// Pay-to-pubkey-hash script.
334+
if valid, hash := isPubKeyHash(pkScript); valid {
335+
target[0] = cstPayToPubKeyHash
336+
copy(target[1:21], hash)
337+
return 21
338+
}
339+
340+
// Pay-to-script-hash script.
341+
if valid, hash := isScriptHash(pkScript); valid {
342+
target[0] = cstPayToScriptHash
343+
copy(target[1:21], hash)
344+
return 21
345+
}
346+
347+
// Pay-to-pubkey (compressed or uncompressed) script.
348+
if valid, serializedPubKey := isPubKey(pkScript); valid {
349+
pubKeyFormat := serializedPubKey[0]
350+
switch pubKeyFormat {
351+
case 0x02, 0x03:
352+
target[0] = pubKeyFormat
353+
copy(target[1:33], serializedPubKey[1:33])
354+
return 33
355+
case 0x04:
356+
// Encode the oddness of the serialized pubkey into the
357+
// compressed script type.
358+
target[0] = pubKeyFormat | (serializedPubKey[64] & 0x01)
359+
copy(target[1:33], serializedPubKey[1:33])
360+
return 33
361+
}
342362
}
343363
}
344364

blockchain/upgrade.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,7 @@ func deserializeUtxoEntryV0(serialized []byte) (map[uint32]*UtxoEntry, error) {
428428
blockHeight: int32(blockHeight),
429429
packedFlags: packedFlags,
430430
}
431+
entries[outputIndex].pkScript, _ = entries[outputIndex].tokenData.SeparateTokenDataFromPKScriptIfExists(entries[outputIndex].pkScript, 0)
431432
}
432433

433434
return entries, nil

blockchain/utxocache.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ func NewUtxoEntry(txOut *wire.TxOut, blockHeight int32, isCoinbase bool) *UtxoEn
8888
if isCoinbase {
8989
cbFlag |= tfCoinBase
9090
}
91-
91+
txOut.PkScript, _ = txOut.TokenData.SeparateTokenDataFromPKScriptIfExists(txOut.PkScript, 0)
9292
return &UtxoEntry{
9393
amount: txOut.Value,
9494
pkScript: txOut.PkScript,

blockchain/utxoviewpoint.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ func (view *UtxoViewpoint) addTxOut(outpoint wire.OutPoint, txOut *wire.TxOut, i
8585
entry.amount = txOut.Value
8686
entry.pkScript = pkScript
8787
entry.blockHeight = blockHeight
88+
entry.pkScript, _ = entry.tokenData.SeparateTokenDataFromPKScriptIfExists(pkScript, 0)
8889
entry.packedFlags = tfModified
8990
if isCoinBase {
9091
entry.packedFlags |= tfCoinBase
@@ -185,6 +186,7 @@ func addTxOuts(view utxoView, tx *bchutil.Tx, blockHeight int32, overwrite bool)
185186
// Create a new entry from the output.
186187
pkScript := make([]byte, len(txOut.PkScript))
187188
copy(pkScript, txOut.PkScript)
189+
pkScript, _ = txOut.TokenData.SeparateTokenDataFromPKScriptIfExists(pkScript, 0)
188190

189191
entry := &UtxoEntry{
190192
amount: txOut.Value,
@@ -234,6 +236,12 @@ func spendTransactionInputs(view utxoView, tx *bchutil.Tx, stxos *[]SpentTxOut)
234236
pkScript := make([]byte, len(entry.PkScript()))
235237
copy(pkScript, entry.PkScript())
236238

239+
if !entry.tokenData.IsEmpty() {
240+
buf := entry.tokenData.TokenDataBuffer()
241+
buf.Write(pkScript)
242+
pkScript = buf.Bytes()
243+
}
244+
237245
// Populate the stxo details using the utxo entry.
238246
var stxo = SpentTxOut{
239247
Amount: entry.Amount(),
@@ -347,6 +355,7 @@ func disconnectTransactions(view utxoView, block *bchutil.Block, stxos []SpentTx
347355
blockHeight: stxo.Height,
348356
packedFlags: tfModified,
349357
}
358+
entry.pkScript, _ = entry.tokenData.SeparateTokenDataFromPKScriptIfExists(entry.pkScript, 0)
350359
if stxo.IsCoinBase {
351360
entry.packedFlags |= tfCoinBase
352361
}
@@ -388,7 +397,7 @@ func disconnectTransactions(view utxoView, block *bchutil.Block, stxos []SpentTx
388397

389398
pkScript := make([]byte, len(txOut.PkScript))
390399
copy(pkScript, txOut.PkScript)
391-
400+
pkScript, _ = txOut.TokenData.SeparateTokenDataFromPKScriptIfExists(pkScript, 0)
392401
// Mark the entry as spent. To make sure the view has the entry,
393402
// create one to pass along.
394403
entry := &UtxoEntry{

0 commit comments

Comments
 (0)