16
16
17
17
package fr .acinq .eclair .blockchain .bitcoind
18
18
19
+ import akka .actor .ActorRef
19
20
import akka .actor .Status .Failure
20
21
import akka .pattern .pipe
21
- import akka .testkit .TestProbe
22
+ import akka .testkit .{ TestActor , TestProbe }
22
23
import fr .acinq .bitcoin
24
+ import fr .acinq .bitcoin .BlockHeader
23
25
import fr .acinq .bitcoin .scalacompat .Crypto .PublicKey
24
26
import fr .acinq .bitcoin .scalacompat .{Block , BtcDouble , ByteVector32 , MilliBtcDouble , OutPoint , Satoshi , SatoshiLong , Script , ScriptWitness , Transaction , TxIn , TxOut }
25
27
import fr .acinq .eclair .blockchain .OnChainWallet .{MakeFundingTxResponse , OnChainBalance }
26
28
import fr .acinq .eclair .blockchain .WatcherSpec .{createSpendManyP2WPKH , createSpendP2WPKH }
27
29
import fr .acinq .eclair .blockchain .bitcoind .BitcoindService .BitcoinReq
28
30
import fr .acinq .eclair .blockchain .bitcoind .rpc .BitcoinCoreClient ._
29
31
import fr .acinq .eclair .blockchain .bitcoind .rpc .BitcoinJsonRPCAuthMethod .UserPassword
30
- import fr .acinq .eclair .blockchain .bitcoind .rpc .{BasicBitcoinJsonRPCClient , BitcoinCoreClient , JsonRPCError }
32
+ import fr .acinq .eclair .blockchain .bitcoind .rpc .{BasicBitcoinJsonRPCClient , BitcoinCoreClient , BitcoinJsonRPCClient , JsonRPCError }
31
33
import fr .acinq .eclair .blockchain .fee .FeeratePerKw
32
34
import fr .acinq .eclair .transactions .{Scripts , Transactions }
33
35
import fr .acinq .eclair .{BlockHeight , TestConstants , TestKitBaseClass , addressToPublicKeyScript , randomKey }
@@ -806,4 +808,98 @@ class BitcoinCoreClientSpec extends TestKitBaseClass with BitcoindService with A
806
808
assert(addressToPublicKeyScript(address, Block .RegtestGenesisBlock .hash) == Script .pay2wpkh(receiveKey))
807
809
}
808
810
811
+ test(" get block header info" ) {
812
+ import fr .acinq .bitcoin .scalacompat .KotlinUtils ._
813
+ val sender = TestProbe ()
814
+ val bitcoinClient = new BitcoinCoreClient (bitcoinrpcclient)
815
+
816
+ bitcoinClient.getBlockHeight().pipeTo(sender.ref)
817
+ val height = sender.expectMsgType[BlockHeight ]
818
+ bitcoinClient.getBlockHash(height.toInt).pipeTo(sender.ref)
819
+ val lastBlockId = sender.expectMsgType[ByteVector32 ]
820
+ bitcoinClient.getBlockHeaderInfo(lastBlockId).pipeTo(sender.ref)
821
+ val lastBlockInfo = sender.expectMsgType[BlockHeaderInfo ]
822
+ assert(lastBlockInfo.nextBlockHash.isEmpty)
823
+
824
+ bitcoinClient.getBlockHash(height.toInt - 1 ).pipeTo(sender.ref)
825
+ val blockId = sender.expectMsgType[ByteVector32 ]
826
+ bitcoinClient.getBlockHeaderInfo(blockId).pipeTo(sender.ref)
827
+ val blockInfo = sender.expectMsgType[BlockHeaderInfo ]
828
+ assert(lastBlockInfo.header.hashPreviousBlock == blockInfo.header.hash)
829
+ assert(blockInfo.nextBlockHash.contains(kmp2scala(lastBlockInfo.header.hash)))
830
+ }
831
+
832
+ test(" get chains of block header infos" ) {
833
+ import fr .acinq .bitcoin .scalacompat .KotlinUtils ._
834
+ val sender = TestProbe ()
835
+ val bitcoinClient = new BitcoinCoreClient (bitcoinrpcclient)
836
+
837
+ def getHeaderInfos (height : Int , count : Int ): List [BlockHeaderInfo ] = {
838
+ bitcoinClient.getBlockHash(height).pipeTo(sender.ref)
839
+ val blockId = sender.expectMsgType[ByteVector32 ]
840
+ bitcoinClient.getBlockHeaderInfos(blockId, count).pipeTo(sender.ref)
841
+ sender.expectMsgType[List [BlockHeaderInfo ]]
842
+ }
843
+
844
+ def check (blockInfos : List [BlockHeaderInfo ]): Unit = {
845
+ for (i <- 0 until blockInfos.size - 1 ) {
846
+ require(blockInfos(i).nextBlockHash.contains(kmp2scala(blockInfos(i + 1 ).header.hash)))
847
+ require(blockInfos(i + 1 ).header.hashPreviousBlock == blockInfos(i).header.hash)
848
+ }
849
+ }
850
+
851
+ check(getHeaderInfos(140 , 5 ))
852
+ check(getHeaderInfos(146 , 5 ))
853
+ }
854
+
855
+ test(" get tx confirmation proof" ) {
856
+ val sender = TestProbe ()
857
+ val bitcoinClient = new BitcoinCoreClient (bitcoinrpcclient)
858
+
859
+ val address = getNewAddress(sender)
860
+ val tx1 = sendToAddress(address, 5 btc, sender)
861
+
862
+ bitcoinClient.getTxConfirmations(tx1.txid).pipeTo(sender.ref)
863
+ sender.expectMsg(Some (0 ))
864
+
865
+ bitcoinClient.checkTxConfirmations(tx1.txid, 1 ).pipeTo(sender.ref)
866
+ sender.expectMsgType[Failure ]
867
+
868
+ generateBlocks(3 )
869
+ bitcoinClient.getTxConfirmations(tx1.txid).pipeTo(sender.ref)
870
+ sender.expectMsg(Some (3 ))
871
+
872
+ bitcoinClient.checkTxConfirmations(tx1.txid, 3 ).pipeTo(sender.ref)
873
+ assert(sender.expectMsgType[Boolean ])
874
+ }
875
+
876
+ test(" verify tx confirmation proof" ) {
877
+ val sender = TestProbe ()
878
+ // this is a valid proof for a random tx on testnet
879
+ val validProof = " 0000c020d80e8834189edc6f67bb6683e0f1fc21608fb30f0c7148432b0000000000000078d01cf841039ee0d10e9e43cae12d54f08251fd96ac13688991a9af155f1c93b4f0d762f1da381903a82037140000000653f44c07bbd9acc8a9f9efa4ffaef176e0be7cfd7125b4985dc63b516191f81384d408a276c856d1816ffaf66f33dd17d4601a8e7c702ad98db859bd2c9d03ee2d982aad9cf8956835baa2011888a30a759548b3702b98c2266f4dd6a42b3dacefa0c54813f90ee2c7629f7600fcb782503c98a1df30368c568cc8c780c9d97b3c99c68fffea99cf505a02138e52df20e51c77e5784460f95bf3660f302b7046ceaa968b4e007fab9a717a9be9403ba5d866ec3ef81c5155e919aa27da49fa17025f00"
880
+ val bitcoinClient = new BitcoinCoreClient (new BitcoinJsonRPCClient {
881
+ override def invoke (method : String , params : Any * )(implicit ec : ExecutionContext ): Future [JValue ] = method match {
882
+ case " gettxoutproof" => Future .successful(new JString (validProof)) // bitcoin core is lying to us
883
+ case _ => bitcoinrpcclient.invoke(method, params : _* )(ec)
884
+ }
885
+ })
886
+
887
+ val address = getNewAddress(sender)
888
+ val tx1 = sendToAddress(address, 5 btc, sender)
889
+
890
+ bitcoinClient.getTxConfirmations(tx1.txid).pipeTo(sender.ref)
891
+ sender.expectMsg(Some (0 ))
892
+
893
+ bitcoinClient.checkTxConfirmations(tx1.txid, 1 ).pipeTo(sender.ref)
894
+ sender.expectMsgType[Failure ]
895
+
896
+ generateBlocks(3 )
897
+ bitcoinClient.getTxConfirmations(tx1.txid).pipeTo(sender.ref)
898
+ sender.expectMsg(Some (3 ))
899
+
900
+ bitcoinClient.checkTxConfirmations(tx1.txid, 3 ).pipeTo(sender.ref)
901
+ val failure = sender.expectMsgType[Failure ]
902
+ assert(failure.cause.getMessage.contains(s " cannot find inclusion proof for ${tx1.txid}" ))
903
+ }
904
+
809
905
}
0 commit comments