mirror of
https://github.com/bitcoin-s/bitcoin-s.git
synced 2024-11-19 01:40:55 +01:00
Support for big SPKs (#4084)
* Support for big SPKs * Support for big SPKs * Bump number of migrations * Fix other test case * cleanup * cleanup * fix psql migrations Co-authored-by: Chris Stewart <stewart.chris1234@gmail.com>
This commit is contained in:
parent
3931897e7f
commit
4d85b7a3d7
@ -2,8 +2,24 @@ package org.bitcoins.core.api.wallet.db
|
||||
|
||||
import org.bitcoins.core.api.db.DbRowAutoInc
|
||||
import org.bitcoins.core.protocol.script.ScriptPubKey
|
||||
import org.bitcoins.crypto.{CryptoUtil, Sha256Digest}
|
||||
|
||||
case class ScriptPubKeyDb(scriptPubKey: ScriptPubKey, id: Option[Long] = None)
|
||||
case class ScriptPubKeyDb(
|
||||
scriptPubKey: ScriptPubKey,
|
||||
hash: Sha256Digest,
|
||||
id: Option[Long] = None)
|
||||
extends DbRowAutoInc[ScriptPubKeyDb] {
|
||||
override def copyWithId(id: Long): ScriptPubKeyDb = copy(id = Option(id))
|
||||
}
|
||||
|
||||
object ScriptPubKeyDb {
|
||||
|
||||
def apply(scriptPubKey: ScriptPubKey): ScriptPubKeyDb =
|
||||
ScriptPubKeyDb(
|
||||
scriptPubKey = scriptPubKey,
|
||||
hash = hash(scriptPubKey)
|
||||
)
|
||||
|
||||
def hash(scriptPubKey: ScriptPubKey): Sha256Digest =
|
||||
CryptoUtil.sha256(scriptPubKey.bytes)
|
||||
}
|
||||
|
@ -106,13 +106,13 @@ class DbManagementTest extends BitcoinSAsyncTest with EmbeddedPg {
|
||||
val result = walletDbManagement.migrate()
|
||||
walletAppConfig.driver match {
|
||||
case SQLite =>
|
||||
val expected = 12
|
||||
val expected = 14
|
||||
assert(result == expected)
|
||||
val flywayInfo = walletDbManagement.info()
|
||||
assert(flywayInfo.applied().length == expected)
|
||||
assert(flywayInfo.pending().length == 0)
|
||||
case PostgreSQL =>
|
||||
val expected = 10
|
||||
val expected = 12
|
||||
assert(result == expected)
|
||||
val flywayInfo = walletDbManagement.info()
|
||||
|
||||
|
@ -6,6 +6,7 @@ import org.bitcoins.core.script.constant.ScriptNumber
|
||||
import org.bitcoins.core.script.reserved._
|
||||
import org.bitcoins.crypto.{DoubleSha256Digest, ECPublicKey}
|
||||
import org.bitcoins.testkit.fixtures.WalletDAOFixture
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
import java.sql.SQLException
|
||||
|
||||
@ -95,4 +96,41 @@ class ScriptPubKeyDAOTest extends WalletDAOFixture {
|
||||
assert(found.head.scriptPubKey == pkh)
|
||||
}
|
||||
}
|
||||
|
||||
it must "be able to store and find big spks" in { daos =>
|
||||
val scriptPubKeyDAO = daos.scriptPubKeyDAO
|
||||
|
||||
val Size = 840011 // the size of the biggest script on testnet
|
||||
|
||||
val big1 = RawScriptPubKey.fromAsmBytes(ByteVector.fill(Size)(0x55))
|
||||
assert(big1.bytes.size == Size + 5)
|
||||
|
||||
val big2 = RawScriptPubKey.fromAsmBytes(ByteVector.fill(Size * 2)(0xaa))
|
||||
assert(big2.bytes.size == Size * 2 + 5)
|
||||
|
||||
val multisig = MultiSignatureScriptPubKey(
|
||||
2,
|
||||
Vector(ECPublicKey.freshPublicKey, ECPublicKey.freshPublicKey))
|
||||
|
||||
val pkh = P2PKHScriptPubKey(ECPublicKey.freshPublicKey)
|
||||
|
||||
val spks = Vector(
|
||||
EmptyScriptPubKey,
|
||||
pkh,
|
||||
big1,
|
||||
multisig,
|
||||
big2
|
||||
).map(spk => ScriptPubKeyDb(spk))
|
||||
|
||||
for {
|
||||
_ <- scriptPubKeyDAO.createAll(spks)
|
||||
fromDb <- scriptPubKeyDAO.findAll()
|
||||
fromDb1 <- scriptPubKeyDAO.findScriptPubKeys(fromDb.map(_.scriptPubKey))
|
||||
} yield {
|
||||
assert(fromDb.sortBy(_.id) == fromDb1.sortBy(_.id))
|
||||
val actual = fromDb1.sortBy(_.id)
|
||||
assert(actual.size == spks.size)
|
||||
assert(actual.map(_.scriptPubKey) == spks.map(_.scriptPubKey))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,5 @@
|
||||
ALTER TABLE pub_key_scripts ADD COLUMN hash VARCHAR(64);
|
||||
|
||||
ALTER TABLE pub_key_scripts DROP CONSTRAINT pub_key_scripts_script_pub_key_key;
|
||||
|
||||
CREATE UNIQUE INDEX pub_key_scripts_hash_idx ON pub_key_scripts(hash);
|
@ -0,0 +1,3 @@
|
||||
ALTER TABLE "pub_key_scripts" ADD COLUMN hash VARCHAR(64);
|
||||
|
||||
CREATE UNIQUE INDEX "pub_key_scripts_hash_idx" ON "pub_key_scripts"(hash);
|
@ -107,8 +107,7 @@ private[wallet] trait AddressHandling extends WalletLogger {
|
||||
|
||||
override def watchScriptPubKey(
|
||||
scriptPubKey: ScriptPubKey): Future[ScriptPubKeyDb] =
|
||||
scriptPubKeyDAO.createIfNotExists(
|
||||
ScriptPubKeyDb(scriptPubKey = scriptPubKey))
|
||||
scriptPubKeyDAO.createIfNotExists(ScriptPubKeyDb(scriptPubKey))
|
||||
|
||||
/** Enumerates the public keys in this wallet */
|
||||
protected[wallet] def listPubkeys(): Future[Vector[ECPublicKey]] =
|
||||
|
@ -3,6 +3,7 @@ package org.bitcoins.wallet.models
|
||||
import org.bitcoins.core.api.wallet.db.ScriptPubKeyDb
|
||||
import org.bitcoins.core.protocol.script.ScriptPubKey
|
||||
import org.bitcoins.core.script.ScriptType
|
||||
import org.bitcoins.crypto.Sha256Digest
|
||||
import org.bitcoins.db.CRUDAutoInc
|
||||
import org.bitcoins.wallet.config.WalletAppConfig
|
||||
import slick.dbio.DBIOAction
|
||||
@ -50,7 +51,8 @@ case class ScriptPubKeyDAO()(implicit
|
||||
/** Searches for the given set of spks and returns the ones that exist in the db */
|
||||
def findScriptPubKeys(
|
||||
spks: Vector[ScriptPubKey]): Future[Vector[ScriptPubKeyDb]] = {
|
||||
val query = table.filter(_.scriptPubKey.inSet(spks))
|
||||
val hashes = spks.map(ScriptPubKeyDb.hash)
|
||||
val query = table.filter(_.hash.inSet(hashes))
|
||||
safeDatabase.runVec(query.result)
|
||||
}
|
||||
|
||||
@ -58,17 +60,20 @@ case class ScriptPubKeyDAO()(implicit
|
||||
extends TableAutoInc[ScriptPubKeyDb](tag, schemaName, "pub_key_scripts") {
|
||||
|
||||
def scriptPubKey: Rep[ScriptPubKey] = column("script_pub_key")
|
||||
|
||||
def scriptType: Rep[ScriptType] = column("script_type")
|
||||
|
||||
private type ScriptPubKeyTuple = (Option[Long], ScriptPubKey, ScriptType)
|
||||
def hash: Rep[Sha256Digest] = column("hash")
|
||||
|
||||
private type ScriptPubKeyTuple =
|
||||
(Option[Long], ScriptPubKey, ScriptType, Sha256Digest)
|
||||
|
||||
private val fromTuple: ScriptPubKeyTuple => ScriptPubKeyDb = {
|
||||
case (id, scriptPubKey, scriptType) =>
|
||||
case (id, scriptPubKey, scriptType, hash) =>
|
||||
require(
|
||||
scriptPubKey.scriptType == scriptType,
|
||||
s"script type must match it script: `${scriptPubKey.scriptType}` != `${scriptType}` ")
|
||||
ScriptPubKeyDb(scriptPubKey, id)
|
||||
|
||||
ScriptPubKeyDb(scriptPubKey, hash, id)
|
||||
}
|
||||
|
||||
private val toTuple: ScriptPubKeyDb => Option[ScriptPubKeyTuple] = {
|
||||
@ -76,11 +81,12 @@ case class ScriptPubKeyDAO()(implicit
|
||||
Some(
|
||||
(scriptPubKeyDb.id,
|
||||
scriptPubKeyDb.scriptPubKey,
|
||||
scriptPubKeyDb.scriptPubKey.scriptType))
|
||||
scriptPubKeyDb.scriptPubKey.scriptType,
|
||||
scriptPubKeyDb.hash))
|
||||
}
|
||||
|
||||
override def * =
|
||||
(id.?, scriptPubKey, scriptType).<>(fromTuple, toTuple)
|
||||
(id.?, scriptPubKey, scriptType, hash).<>(fromTuple, toTuple)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
package postgresql.wallet.migration
|
||||
|
||||
import org.bitcoins.core.api.wallet.db.ScriptPubKeyDb
|
||||
import org.bitcoins.core.protocol.script.ScriptPubKey
|
||||
import org.flywaydb.core.api.migration.{BaseJavaMigration, Context}
|
||||
|
||||
class V15__compute_spk_hashes extends BaseJavaMigration {
|
||||
|
||||
override def migrate(context: Context): Unit = {
|
||||
val selectStatement = context.getConnection.createStatement()
|
||||
try {
|
||||
val rows = selectStatement.executeQuery(
|
||||
"SELECT id, script_pub_key FROM pub_key_scripts")
|
||||
while (rows.next()) {
|
||||
val id = rows.getLong(1)
|
||||
val hex = rows.getString(2)
|
||||
val spk = ScriptPubKey(hex)
|
||||
val hash = ScriptPubKeyDb.hash(spk)
|
||||
val updateStatement = context.getConnection.prepareStatement(
|
||||
"UPDATE pub_key_scripts SET hash=? WHERE id=?")
|
||||
updateStatement.setString(1, hash.hex)
|
||||
updateStatement.setLong(2, id)
|
||||
try {
|
||||
updateStatement.executeUpdate()
|
||||
} finally updateStatement.close()
|
||||
}
|
||||
} finally selectStatement.close()
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package sqlite.wallet.migration
|
||||
|
||||
import org.bitcoins.core.api.wallet.db.ScriptPubKeyDb
|
||||
import org.bitcoins.core.protocol.script.ScriptPubKey
|
||||
import org.flywaydb.core.api.migration.{BaseJavaMigration, Context}
|
||||
|
||||
class V14__compute_spk_hashes extends BaseJavaMigration {
|
||||
|
||||
override def migrate(context: Context): Unit = {
|
||||
val selectStatement = context.getConnection.createStatement()
|
||||
try {
|
||||
val rows = selectStatement.executeQuery(
|
||||
"SELECT id, script_pub_key FROM pub_key_scripts")
|
||||
while (rows.next()) {
|
||||
val id = rows.getLong(1)
|
||||
val hex = rows.getString(2)
|
||||
val spk = ScriptPubKey(hex)
|
||||
val hash = ScriptPubKeyDb.hash(spk)
|
||||
val updateStatement = context.getConnection.prepareStatement(
|
||||
"UPDATE pub_key_scripts SET hash=? WHERE id=?")
|
||||
updateStatement.setString(1, hash.hex)
|
||||
updateStatement.setLong(2, id)
|
||||
try {
|
||||
updateStatement.executeUpdate()
|
||||
} finally updateStatement.close()
|
||||
}
|
||||
} finally selectStatement.close()
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user