Browse Source

server: Remove TPoS contract logic from the ScriptPubKey model

master
Alexis Hernandez 6 years ago
parent
commit
4af9a6cac4
  1. 11
      server/app/com/xsn/explorer/models/persisted/Transaction.scala
  2. 28
      server/app/com/xsn/explorer/models/rpc/ScriptPubKey.scala
  3. 8
      server/app/com/xsn/explorer/services/BlockService.scala
  4. 19
      server/app/com/xsn/explorer/services/logic/BlockLogic.scala
  5. 57
      server/test/com/xsn/explorer/models/rpc/ScriptPubKeySpec.scala
  6. 2
      server/test/resources/transactions/7f2b5f25b0ae24a417633e4214827f930a69802c1c43d1fb2ff7b7075b2d1701
  7. 2
      server/test/resources/transactions/99c51e4fe89466faa734d6207a7ef6115fa1dd33f7156b006fafc6bb85a79eb8

11
server/app/com/xsn/explorer/models/persisted/Transaction.scala

@ -63,12 +63,19 @@ object Transaction {
}
val outputs = tx.vout.flatMap { vout =>
val tposAddresses = vout.scriptPubKey.flatMap(_.getTPoSAddresses)
val contract = vout.scriptPubKey.flatMap(_.getTPoSContractDetails)
val scriptMaybe = vout.scriptPubKey.map(_.hex)
for {
address <- vout.address
script <- scriptMaybe
} yield Transaction.Output(tx.id, vout.n, vout.value, address, script, tposAddresses.map(_._1), tposAddresses.map(_._2))
} yield Transaction.Output(
tx.id,
vout.n,
vout.value,
address,
script,
tposOwnerAddress = contract.map(_.owner),
tposMerchantAddress = contract.map(_.merchant))
}
val transaction = Transaction(

28
server/app/com/xsn/explorer/models/rpc/ScriptPubKey.scala

@ -1,5 +1,6 @@
package com.xsn.explorer.models.rpc
import com.xsn.explorer.models.TPoSContract
import com.xsn.explorer.models.values.{Address, HexString}
import play.api.libs.functional.syntax._
import play.api.libs.json.{Reads, __}
@ -11,31 +12,10 @@ case class ScriptPubKey(
addresses: List[Address]) {
/**
* Parse addresses from a TPoS contract transaction.
*
* @return (owner address, merchant address)
* Get TPoS contract details if available
*/
def getTPoSAddresses: Option[(Address, Address)] = {
/**
* expected:
* - "asm": "OP_RETURN 5869337351664d51737932437a4d5a54726e4b573648464770315671465468644c77 58794a4338786e664672484e634d696e68366778755052595939484361593944416f 99"
*
* new format:
*- "asm": "OP_RETURN 586a55587938507a55464d78534c37594135767866574a587365746b354d5638676f 58794a4338786e664672484e634d696e68366778755052595939484361593944416f 99 1f60a6a385a4e5163ffef65dd873f17452bb0d9f89da701ffcc5a0f72287273c0571485c29123fef880d2d8169cfdb884bf95a18a0b36461517acda390ce4cf441"
*/
Option(asm)
.map(_ split " ")
.filter(_.size >= 4) // relax size check
.map(_.toList)
.flatMap {
case op :: owner :: merchant :: _ if op == "OP_RETURN" =>
for {
ownerAddress <- Address.fromHex(owner)
merchantAddress <- Address.fromHex(merchant)
} yield (ownerAddress, merchantAddress)
case _ => None
}
def getTPoSContractDetails: Option[TPoSContract.Details] = {
TPoSContract.Details.fromOutputScriptASM(asm)
}
}

8
server/app/com/xsn/explorer/services/BlockService.scala

@ -255,14 +255,12 @@ class BlockService @Inject() (
.getTransaction(tposTxId)
.toFutureOr
addresses <- blockLogic
.getTPoSAddresses(tposTx)
contract <- blockLogic
.getTPoSContractDetails(tposTx)
.toFutureOr
(ownerAddress, merchantAddress) = addresses
rewards <- blockLogic
.getTPoSRewards(coinstakeTx, ownerAddress, merchantAddress, coinstakeInput)
.getTPoSRewards(coinstakeTx, contract, coinstakeInput)
.toFutureOr
} yield rewards

19
server/app/com/xsn/explorer/services/logic/BlockLogic.scala

@ -45,11 +45,11 @@ class BlockLogic {
Or.from(maybe, One(BlockNotFoundError))
}
def getTPoSAddresses(tposContract: Transaction[_]): ApplicationResult[(Address, Address)] = {
def getTPoSContractDetails(tposContract: Transaction[_]): ApplicationResult[TPoSContract.Details] = {
val maybe = tposContract
.vout
.flatMap(_.scriptPubKey)
.flatMap(_.getTPoSAddresses)
.flatMap(_.getTPoSContractDetails)
.headOption
Or.from(maybe, One(BlockNotFoundError))
@ -107,8 +107,7 @@ class BlockLogic {
def getTPoSRewards(
coinstakeTx: Transaction[_],
owner: Address,
merchant: Address,
contract: TPoSContract.Details,
coinstakeInput: BigDecimal): ApplicationResult[TPoSBlockRewards] = {
/**
@ -123,22 +122,22 @@ class BlockLogic {
val coinstakeVOUT = coinstakeTx.vout
val ownerValue = coinstakeVOUT
.filter(_.address contains owner)
.filter(_.address contains contract.owner)
.map(_.value)
.sum
val ownerReward = BlockReward(
owner,
contract.owner,
(ownerValue - coinstakeInput) max 0)
// merchant
val merchantValue = coinstakeVOUT.filter(_.address contains merchant).map(_.value).sum
val merchantReward = BlockReward(merchant, merchantValue)
val merchantValue = coinstakeVOUT.filter(_.address contains contract.merchant).map(_.value).sum
val merchantReward = BlockReward(contract.merchant, merchantValue)
// master node
val masternodeRewardOUT = coinstakeVOUT.filterNot { out =>
out.address.contains(owner) ||
out.address.contains(merchant)
out.address.contains(contract.owner) ||
out.address.contains(contract.merchant)
}
val masternodeAddressMaybe = masternodeRewardOUT.flatMap(_.address).headOption
val masternodeRewardMaybe = masternodeAddressMaybe.map { masternodeAddress =>

57
server/test/com/xsn/explorer/models/rpc/ScriptPubKeySpec.scala

@ -1,57 +0,0 @@
package com.xsn.explorer.models.rpc
import com.xsn.explorer.models.values.{HexString, _}
import org.scalatest.{MustMatchers, OptionValues, WordSpec}
class ScriptPubKeySpec extends WordSpec with MustMatchers with OptionValues {
private val dummyScript = HexString.from("00").get
"getTPoSAddresses" should {
"parse the addresses" in {
val script = ScriptPubKey("nulldata", "OP_RETURN 5869337351664d51737932437a4d5a54726e4b573648464770315671465468644c77 58794a4338786e664672484e634d696e68366778755052595939484361593944416f 99", dummyScript, List.empty)
val expected = (
Address.from("Xi3sQfMQsy2CzMZTrnKW6HFGp1VqFThdLw").get,
Address.from("XyJC8xnfFrHNcMinh6gxuPRYY9HCaY9DAo").get)
val result = script.getTPoSAddresses
result.value mustEqual expected
}
"support more than 4 values if we have the addresses" in {
val script = ScriptPubKey("nulldata", "OP_RETURN 586a55587938507a55464d78534c37594135767866574a587365746b354d5638676f 58794a4338786e664672484e634d696e68366778755052595939484361593944416f 99 1f60a6a385a4e5163ffef65dd873f17452bb0d9f89da701ffcc5a0f72287273c0571485c29123fef880d2d8169cfdb884bf95a18a0b36461517acda390ce4cf441", dummyScript, List.empty)
val result = script.getTPoSAddresses
result.nonEmpty mustEqual true
}
"fail if OP_RETURN is not present" in {
val script = ScriptPubKey("nulldata", "OP_RTURN 5869337351664d51737932437a4d5a54726e4b573648464770315671465468644c77 58794a4338786e664672484e634d696e68366778755052595939484361593944416f 99", dummyScript, List.empty)
val result = script.getTPoSAddresses
result.isEmpty mustEqual true
}
"fail if the comission is missing" in {
val script = ScriptPubKey("nulldata", "OP_RETURN 5869337351664d51737932437a4d5a54726e4b573648464770315671465468644c77 58794a4338786e664672484e634d696e68366778755052595939484361593944416f ", dummyScript, List.empty)
val result = script.getTPoSAddresses
result.isEmpty mustEqual true
}
"fail if the owner address is malformed" in {
val script = ScriptPubKey("nulldata", "OP_RETURN 586933735164d51737932437a4d5a54726e4b573648464770315671465468644c77 58794a4338786e664672484e634d696e68366778755052595939484361593944416f 99", dummyScript, List.empty)
val result = script.getTPoSAddresses
result.isEmpty mustEqual true
}
"fail if the merchant address is malformed" in {
val script = ScriptPubKey("nulldata", "OP_RETURN 5869337351664d51737932437a4d5a54726e4b573648464770315671465468644c77 58794a4338786664672484e634d696e68366778755052595939484361593944416f 99", dummyScript, List.empty)
val result = script.getTPoSAddresses
result.isEmpty mustEqual true
}
}
}

2
server/test/resources/transactions/7f2b5f25b0ae24a417633e4214827f930a69802c1c43d1fb2ff7b7075b2d1701

@ -24,7 +24,7 @@
"valueSat": 0,
"n": 0,
"scriptPubKey": {
"asm": "OP_RETURN 5869337351664d51737932437a4d5a54726e4b573648464770315671465468644c77 58794a4338786e664672484e634d696e68366778755052595939484361593944416f 99",
"asm": "OP_RETURN 5869337351664d51737932437a4d5a54726e4b573648464770315671465468644c77 58794a4338786e664672484e634d696e68366778755052595939484361593944416f 99 ffaabbcc",
"hex": "6a225869337351664d51737932437a4d5a54726e4b573648464770315671465468644c772258794a4338786e664672484e634d696e68366778755052595939484361593944416f0163",
"type": "nulldata"
}

2
server/test/resources/transactions/99c51e4fe89466faa734d6207a7ef6115fa1dd33f7156b006fafc6bb85a79eb8

@ -24,7 +24,7 @@
"valueSat": 0,
"n": 0,
"scriptPubKey": {
"asm": "OP_RETURN 587535556b67524c385952716f57367545573853784d4c446b4a77626a4656666765 5862474670737568763641483367703364783565517241657850356b455368396259 99",
"asm": "OP_RETURN 587535556b67524c385952716f57367545573853784d4c446b4a77626a4656666765 5862474670737568763641483367703364783565517241657850356b455368396259 99 ffaabbcc",
"hex": "6a22587535556b67524c385952716f57367545573853784d4c446b4a77626a4656666765225862474670737568763641483367703364783565517241657850356b4553683962590163",
"type": "nulldata"
}

Loading…
Cancel
Save