diff --git a/interpreter/shared/src/main/scala/org/ergoplatform/ErgoAddress.scala b/interpreter/shared/src/main/scala/org/ergoplatform/ErgoAddress.scala index 483a0c1dde..5813ff99e7 100644 --- a/interpreter/shared/src/main/scala/org/ergoplatform/ErgoAddress.scala +++ b/interpreter/shared/src/main/scala/org/ergoplatform/ErgoAddress.scala @@ -2,11 +2,11 @@ package org.ergoplatform import scorex.utils.Ints import org.ergoplatform.ErgoAddressEncoder.NetworkPrefix -import scorex.crypto.hash.{Digest32, Blake2b256} +import scorex.crypto.hash.{Blake2b256, Digest32} import scorex.util.encode.Base58 import sigmastate.Values._ import sigmastate._ -import sigmastate.crypto.DLogProtocol.{ProveDlogProp, ProveDlog} +import sigmastate.crypto.DLogProtocol.{ProveDlog, ProveDlogProp} import sigmastate.exceptions.SigmaException import sigmastate.serialization._ import sigmastate.utxo.{DeserializeContext, Slice} @@ -128,7 +128,9 @@ object P2PKAddress { } } -/** Implementation of pay-to-script-hash [[ErgoAddress]]. */ +/** Implementation of pay-to-script-hash [[ErgoAddress]]. + * @param scriptHash first 192 bits of the Blake2b256 hash of serialized script bytes + */ class Pay2SHAddress(val scriptHash: Array[Byte])(implicit val encoder: ErgoAddressEncoder) extends ErgoAddress { override val addressTypePrefix: Byte = Pay2SHAddress.addressTypePrefix @@ -141,12 +143,12 @@ class Pay2SHAddress(val scriptHash: Array[Byte])(implicit val encoder: ErgoAddre /** The proposition which checks that `contextVar(scriptId)` has original script * (whose hash equals to this [[scriptHash]]) which evaluates to true. * - * Assumes the context variable is accessed as `getVar[Coll[Byte]](1).get` + * Assumes the context variable is accessed as `getVar[Coll[Byte]](126).get` * and contains serialized original script bytes. * - * NOTE: This script is not stored in [[contentBytes]] of the address. + * NOTE: This `script` field is not stored in [[contentBytes]] of the address. * So the address doesn't depend on this script which means this specific script can be - * changed without breaking the addresses. + * changed without breaking the existing p2sh addresses. * * NOTE: The ErgoTree is created without segregation of the constants. * @@ -158,7 +160,7 @@ class Pay2SHAddress(val scriptHash: Array[Byte])(implicit val encoder: ErgoAddre override val script = { val hashEquals = EQ( Slice(CalcBlake2b256(GetVarByteArray(scriptId).get), IntConstant(0), IntConstant(24)), - scriptHash + ByteArrayConstant(scriptHash) ) val scriptIsCorrect = DeserializeContext(scriptId, SSigmaProp) ErgoTree.withoutSegregation(SigmaAnd(hashEquals.toSigmaProp, scriptIsCorrect)) @@ -176,9 +178,10 @@ class Pay2SHAddress(val scriptHash: Array[Byte])(implicit val encoder: ErgoAddre object Pay2SHAddress { /** An id of the context variable used in pay-to-script-hash address script. + * Note, value 127 is used for strage rent in Ergo node, see org.ergoplatform.wallet.interpreter.ErgoInterpreter * @see [[Pay2SHAddress.script]] */ - val scriptId = 1: Byte + val scriptId = 126: Byte /** Value added to the prefix byte in the serialized bytes of an encoded P2SH address. * @see [[ErgoAddressEncoder.toString]] @@ -300,7 +303,7 @@ case class ErgoAddressEncoder(networkPrefix: NetworkPrefix) { new P2PKAddress(ProveDlog(p), contentBytes) case Pay2SHAddress.addressTypePrefix => if (contentBytes.length != 24) { //192-bits hash used - throw new Exception(s"Improper content in P2SH script: $addrBase58Str") + throw new Exception(s"Invalid length of the hash bytes in P2SH address: $addrBase58Str") } new Pay2SHAddress(contentBytes) case Pay2SAddress.addressTypePrefix => @@ -328,7 +331,8 @@ case class ErgoAddressEncoder(networkPrefix: NetworkPrefix) { } /** Converts the given [[ErgoTree]] to the corresponding [[ErgoAddress]]. - * It is inverse of [[ErgoAddress.script]] such that `fromProposition(addr.script) == addr` + * It is inverse of [[ErgoAddress.script]] such that + * `ErgoAddressEncoder.fromProposition(addr.script) == addr` * * @return Failure(ex) if the `proposition` cannot be converted to any type of address. */ diff --git a/sc/shared/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala b/sc/shared/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala index b4153ff4f2..73156ca1b8 100644 --- a/sc/shared/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala +++ b/sc/shared/src/test/scala/org/ergoplatform/ErgoAddressSpecification.scala @@ -170,7 +170,7 @@ class ErgoAddressSpecification extends SigmaDslTesting assertExceptionThrown( ergoAddressEncoder.fromString(addrStr).getOrThrow, - t => t.getMessage.contains("Improper content in P2SH script: 41fKjb7zWNw") + t => t.getMessage.contains("Invalid length of the hash bytes in P2SH address: 41fKjb7zWNw") ) } @@ -228,7 +228,7 @@ class ErgoAddressSpecification extends SigmaDslTesting } def testPay2SHAddress(address: Pay2SHAddress, scriptBytes: Array[Byte]) = { - val scriptId = 1.toByte + val scriptId = Pay2SHAddress.scriptId val boxToSpend = testBox(10, address.script, creationHeight = 5) val ctx = ErgoLikeContextTesting.dummy(boxToSpend, activatedVersionInTests) .withExtension(ContextExtension(Seq( @@ -271,7 +271,7 @@ class ErgoAddressSpecification extends SigmaDslTesting res } - val scriptVarId = 1.toByte + val scriptVarId = Pay2SHAddress.scriptId val script = "{ 1 < 2 }" val prop = compile(Map.empty, script).asBoolValue.toSigmaProp val scriptBytes = ValueSerializer.serialize(prop)