1
0
Fork 0
mirror of https://github.com/ACINQ/eclair.git synced 2025-02-22 14:22:39 +01:00

Electrum: do not persist transaction locks (#953)

Locks held on utxos that are used in unpublished funding transactions should not be persisted.
If the app is stopped before the funding transaction has been published the channel is forgotten
and so should be locks on its funding tx utxos.
This commit is contained in:
Fabrice Drouin 2019-04-17 19:10:14 +02:00 committed by GitHub
parent 9032da5326
commit 6afe28d147
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 63 additions and 36 deletions

View file

@ -211,7 +211,7 @@ object SqliteWalletDb {
("history" | historyCodec) ::
("proofs" | proofsCodec) ::
("pendingTransactions" | listOfN(uint16, txCodec)) ::
("locks" | setCodec(txCodec))).as[PersistentData]
("locks" | provide(Set.empty[Transaction]))).as[PersistentData]
def serialize(data: PersistentData): Array[Byte] = persistentDataCodec.encode(data).require.toByteArray

View file

@ -17,11 +17,16 @@
package fr.acinq.eclair.blockchain.electrum.db.sqlite
import fr.acinq.bitcoin.{Block, BlockHeader, OutPoint, Satoshi, Transaction, TxIn, TxOut}
import fr.acinq.eclair.TestConstants
import fr.acinq.eclair.{TestConstants, randomBytes, randomBytes32}
import fr.acinq.eclair.blockchain.electrum.ElectrumClient
import fr.acinq.eclair.blockchain.electrum.ElectrumClient.GetMerkleResponse
import fr.acinq.eclair.blockchain.electrum.ElectrumWallet.PersistentData
import fr.acinq.eclair.blockchain.electrum.db.sqlite.SqliteWalletDb.version
import fr.acinq.eclair.wire.ChannelCodecs.txCodec
import org.scalatest.FunSuite
import scodec.Codec
import scodec.bits.BitVector
import scodec.codecs.{constant, listOfN, provide, uint16}
import scala.util.Random
@ -34,34 +39,6 @@ class SqliteWalletDbSpec extends FunSuite {
if (acc.size == n) acc else makeHeaders(n, acc :+ makeChildHeader(acc.last))
}
test("add/get/list headers") {
val db = new SqliteWalletDb(TestConstants.sqliteInMemory())
val headers = makeHeaders(100)
db.addHeaders(2016, headers)
val headers1 = db.getHeaders(2016, None)
assert(headers1 === headers)
val headers2 = db.getHeaders(2016, Some(50))
assert(headers2 === headers.take(50))
var height = 2016
headers.foreach(header => {
val Some((height1, header1)) = db.getHeader(header.hash)
assert(height1 == height)
assert(header1 == header)
val Some(header2) = db.getHeader(height1)
assert(header2 == header)
height = height + 1
})
}
test("serialize persistent data") {
val db = new SqliteWalletDb(TestConstants.sqliteInMemory())
import fr.acinq.eclair.{randomBytes, randomBytes32}
def randomTransaction = Transaction(version = 2,
txIn = TxIn(OutPoint(randomBytes32, random.nextInt(100)), signatureScript = Nil, sequence = TxIn.SEQUENCE_FINAL) :: Nil,
txOut = TxOut(Satoshi(random.nextInt(10000000)), randomBytes(20)) :: Nil,
@ -92,13 +69,63 @@ class SqliteWalletDbSpec extends FunSuite {
)
}
test("add/get/list headers") {
val db = new SqliteWalletDb(TestConstants.sqliteInMemory())
val headers = makeHeaders(100)
db.addHeaders(2016, headers)
val headers1 = db.getHeaders(2016, None)
assert(headers1 === headers)
val headers2 = db.getHeaders(2016, Some(50))
assert(headers2 === headers.take(50))
var height = 2016
headers.foreach(header => {
val Some((height1, header1)) = db.getHeader(header.hash)
assert(height1 == height)
assert(header1 == header)
val Some(header2) = db.getHeader(height1)
assert(header2 == header)
height = height + 1
})
}
test("serialize persistent data") {
val db = new SqliteWalletDb(TestConstants.sqliteInMemory())
assert(db.readPersistentData() == None)
for (i <- 0 until 50) {
val data = randomPersistentData
db.persist(data)
val Some(check) = db.readPersistentData()
assert(check === data)
assert(check === data.copy(locks = Set.empty[Transaction]))
}
}
test("read old persistent data") {
import scodec.codecs._
import SqliteWalletDb._
import fr.acinq.eclair.wire.ChannelCodecs._
val oldPersistentDataCodec: Codec[PersistentData] = (
("version" | constant(BitVector.fromInt(version))) ::
("accountKeysCount" | int32) ::
("changeKeysCount" | int32) ::
("status" | statusCodec) ::
("transactions" | transactionsCodec) ::
("heights" | heightsCodec) ::
("history" | historyCodec) ::
("proofs" | proofsCodec) ::
("pendingTransactions" | listOfN(uint16, txCodec)) ::
("locks" | setCodec(txCodec))).as[PersistentData]
for (i <- 0 until 50) {
val data = randomPersistentData
val encoded = oldPersistentDataCodec.encode(data).require
val decoded = persistentDataCodec.decode(encoded).require.value
assert(decoded === data.copy(locks = Set.empty[Transaction]))
}
}
}