Browse Source

server: Support multiple inputs on transactions

scalafmt-draft
Alexis Hernandez 7 years ago
parent
commit
1b614d2807
  1. 14
      server/app/com/xsn/explorer/models/TransactionDetails.scala
  2. 3
      server/app/com/xsn/explorer/models/rpc/Transaction.scala
  3. 17
      server/app/com/xsn/explorer/models/rpc/TransactionVIN.scala
  4. 47
      server/app/com/xsn/explorer/services/TransactionService.scala
  5. 2
      server/app/com/xsn/explorer/services/logic/TransactionLogic.scala
  6. 27
      server/app/com/xsn/explorer/util/Extensions.scala
  7. 3
      server/test/com/xsn/explorer/services/XSNServiceRPCImplSpec.scala
  8. 61
      server/test/controllers/TransactionsControllerSpec.scala
  9. 182
      server/test/resources/transactions/a3c43d22bbba31a6e5c00f565cb9c5a1a365407df4cc90efa8a865656b52c0eb

14
server/app/com/xsn/explorer/models/TransactionDetails.scala

@ -10,11 +10,11 @@ case class TransactionDetails(
time: Long,
blocktime: Long,
confirmations: Confirmations,
input: Option[TransactionValue],
input: List[TransactionValue],
output: List[TransactionValue]) {
lazy val fee: BigDecimal = {
val vin = input.map(_.value).getOrElse(BigDecimal(0))
val vin = input.map(_.value).sum
val vout = output.map(_.value).sum
(vin - vout) max 0
}
@ -22,13 +22,7 @@ case class TransactionDetails(
object TransactionDetails {
def from(tx: Transaction, previous: Transaction): TransactionDetails = {
val input = tx.vin.flatMap { vin =>
val voutMaybe = previous.vout.find(_.n == vin.voutIndex)
voutMaybe.flatMap(TransactionValue.from)
}
def from(tx: Transaction, input: List[TransactionValue]): TransactionDetails = {
TransactionDetails
.from(tx)
.copy(input = input)
@ -37,7 +31,7 @@ object TransactionDetails {
def from(tx: Transaction): TransactionDetails = {
val output = tx.vout.flatMap(TransactionValue.from)
TransactionDetails(tx.id, tx.size, tx.blockhash, tx.time, tx.blocktime, tx.confirmations, None, output)
TransactionDetails(tx.id, tx.size, tx.blockhash, tx.time, tx.blocktime, tx.confirmations, List.empty, output)
}
implicit val writes: Writes[TransactionDetails] = Json.writes[TransactionDetails]

3
server/app/com/xsn/explorer/models/rpc/Transaction.scala

@ -11,7 +11,7 @@ case class Transaction(
time: Long,
blocktime: Long,
confirmations: Confirmations,
vin: Option[TransactionVIN],
vin: List[TransactionVIN],
vout: List[TransactionVOUT],
)
@ -28,7 +28,6 @@ object Transaction {
(__ \ 'vin).readNullable[List[JsValue]]
.map(_ getOrElse List.empty)
.map { list => list.flatMap(_.asOpt[TransactionVIN]) }
.map(_.headOption)
builder.apply { (id, size, blockHash, time, blockTime, confirmations, vout, vin) =>
Transaction(id, size, blockHash, time, blockTime, confirmations, vin, vout)

17
server/app/com/xsn/explorer/models/rpc/TransactionVIN.scala

@ -1,18 +1,25 @@
package com.xsn.explorer.models.rpc
import com.xsn.explorer.models.TransactionId
import com.xsn.explorer.models.{Address, TransactionId}
import play.api.libs.functional.syntax._
import play.api.libs.json.{Reads, __}
case class TransactionVIN(txid: TransactionId, voutIndex: Int)
case class TransactionVIN(
txid: TransactionId,
voutIndex: Int,
value: Option[BigDecimal],
address: Option[Address])
object TransactionVIN {
implicit val reads: Reads[TransactionVIN] = {
val builder = (__ \ 'txid).read[TransactionId] and (__ \ 'vout).read[Int]
val builder = (__ \ 'txid).read[TransactionId] and
(__ \ 'vout).read[Int] and
(__ \ 'value).readNullable[BigDecimal] and
(__ \ 'address).readNullable[Address]
builder.apply { (txid, index) =>
TransactionVIN(txid, index)
builder.apply { (txid, index, value, address) =>
TransactionVIN(txid, index, value, address)
}
}
}

47
server/app/com/xsn/explorer/services/TransactionService.scala

@ -4,8 +4,10 @@ import javax.inject.Inject
import com.alexitc.playsonify.core.FutureApplicationResult
import com.alexitc.playsonify.core.FutureOr.Implicits.{FutureOps, OrOps}
import com.xsn.explorer.errors.TransactionFormatError
import com.xsn.explorer.models.{TransactionDetails, TransactionId}
import com.xsn.explorer.errors.{TransactionFormatError, TransactionNotFoundError}
import com.xsn.explorer.models.rpc.TransactionVIN
import com.xsn.explorer.models.{TransactionDetails, TransactionId, TransactionValue}
import com.xsn.explorer.util.Extensions.FutureApplicationResultExt
import org.scalactic.{Good, One, Or}
import scala.concurrent.{ExecutionContext, Future}
@ -21,19 +23,40 @@ class TransactionService @Inject() (xsnService: XSNService)(implicit ec: Executi
transaction <- xsnService.getTransaction(txid).toFutureOr
previousMaybe <- transaction
input <- transaction
.vin
.map(_.txid)
.map(xsnService.getTransaction)
.map { f => f.toFutureOr.map(Option.apply).toFuture }
.getOrElse { Future.successful(Good(Option.empty))}
.map(getTransactionValue)
.toFutureOr
} yield {
previousMaybe
.map { previous => TransactionDetails.from(transaction, previous) }
.getOrElse { TransactionDetails.from(transaction) }
}
} yield TransactionDetails.from(transaction, input)
result.toFuture
}
private def getTransactionValue(vin: TransactionVIN): FutureApplicationResult[TransactionValue] = {
val valueMaybe = for {
value <- vin.value
address <- vin.address
} yield TransactionValue(address, value)
valueMaybe
.map(Good(_))
.map(Future.successful)
.getOrElse {
val txid = vin.txid
val result = for {
tx <- xsnService.getTransaction(txid).toFutureOr
r <- {
val maybe = tx
.vout
.find(_.n == vin.voutIndex)
.flatMap(TransactionValue.from)
Or.from(maybe, One(TransactionNotFoundError)).toFutureOr
}
} yield r
result.toFuture
}
}
}

2
server/app/com/xsn/explorer/services/logic/TransactionLogic.scala

@ -14,7 +14,7 @@ class TransactionLogic {
}
def getVIN(tx: Transaction, error: ApplicationError): ApplicationResult[TransactionVIN] = {
val maybe = tx.vin
val maybe = tx.vin.headOption
Or.from(maybe, One(error))
}

27
server/app/com/xsn/explorer/util/Extensions.scala

@ -1,5 +1,10 @@
package com.xsn.explorer.util
import com.alexitc.playsonify.core.{FutureApplicationResult, FutureOr}
import org.scalactic.{Bad, Good}
import scala.concurrent.{ExecutionContext, Future}
object Extensions {
private val SatoshiScale = 100000000L
@ -9,4 +14,26 @@ object Extensions {
inner / SatoshiScale
}
}
implicit class FutureApplicationResultExt[+A](val inner: List[FutureApplicationResult[A]]) extends AnyVal {
def toFutureOr(implicit ec: ExecutionContext): FutureOr[List[A]] = {
val futureList = Future.sequence(inner)
val future = futureList.map { resultList =>
val errorsMaybe = resultList
.flatMap(_.swap.toOption)
.reduceLeftOption(_ ++ _)
.map(_.distinct)
errorsMaybe
.map(Bad(_))
.getOrElse {
val valueList = resultList.flatMap(_.toOption)
Good(valueList)
}
}
new FutureOr(future)
}
}
}

3
server/test/com/xsn/explorer/services/XSNServiceRPCImplSpec.scala

@ -93,7 +93,8 @@ class XSNServiceRPCImplSpec extends WordSpec with MustMatchers with ScalaFutures
val tx = result.get
tx.id.string mustEqual txid.string
tx.vin.value.txid.string mustEqual "585cec5009c8ca19e83e33d282a6a8de65eb2ca007b54d6572167703768967d9"
tx.vin.size mustEqual 1
tx.vin.head.txid.string mustEqual "585cec5009c8ca19e83e33d282a6a8de65eb2ca007b54d6572167703768967d9"
tx.vout.size mustEqual 3
}
}

61
server/test/controllers/TransactionsControllerSpec.scala

@ -3,7 +3,7 @@ package controllers
import com.alexitc.playsonify.PublicErrorRenderer
import com.alexitc.playsonify.core.FutureApplicationResult
import com.xsn.explorer.errors.TransactionNotFoundError
import com.xsn.explorer.helpers.{DummyXSNService, TransactionLoader}
import com.xsn.explorer.helpers.{DataHelper, DummyXSNService, TransactionLoader}
import com.xsn.explorer.models._
import com.xsn.explorer.models.rpc.Transaction
import com.xsn.explorer.services.XSNService
@ -17,15 +17,19 @@ import scala.concurrent.Future
class TransactionsControllerSpec extends MyAPISpec {
import DataHelper._
val coinbaseTx = TransactionLoader.get("024aba1d535cfe5dd3ea465d46a828a57b00e1df012d7a2d158e0f7484173f7c")
val nonCoinbaseTx = TransactionLoader.get("0834641a7d30d8a2d2b451617599670445ee94ed7736e146c13be260c576c641")
val nonCoinbasePreviousTx = TransactionLoader.get("585cec5009c8ca19e83e33d282a6a8de65eb2ca007b54d6572167703768967d9")
val severalInputsTx = TransactionLoader.get("a3c43d22bbba31a6e5c00f565cb9c5a1a365407df4cc90efa8a865656b52c0eb")
val customXSNService = new DummyXSNService {
val map = Map(
coinbaseTx.id -> coinbaseTx,
nonCoinbaseTx.id -> nonCoinbaseTx,
nonCoinbasePreviousTx.id -> nonCoinbasePreviousTx
nonCoinbasePreviousTx.id -> nonCoinbasePreviousTx,
severalInputsTx.id -> severalInputsTx
)
override def getTransaction(txid: TransactionId): FutureApplicationResult[Transaction] = {
@ -69,7 +73,12 @@ class TransactionsControllerSpec extends MyAPISpec {
"return non-coinbase transaction" in {
val tx = nonCoinbaseTx
val details = TransactionDetails.from(nonCoinbaseTx, nonCoinbasePreviousTx)
val input = List(
TransactionValue(
createAddress("XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL"),
BigDecimal("2343749.965625"))
)
val details = TransactionDetails.from(nonCoinbaseTx, input)
val response = GET(url(tx.id.string))
status(response) mustEqual OK
@ -81,9 +90,12 @@ class TransactionsControllerSpec extends MyAPISpec {
(json \ "blocktime").as[Long] mustEqual tx.blocktime
(json \ "confirmations").as[Confirmations] mustEqual tx.confirmations
val inputJson = (json \ "input").as[JsValue]
(inputJson \ "address").as[String] mustEqual details.input.get.address.string
(inputJson \ "value").as[BigDecimal] mustEqual details.input.get.value
val inputJsonList = (json \ "input").as[List[JsValue]]
inputJsonList.size mustEqual 1
val inputJson = inputJsonList.head
(inputJson \ "address").as[String] mustEqual details.input.head.address.string
(inputJson \ "value").as[BigDecimal] mustEqual details.input.head.value
val outputJsonList = (json \ "output").as[List[JsValue]]
outputJsonList.size mustEqual 2
@ -97,6 +109,43 @@ class TransactionsControllerSpec extends MyAPISpec {
(outputJson2 \ "value").as[BigDecimal] mustEqual details.output.drop(1).head.value
}
"return a transaction with several inputs" in {
val tx = severalInputsTx
val inputValue = TransactionValue(
createAddress("XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL"),
BigDecimal("73242.18642578"))
val response = GET(url(tx.id.string))
status(response) mustEqual OK
val json = contentAsJson(response)
(json \ "id").as[String] mustEqual tx.id.string
(json \ "blockhash").as[String] mustEqual tx.blockhash.string
(json \ "size").as[Size] mustEqual tx.size
(json \ "time").as[Long] mustEqual tx.time
(json \ "blocktime").as[Long] mustEqual tx.blocktime
(json \ "confirmations").as[Confirmations] mustEqual tx.confirmations
val inputJsonList = (json \ "input").as[List[JsValue]]
inputJsonList.size mustEqual 11
inputJsonList.foreach { inputJson =>
(inputJson \ "address").as[String] mustEqual inputValue.address.string
(inputJson \ "value").as[BigDecimal] mustEqual inputValue.value
}
val outputJsonList = (json \ "output").as[List[JsValue]]
outputJsonList.size mustEqual 2
val outputJson = outputJsonList.head
(outputJson \ "address").as[String] mustEqual "XcmqLX4qptMgAigXTVH4SJRVb6ZKmq8rjH"
(outputJson \ "value").as[BigDecimal] mustEqual BigDecimal("55664.05066658")
val outputJson2 = outputJsonList.drop(1).head
(outputJson2 \ "address").as[String] mustEqual "XvUAd4vQtFtZ7v2Uo8e6aSsiRLAwyq1jwb"
(outputJson2 \ "value").as[BigDecimal] mustEqual BigDecimal("750000.00000000")
}
"fail on wrong transaction format" in {
// 63 characters
val txid = "000001d535cfe5dd3ea465d46a828a57b00e1df012d7a2d158e0f7484173f7c"

182
server/test/resources/transactions/a3c43d22bbba31a6e5c00f565cb9c5a1a365407df4cc90efa8a865656b52c0eb

@ -0,0 +1,182 @@
{
"hex": "010000000ba6ec9e87158b7f938fc0e5015b5bbd681ad52efeb69f45c6af35f85b7b0b0e10010000006a47304402202620392b295b252b159355b2bb57e73f50969b3e26faefadfb2d5050b475884b022072bd078824eb99337157e74d2112499b323c773fcb6935c520c03edb8e429d21012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1fefffffffe93099e481eb4af7309d3a21b41e1100c0fa37d2b73627e5591904b57d36113020000006a473044022074d7fb7e02b1f8a0c6eb427b0fa6d81996f3794ebfb897ac62a11b22ac350412022010e38899f61b22e0175d62aec9910d3c5ae85cb301a50b40f330b3fcac871133012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1feffffff4a35e69f21408809dd92c75f2ce3b9f25ac329bf853e906e58a4019d4d84e156010000006a47304402205c1a188aee5cbd94633eaec16561f1329e5cd52672a0a871197ea28f7302d45102201dcfaa74244c30a8350af971641542f006d7c9a5e8ba428eeacfbb1bdf8ed1ef012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1feffffff347bfc3e91604e4bda1217ed0b5816386bf2897e6de969d9f58d1dbf93965363010000006b483045022100c234c7fadaa4f89f96c8ac8126d29d8a44ee9eff2335111ac6cc5c43edb91c2a022014e1b3d8c33e1ed1af425690a3d711105256d672d9834a7f4d324cc3a85a481d012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1feffffff0cd69c1ad6437a2e7ffa940dbfc2771480a8341b4a0b930624f9e0eeb6ae4379020000006b483045022100c58ac3d28e2a715ce4e260a21478fe1a1fa93ae07ecc73563ceb09536a11ae3c02202534ef572cfccef865fa89be4bea7eef5494e88145758ebfbb8ad584b639069e012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1feffffff8d8af7a190c8b4161011ac358b7d512bbde95161d2c6579a4da47775ebc30d98010000006a47304402205259f762e5d85a5ce093b7990736cd3d36200653beaed9d6a51b51d7cecadb63022031ec68204320700ce7b180c289ef0cbb48eb7657a4c961e8b68241046dbbaec2012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1feffffffe53f8f0867dfe460193cd637318efd8561ad3b1eb64ede438be5667ff83acfa70200000069463043021f18674a8678f7083a355135a4fc4789b05e32c0b75ed1f7f14c2f2f98266bb8022020fbb3c7b89f8710d16aa8e643ae4c8b95a709e032b75917aa6e8de220667fe8012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1feffffffbabc509d23139cd2f95f1f52db8a41f6ca7de19df3b5bc8d04cb544c8c430eb2020000006a473044022074a0b736ed0daf39978040a75d7ff390be7e42c4f7903c03c401f37a96327b3f02202a4e58775a54520035ecdd361ec321340ce5876a64c76576182305e791604f8e012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1feffffff6c8c824db640dadf8064fca68ecc69e09b029b8579777b345f3ad7435f5a71bd020000006a47304402204f7182091a5e453105055e00857aca40f993d4f36dd5995c0eb3c0d72437d7e502200883c7a765582f91ba77d5c9ffd9f2d431cef5a21762c1ecc0c2aefa8c745c02012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1feffffff1a94f9e4cbe60afcfa68160369bd99ab7178d236f6ee02670fb21c7b03f81ada010000006a473044022047973e8d3ccf2bd83be3fb88bd6bb5e4c52cd121ea319d38ac04306b12cd99f302203755e0a757433954a35baaf7daf42630dd6147caa4a63a66eebe9cf79df7d75e012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1feffffff88718b1747d17d2119f58598dbcb4a86a7dd6534fb14245fe7e70ff137fa6ce6020000006b483045022100a1ee3436dd136fcc4ad78cb17120ec51fbae562cc0fc1864c1e67b0f0a0860a002204430e283fd4cd1fb4601558f6b46fdd4b4aa8d096b6623c369f07f5f39a05e98012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1feffffff02a2bf9807100500001976a91416e1eaf6643ce8947b03cf6b8cedb18af941b03888ac00b05b4c364400001976a914d8fccb0f4638a314e2248d99ed8b8531c63179eb88ace8780000",
"txid": "a3c43d22bbba31a6e5c00f565cb9c5a1a365407df4cc90efa8a865656b52c0eb",
"size": 1697,
"version": 1,
"locktime": 30952,
"vin": [
{
"txid": "100e0b7b5bf835afc6459fb6fe2ed51a68bd5b5b01e5c08f937f8b15879eeca6",
"vout": 1,
"scriptSig": {
"asm": "304402202620392b295b252b159355b2bb57e73f50969b3e26faefadfb2d5050b475884b022072bd078824eb99337157e74d2112499b323c773fcb6935c520c03edb8e429d21[ALL] 03624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1",
"hex": "47304402202620392b295b252b159355b2bb57e73f50969b3e26faefadfb2d5050b475884b022072bd078824eb99337157e74d2112499b323c773fcb6935c520c03edb8e429d21012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1"
},
"value": 73242.18642578,
"valueSat": 7324218642578,
"address": "XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL",
"sequence": 4294967294
},
{
"txid": "1361d3574b9091557e62732b7da30f0c10e1411ba2d30973afb41e489e0993fe",
"vout": 2,
"scriptSig": {
"asm": "3044022074d7fb7e02b1f8a0c6eb427b0fa6d81996f3794ebfb897ac62a11b22ac350412022010e38899f61b22e0175d62aec9910d3c5ae85cb301a50b40f330b3fcac871133[ALL] 03624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1",
"hex": "473044022074d7fb7e02b1f8a0c6eb427b0fa6d81996f3794ebfb897ac62a11b22ac350412022010e38899f61b22e0175d62aec9910d3c5ae85cb301a50b40f330b3fcac871133012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1"
},
"value": 73242.18642578,
"valueSat": 7324218642578,
"address": "XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL",
"sequence": 4294967294
},
{
"txid": "56e1844d9d01a4586e903e85bf29c35af2b9e32c5fc792dd098840219fe6354a",
"vout": 1,
"scriptSig": {
"asm": "304402205c1a188aee5cbd94633eaec16561f1329e5cd52672a0a871197ea28f7302d45102201dcfaa74244c30a8350af971641542f006d7c9a5e8ba428eeacfbb1bdf8ed1ef[ALL] 03624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1",
"hex": "47304402205c1a188aee5cbd94633eaec16561f1329e5cd52672a0a871197ea28f7302d45102201dcfaa74244c30a8350af971641542f006d7c9a5e8ba428eeacfbb1bdf8ed1ef012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1"
},
"value": 73242.18642578,
"valueSat": 7324218642578,
"address": "XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL",
"sequence": 4294967294
},
{
"txid": "63539693bf1d8df5d969e96d7e89f26b3816580bed1712da4b4e60913efc7b34",
"vout": 1,
"scriptSig": {
"asm": "3045022100c234c7fadaa4f89f96c8ac8126d29d8a44ee9eff2335111ac6cc5c43edb91c2a022014e1b3d8c33e1ed1af425690a3d711105256d672d9834a7f4d324cc3a85a481d[ALL] 03624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1",
"hex": "483045022100c234c7fadaa4f89f96c8ac8126d29d8a44ee9eff2335111ac6cc5c43edb91c2a022014e1b3d8c33e1ed1af425690a3d711105256d672d9834a7f4d324cc3a85a481d012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1"
},
"value": 73242.18642578,
"valueSat": 7324218642578,
"address": "XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL",
"sequence": 4294967294
},
{
"txid": "7943aeb6eee0f92406930b4a1b34a8801477c2bf0d94fa7f2e7a43d61a9cd60c",
"vout": 2,
"scriptSig": {
"asm": "3045022100c58ac3d28e2a715ce4e260a21478fe1a1fa93ae07ecc73563ceb09536a11ae3c02202534ef572cfccef865fa89be4bea7eef5494e88145758ebfbb8ad584b639069e[ALL] 03624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1",
"hex": "483045022100c58ac3d28e2a715ce4e260a21478fe1a1fa93ae07ecc73563ceb09536a11ae3c02202534ef572cfccef865fa89be4bea7eef5494e88145758ebfbb8ad584b639069e012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1"
},
"value": 73242.18642578,
"valueSat": 7324218642578,
"address": "XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL",
"sequence": 4294967294
},
{
"txid": "980dc3eb7577a44d9a57c6d26151e9bd2b517d8b35ac111016b4c890a1f78a8d",
"vout": 1,
"scriptSig": {
"asm": "304402205259f762e5d85a5ce093b7990736cd3d36200653beaed9d6a51b51d7cecadb63022031ec68204320700ce7b180c289ef0cbb48eb7657a4c961e8b68241046dbbaec2[ALL] 03624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1",
"hex": "47304402205259f762e5d85a5ce093b7990736cd3d36200653beaed9d6a51b51d7cecadb63022031ec68204320700ce7b180c289ef0cbb48eb7657a4c961e8b68241046dbbaec2012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1"
},
"value": 73242.18642578,
"valueSat": 7324218642578,
"address": "XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL",
"sequence": 4294967294
},
{
"txid": "a7cf3af87f66e58b43de4eb61e3bad6185fd8e3137d63c1960e4df67088f3fe5",
"vout": 2,
"scriptSig": {
"asm": "3043021f18674a8678f7083a355135a4fc4789b05e32c0b75ed1f7f14c2f2f98266bb8022020fbb3c7b89f8710d16aa8e643ae4c8b95a709e032b75917aa6e8de220667fe8[ALL] 03624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1",
"hex": "463043021f18674a8678f7083a355135a4fc4789b05e32c0b75ed1f7f14c2f2f98266bb8022020fbb3c7b89f8710d16aa8e643ae4c8b95a709e032b75917aa6e8de220667fe8012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1"
},
"value": 73242.18642578,
"valueSat": 7324218642578,
"address": "XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL",
"sequence": 4294967294
},
{
"txid": "b20e438c4c54cb048dbcb5f39de17dcaf6418adb521f5ff9d29c13239d50bcba",
"vout": 2,
"scriptSig": {
"asm": "3044022074a0b736ed0daf39978040a75d7ff390be7e42c4f7903c03c401f37a96327b3f02202a4e58775a54520035ecdd361ec321340ce5876a64c76576182305e791604f8e[ALL] 03624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1",
"hex": "473044022074a0b736ed0daf39978040a75d7ff390be7e42c4f7903c03c401f37a96327b3f02202a4e58775a54520035ecdd361ec321340ce5876a64c76576182305e791604f8e012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1"
},
"value": 73242.18642578,
"valueSat": 7324218642578,
"address": "XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL",
"sequence": 4294967294
},
{
"txid": "bd715a5f43d73a5f347b7779859b029be069cc8ea6fc6480dfda40b64d828c6c",
"vout": 2,
"scriptSig": {
"asm": "304402204f7182091a5e453105055e00857aca40f993d4f36dd5995c0eb3c0d72437d7e502200883c7a765582f91ba77d5c9ffd9f2d431cef5a21762c1ecc0c2aefa8c745c02[ALL] 03624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1",
"hex": "47304402204f7182091a5e453105055e00857aca40f993d4f36dd5995c0eb3c0d72437d7e502200883c7a765582f91ba77d5c9ffd9f2d431cef5a21762c1ecc0c2aefa8c745c02012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1"
},
"value": 73242.18642578,
"valueSat": 7324218642578,
"address": "XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL",
"sequence": 4294967294
},
{
"txid": "da1af8037b1cb20f6702eef636d27871ab99bd69031668fafc0ae6cbe4f9941a",
"vout": 1,
"scriptSig": {
"asm": "3044022047973e8d3ccf2bd83be3fb88bd6bb5e4c52cd121ea319d38ac04306b12cd99f302203755e0a757433954a35baaf7daf42630dd6147caa4a63a66eebe9cf79df7d75e[ALL] 03624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1",
"hex": "473044022047973e8d3ccf2bd83be3fb88bd6bb5e4c52cd121ea319d38ac04306b12cd99f302203755e0a757433954a35baaf7daf42630dd6147caa4a63a66eebe9cf79df7d75e012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1"
},
"value": 73242.18642578,
"valueSat": 7324218642578,
"address": "XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL",
"sequence": 4294967294
},
{
"txid": "e66cfa37f10fe7e75f2414fb3465dda7864acbdb9885f519217dd147178b7188",
"vout": 2,
"scriptSig": {
"asm": "3045022100a1ee3436dd136fcc4ad78cb17120ec51fbae562cc0fc1864c1e67b0f0a0860a002204430e283fd4cd1fb4601558f6b46fdd4b4aa8d096b6623c369f07f5f39a05e98[ALL] 03624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1",
"hex": "483045022100a1ee3436dd136fcc4ad78cb17120ec51fbae562cc0fc1864c1e67b0f0a0860a002204430e283fd4cd1fb4601558f6b46fdd4b4aa8d096b6623c369f07f5f39a05e98012103624fbfb0079e85bbc9aaeba6f48581326ad01194b3c54ce22852a27b1d2892d1"
},
"value": 73242.18642578,
"valueSat": 7324218642578,
"address": "XgEGH3y7RfeKEdn2hkYEvBnrnmGBr7zvjL",
"sequence": 4294967294
}
],
"vout": [
{
"value": 55664.05066658,
"valueSat": 5566405066658,
"n": 0,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 16e1eaf6643ce8947b03cf6b8cedb18af941b038 OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a91416e1eaf6643ce8947b03cf6b8cedb18af941b03888ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"XcmqLX4qptMgAigXTVH4SJRVb6ZKmq8rjH"
]
},
"spentTxId": "a645956bee96351d86d860ce71b793ab0aa4c2c0d2c1d687321beaca414313ea",
"spentIndex": 5,
"spentHeight": 33257
},
{
"value": 750000.00000000,
"valueSat": 75000000000000,
"n": 1,
"scriptPubKey": {
"asm": "OP_DUP OP_HASH160 d8fccb0f4638a314e2248d99ed8b8531c63179eb OP_EQUALVERIFY OP_CHECKSIG",
"hex": "76a914d8fccb0f4638a314e2248d99ed8b8531c63179eb88ac",
"reqSigs": 1,
"type": "pubkeyhash",
"addresses": [
"XvUAd4vQtFtZ7v2Uo8e6aSsiRLAwyq1jwb"
]
},
"spentTxId": "d840d65a9666fa0ed756ebea07c7256f318634df735ff1852ebb159c28e7d6c2",
"spentIndex": 0,
"spentHeight": 30958
}
],
"blockhash": "d91ae20bcab3074715cd401fa854c35d011a8f393323a7938baf687038b563a1",
"height": 30953,
"confirmations": 3093,
"time": 1522271123,
"blocktime": 1522271123
}
Loading…
Cancel
Save