scodec.bits.ByteVector Scala Examples

The following examples show how to use scodec.bits.ByteVector. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example.
Example 1
Source File: ByteVectorBytes.scala    From swave   with Mozilla Public License 2.0 5 votes vote down vote up
package swave.compat.scodec.impl

import java.io.OutputStream
import java.nio.ByteBuffer
import java.nio.charset.{CharacterCodingException, Charset}
import scala.collection.GenTraversableOnce
import scodec.bits.ByteVector
import swave.core.io.Bytes

class ByteVectorBytes extends Bytes[ByteVector] {

  ///////////////// CONSTRUCTION ///////////////////

  def empty                                               = ByteVector.empty
  def fill[A: Integral](size: Long)(byte: A)              = ByteVector.fill(size)(byte)
  def apply(array: Array[Byte])                           = ByteVector(array)
  def apply(bytes: Array[Byte], offset: Int, length: Int) = ByteVector(bytes, offset, length)
  def apply[A: Integral](bytes: A*)                       = ByteVector(bytes: _*)
  def apply(bytes: Vector[Byte])                          = ByteVector(bytes)
  def apply(buffer: ByteBuffer)                           = ByteVector(buffer)
  def apply(bs: GenTraversableOnce[Byte])                 = ByteVector(bs)
  def view(bytes: Array[Byte])                            = ByteVector(bytes)
  def view(bytes: ByteBuffer)                             = ByteVector(bytes)
  def encodeString(str: String, charset: Charset)         = if (str.isEmpty) empty else ByteVector(str getBytes charset)
  def encodeStringStrict(str: String, charset: Charset)   = ByteVector.encodeString(str)(charset)

  ///////////////// QUERY ///////////////////

  def size(value: ByteVector)                                           = value.size
  def byteAt(value: ByteVector, ix: Long)                               = value(ix)
  def indexOfSlice(value: ByteVector, slice: ByteVector, startIx: Long) = value.indexOfSlice(slice, startIx)

  ///////////////// TRANSFORMATION TO ByteVector ///////////////////

  def update(value: ByteVector, ix: Long, byte: Byte) = value.update(ix, byte)
  def concat(value: ByteVector, other: ByteVector)    = value ++ other
  def concat(value: ByteVector, byte: Byte)           = value :+ byte
  def concat(byte: Byte, value: ByteVector)           = byte +: value
  def drop(value: ByteVector, n: Long)                = value.drop(n)
  def take(value: ByteVector, n: Long)                = value.take(n)
  def map(value: ByteVector, f: Byte ⇒ Byte)          = value.map(f)
  def reverse(value: ByteVector)                      = value.reverse
  def compact(value: ByteVector)                      = value.compact

  ///////////////// TRANSFORMATION TO OTHER TYPES ///////////////////

  def toArray(value: ByteVector)                                   = value.toArray
  def copyToArray(value: ByteVector, xs: Array[Byte], offset: Int) = value.copyToArray(xs, offset)
  def copyToArray(value: ByteVector, sourceOffset: Long, xs: Array[Byte], destOffset: Int, len: Int) =
    value.copyToArray(xs, destOffset, sourceOffset, len)
  def copyToBuffer(value: ByteVector, buffer: ByteBuffer): Int = value.copyToBuffer(buffer)
  def copyToOutputStream(value: ByteVector, s: OutputStream)   = value.copyToStream(s)
  def toByteBuffer(value: ByteVector)                          = value.toByteBuffer
  def toIndexedSeq(value: ByteVector): IndexedSeq[Byte]        = value.toIndexedSeq
  def toSeq(value: ByteVector): Seq[Byte]                      = value.toSeq
  def decodeString(value: ByteVector, charset: Charset): Either[CharacterCodingException, String] =
    value.decodeString(charset)

  ///////////////// ITERATION ///////////////////

  def foldLeft[A](value: ByteVector, z: A, f: (A, Byte) ⇒ A)  = value.foldLeft(z)(f)
  def foldRight[A](value: ByteVector, z: A, f: (Byte, A) ⇒ A) = value.foldRight(z)(f)
  def foreach(value: ByteVector, f: Byte ⇒ Unit)              = value.foreach(f)

} 
Example 2
Source File: WatcherTypes.scala    From eclair   with Apache License 2.0 5 votes vote down vote up
package fr.acinq.eclair.blockchain

import akka.actor.ActorRef
import fr.acinq.bitcoin.Crypto.PublicKey
import fr.acinq.bitcoin.{ByteVector32, Script, ScriptWitness, Transaction}
import fr.acinq.eclair.channel.BitcoinEvent
import fr.acinq.eclair.wire.ChannelAnnouncement
import scodec.bits.ByteVector

import scala.util.{Failure, Success, Try}


final case class PublishAsap(tx: Transaction)
final case class ValidateRequest(ann: ChannelAnnouncement)
sealed trait UtxoStatus
object UtxoStatus {
  case object Unspent extends UtxoStatus
  case class Spent(spendingTxConfirmed: Boolean) extends UtxoStatus
}
final case class ValidateResult(c: ChannelAnnouncement, fundingTx: Either[Throwable, (Transaction, UtxoStatus)])

final case class GetTxWithMeta(txid: ByteVector32)
final case class GetTxWithMetaResponse(txid: ByteVector32, tx_opt: Option[Transaction], lastBlockTimestamp: Long)

// @formatter:on 
Example 3
Source File: NodeURI.scala    From eclair   with Apache License 2.0 5 votes vote down vote up
package fr.acinq.eclair.io

import com.google.common.net.HostAndPort
import fr.acinq.bitcoin.Crypto.PublicKey
import scodec.bits.ByteVector

import scala.util.{Failure, Success, Try}

case class NodeURI(nodeId: PublicKey, address: HostAndPort) {
  override def toString: String = s"$nodeId@$address"
}

object NodeURI {

  val DEFAULT_PORT = 9735

  
  @throws[IllegalArgumentException]
  def parse(uri: String): NodeURI = {
    uri.split("@") match {
      case Array(nodeId, address) => (Try(PublicKey(ByteVector.fromValidHex(nodeId))), Try(HostAndPort.fromString(address).withDefaultPort(DEFAULT_PORT))) match {
        case (Success(pk), Success(hostAndPort)) => NodeURI(pk, hostAndPort)
        case (Failure(_), _) => throw new IllegalArgumentException("Invalid node id")
        case (_, Failure(_)) => throw new IllegalArgumentException("Invalid host:port")
      }
      case _ => throw new IllegalArgumentException("Invalid uri, should be nodeId@host:port")
    }
  }
} 
Example 4
Source File: WaitForFundingCreatedInternalStateSpec.scala    From eclair   with Apache License 2.0 5 votes vote down vote up
package fr.acinq.eclair.channel.states.b

import akka.testkit.{TestFSMRef, TestProbe}
import fr.acinq.bitcoin.{ByteVector32, Satoshi}
import fr.acinq.eclair.TestConstants.{Alice, Bob}
import fr.acinq.eclair.blockchain.{MakeFundingTxResponse, TestWallet}
import fr.acinq.eclair.channel._
import fr.acinq.eclair.channel.states.StateTestsHelperMethods
import fr.acinq.eclair.wire._
import fr.acinq.eclair.{TestConstants, TestKitBaseClass}
import org.scalatest.Outcome
import org.scalatest.funsuite.FixtureAnyFunSuiteLike
import scodec.bits.ByteVector

import scala.concurrent.duration._
import scala.concurrent.{Future, Promise}



class WaitForFundingCreatedInternalStateSpec extends TestKitBaseClass with FixtureAnyFunSuiteLike with StateTestsHelperMethods {

  case class FixtureParam(alice: TestFSMRef[State, Data, Channel], alice2bob: TestProbe, bob2alice: TestProbe, alice2blockchain: TestProbe)

  override def withFixture(test: OneArgTest): Outcome = {
    val noopWallet = new TestWallet {
      override def makeFundingTx(pubkeyScript: ByteVector, amount: Satoshi, feeRatePerKw: Long): Future[MakeFundingTxResponse] = Promise[MakeFundingTxResponse].future  // will never be completed
    }
    val setup = init(wallet = noopWallet)
    import setup._
    val aliceInit = Init(Alice.channelParams.features)
    val bobInit = Init(Bob.channelParams.features)
    within(30 seconds) {
      alice ! INPUT_INIT_FUNDER(ByteVector32.Zeroes, TestConstants.fundingSatoshis, TestConstants.pushMsat, TestConstants.feeratePerKw, TestConstants.feeratePerKw, Alice.channelParams, alice2bob.ref, bobInit, ChannelFlags.Empty, ChannelVersion.STANDARD)
      bob ! INPUT_INIT_FUNDEE(ByteVector32.Zeroes, Bob.channelParams, bob2alice.ref, aliceInit)
      alice2bob.expectMsgType[OpenChannel]
      alice2bob.forward(bob)
      bob2alice.expectMsgType[AcceptChannel]
      bob2alice.forward(alice)
      awaitCond(alice.stateName == WAIT_FOR_FUNDING_INTERNAL)
      withFixture(test.toNoArgTest(FixtureParam(alice, alice2bob, bob2alice, alice2blockchain)))
    }
  }

  test("recv Error") { f =>
    import f._
    alice ! Error(ByteVector32.Zeroes, "oops")
    awaitCond(alice.stateName == CLOSED)
  }

  test("recv CMD_CLOSE") { f =>
    import f._
    alice ! CMD_CLOSE(None)
    awaitCond(alice.stateName == CLOSED)
  }

} 
Example 5
Source File: FuzzyPipe.scala    From eclair   with Apache License 2.0 5 votes vote down vote up
package fr.acinq.eclair.channel

import akka.actor.{Actor, ActorLogging, ActorRef, Stash}
import fr.acinq.eclair.Features
import fr.acinq.eclair.channel.Commitments.msg2String
import fr.acinq.eclair.wire.{Init, LightningMessage}
import scodec.bits.ByteVector

import scala.concurrent.duration._
import scala.util.Random


class FuzzyPipe(fuzzy: Boolean) extends Actor with Stash with ActorLogging {

  import scala.concurrent.ExecutionContext.Implicits.global

  def receive = {
    case (a: ActorRef, b: ActorRef) =>
      unstashAll()
      context become connected(a, b, 10)

    case _ => stash()
  }

  def stayOrDisconnect(a: ActorRef, b: ActorRef, countdown: Int): Unit = {
    if (!fuzzy) context become connected(a, b, countdown - 1) // fuzzy mode disabled, we never disconnect
    else if (countdown > 1) context become connected(a, b, countdown - 1)
    else {
      log.debug("DISCONNECTED")
      a ! INPUT_DISCONNECTED
      b ! INPUT_DISCONNECTED
      context.system.scheduler.scheduleOnce(100 millis, self, 'reconnect)
      context become disconnected(a, b)
    }
  }

  def connected(a: ActorRef, b: ActorRef, countdown: Int): Receive = {
    case msg: LightningMessage if sender() == a =>
      log.debug(f"A ---${msg2String(msg)}%-6s--> B")
      b forward msg
      stayOrDisconnect(a, b, countdown)
    case msg: LightningMessage if sender() == b =>
      log.debug(f"A <--${msg2String(msg)}%-6s--- B")
      a forward msg
      stayOrDisconnect(a, b, countdown)
  }

  def disconnected(a: ActorRef, b: ActorRef): Receive = {
    case msg: LightningMessage if sender() == a =>
      // dropped
      log.info(f"A ---${msg2String(msg)}%-6s-X")
    case msg: LightningMessage if sender() == b =>
      // dropped
      log.debug(f"  X-${msg2String(msg)}%-6s--- B")
    case 'reconnect =>
      log.debug("RECONNECTED")
      val dummyInit = Init(Features.empty)
      a ! INPUT_RECONNECTED(self, dummyInit, dummyInit)
      b ! INPUT_RECONNECTED(self, dummyInit, dummyInit)
      context become connected(a, b, Random.nextInt(40))
  }
} 
Example 6
Source File: SqliteChannelsDbSpec.scala    From eclair   with Apache License 2.0 5 votes vote down vote up
package fr.acinq.eclair.db

import fr.acinq.bitcoin.ByteVector32
import fr.acinq.eclair.db.sqlite.SqliteUtils.{getVersion, using}
import fr.acinq.eclair.db.sqlite.{SqliteChannelsDb, SqlitePendingRelayDb}
import fr.acinq.eclair.wire.ChannelCodecs.stateDataCodec
import fr.acinq.eclair.wire.ChannelCodecsSpec
import fr.acinq.eclair.{CltvExpiry, TestConstants}
import org.scalatest.funsuite.AnyFunSuite
import org.sqlite.SQLiteException
import scodec.bits.ByteVector

class SqliteChannelsDbSpec extends AnyFunSuite {

  test("init sqlite 2 times in a row") {
    val sqlite = TestConstants.sqliteInMemory()
    val db1 = new SqliteChannelsDb(sqlite)
    val db2 = new SqliteChannelsDb(sqlite)
  }

  test("add/remove/list channels") {
    val sqlite = TestConstants.sqliteInMemory()
    val db = new SqliteChannelsDb(sqlite)
    new SqlitePendingRelayDb(sqlite) // needed by db.removeChannel

    val channel = ChannelCodecsSpec.normal

    val commitNumber = 42
    val paymentHash1 = ByteVector32.Zeroes
    val cltvExpiry1 = CltvExpiry(123)
    val paymentHash2 = ByteVector32(ByteVector.fill(32)(1))
    val cltvExpiry2 = CltvExpiry(656)

    intercept[SQLiteException](db.addHtlcInfo(channel.channelId, commitNumber, paymentHash1, cltvExpiry1)) // no related channel

    assert(db.listLocalChannels().toSet === Set.empty)
    db.addOrUpdateChannel(channel)
    db.addOrUpdateChannel(channel)
    assert(db.listLocalChannels() === List(channel))

    assert(db.listHtlcInfos(channel.channelId, commitNumber).toList == Nil)
    db.addHtlcInfo(channel.channelId, commitNumber, paymentHash1, cltvExpiry1)
    db.addHtlcInfo(channel.channelId, commitNumber, paymentHash2, cltvExpiry2)
    assert(db.listHtlcInfos(channel.channelId, commitNumber).toList == List((paymentHash1, cltvExpiry1), (paymentHash2, cltvExpiry2)))
    assert(db.listHtlcInfos(channel.channelId, 43).toList == Nil)

    db.removeChannel(channel.channelId)
    assert(db.listLocalChannels() === Nil)
    assert(db.listHtlcInfos(channel.channelId, commitNumber).toList == Nil)
  }

  test("migrate channel database v1 -> v2") {
    val sqlite = TestConstants.sqliteInMemory()

    // create a v1 channels database
    using(sqlite.createStatement()) { statement =>
      getVersion(statement, "channels", 1)
      statement.execute("PRAGMA foreign_keys = ON")
      statement.executeUpdate("CREATE TABLE IF NOT EXISTS local_channels (channel_id BLOB NOT NULL PRIMARY KEY, data BLOB NOT NULL)")
      statement.executeUpdate("CREATE TABLE IF NOT EXISTS htlc_infos (channel_id BLOB NOT NULL, commitment_number BLOB NOT NULL, payment_hash BLOB NOT NULL, cltv_expiry INTEGER NOT NULL, FOREIGN KEY(channel_id) REFERENCES local_channels(channel_id))")
      statement.executeUpdate("CREATE INDEX IF NOT EXISTS htlc_infos_idx ON htlc_infos(channel_id, commitment_number)")
    }

    // insert 1 row
    val channel = ChannelCodecsSpec.normal
    val data = stateDataCodec.encode(channel).require.toByteArray
    using(sqlite.prepareStatement("INSERT INTO local_channels VALUES (?, ?)")) { statement =>
      statement.setBytes(1, channel.channelId.toArray)
      statement.setBytes(2, data)
      statement.executeUpdate()
    }

    // check that db migration works
    val db = new SqliteChannelsDb(sqlite)
    using(sqlite.createStatement()) { statement =>
      assert(getVersion(statement, "channels", 1) == 2) // version changed from 1 -> 2
    }
    assert(db.listLocalChannels() === List(channel))
  }
} 
Example 7
Source File: BinaryCodecs.scala    From skunk   with MIT License 5 votes vote down vote up
// Copyright (c) 2018-2020 by Rob Norris
// This software is licensed under the MIT License (MIT).
// For more information see LICENSE or https://opensource.org/licenses/MIT

package skunk
package codec

import cats.implicits._
import scodec.bits.ByteVector
import skunk.data.Type

trait BinaryCodecs {

  val bytea: Codec[Array[Byte]] = Codec.simple[Array[Byte]](
    "\\x" + ByteVector.view(_).toHex,
    z => ByteVector.fromHex(z.substring(2)).map(_.toArray).fold("Cannot decode bytes from HEX String".asLeft[Array[Byte]])(_.asRight[String]),
    Type.bytea)

}

object binary extends BinaryCodecs 
Example 8
Source File: HashTransformationSpec.scala    From swave   with Mozilla Public License 2.0 5 votes vote down vote up
package swave.core.hash

import scodec.bits.ByteVector
import swave.compat.scodec._
import swave.core._

class HashTransformationSpec extends SwaveSpec {
  import swave.core.text._

  implicit val env = StreamEnv()

  "HashTransformations" - {

    "md5" in {
      Spout
        .one("swave rocks!")
        .utf8Encode
        .md5
        .drainToHead()
        .value
        .get
        .get shouldEqual ByteVector.fromHex("e1b2b603f9cca4a909c07d42a5788fe3").get
    }
  }
} 
Example 9
Source File: TextTransformationSpec.scala    From swave   with Mozilla Public License 2.0 5 votes vote down vote up
package swave.core.text

import scala.concurrent.duration._
import scodec.bits.ByteVector
import swave.compat.scodec._
import swave.core._
import swave.core.util._

class TextTransformationSpec extends SwaveSpec {

  implicit val env = StreamEnv()
  import env.defaultDispatcher

  val largeText =
    """Es war einmal, zur Zeit t=t0, ein armer rechtschaffener Vierpol namens Eddy Wirbelstrom. Er bewohnte einen
      |bescheiden möbilierten Hohlraum im Dielektrikum mit fließend kalten und warmen Sättigungsstrom. Leider mußte er
      |während der kalten Jahreszeit für die Erwärmung der Sperrschicht noch extra bezahlen. Seinen Lebensunterhalt
      |bestritt er mit einer Verstärkerzucht auf Transistorbasis.
      |
      |Eddy Wirbelstrom liebte mit der ganzen Kraft seiner Übertragungsfunktion - Ionchen!
      |
      |Die induktivste Spule mit dem kleinsten Verlustwinkel im ganzen Kreise und Tochter der einflußreichen EMKs.
      |Ihr remanenter Ferritkörper, ihre symmetrischen Netzintegrale, ihre überaus harmonischen Oberwellen - besonders
      |der Sinus - beeindruckten selbst die Suszeptibilität ausgedienter Leidener Flaschen, was viel heißen will.
      |Die jungfräulichen Kurven Ionchens waren auch wirklich sehr steil.
      |
      |Ionchens Vater, Cosinus Phi, ein bekannter industrieller Leistungsfaktor, hatte allerdings bereits konkrete
      |Schaltpläne für die Zukunft t >> t0 seiner Tochter. Sie sollte nur einer anerkannten Kapazität mit
      |ausgeprägtem Nennwert angeschlossen werden, aber wie so oft während der Lebensdauer L hatte auch diese Masche
      |einen Knoten, denn der Zufallstrieb wollte es anders.
      |
      |Als Ionchen eines Tages, zur Zeit t=t1, auf ihrem Picofarad vom Frisiersalon nach Hause fuhr (sie hatte sich eine
      |neue Stehwelle legen lassen), da geriet ihr ein Sägezahn in die Siebkette. Aber Eddy Wirbelstrom, der die Gegend
      |periodisch frequentierte, eilte mit minimaler Laufzeit hinzu, und es gelang ihm, Ionchens Kippschwingung noch
      |vor dem Maximum der Amplitude abzufangen, gleichzurichten und so die Resonanzkatastrophe zu verhindern.
      |
      |Es ist sicherlich nicht dem Zufall z1 zuzuschreiben, daß sie sich schon zur Zeit t = t1 + dt wiedersahen.
      |Eddy lud Ionchen zum Abendessen ins "Goldene Integral" ein. Aber das Integral war wie immer geschlossen.
      |"Macht nichts", sagte Ionchen, "ich habe zu Mittag gut gegessen und die Sättigungsinduktion hat bis jetzt
      |angehalten. Außerdem muß ich auf meine Feldlinie achten." Unter irgendeinem Vorwand lud Eddy sie dann zu einer
      |Rundfahrt im Rotor ein. Aber Ionchen lehnte ab: "Mir wird bei der zweiten Ableitung immer so leicht übel."
      |So unternahmen sie, ganz entgegen den Schaltplänen von Vater Cosinus Phi, einen kleinen Frequenzgang entlang dem
      |nahegelegenen Streufluß.
      |
      |Der Abend senkte sich über die komplexe Ebene und im imaginären Raum erglänzten die Sternschaltungen.
      |Eddy und Ionchen genossen die Isolierung vom lauten Getriebe der Welt und ließen ihre Blicke gegen 0 laufen.
      |Ein einsamer Modulationsbrummer flog vorbei, sanft plätscherten die elektromagnetischen Wellen und leise sang
      |eine Entstördrossel.
      |
      |Als sie an der Wheatston-Brücke angelangt waren, dort, wo der Blindstrom in den Streufluß mündet, lehnten sie
      |sich ans Gitter. Da nahm Eddy Wirbelstrom seinen ganzen Durchgriff zusammen und emittierte: "Bei Gauß!",
      |worauf Ionchen hauchte: "Deine lose Rückkopplung hat es mir angetan." Ihr Kilohertz schlug heftig.
      |
      |Der Informationsgehalt dieser Nachricht durchflutete Eddy. Die Summe über alle Theta, von Theta = 0 bis zu diesem
      |Ereignis war zu konvergent und beide entglitten der Kontrolle ihrer Zeitkonstanten.
      |Im Überschwange des jungen Glücks erreichten sie vollausgesteuert die Endstufen.
      |Und wenn sie nicht gedämpft wurden, so schwingen sie heute noch.""".stripMargin.replace("\r\n", "\n")

  "TextTransformations" - {

    "utf8decode" in {
      for (_ <- 1 to 10) {
        val random = XorShiftRandom()
        Spout(largeText.getBytes(UTF8).iterator)
          .injectSequential()
          .flatMap(_.take(random.nextLong(32)).drainToVector(32).map(ByteVector(_)))
          .utf8Decode
          .async()
          .drainToMkString(1000)
          .await(3.seconds) shouldEqual largeText
      }
    }

    "utf8encode" in {
      for (_ <- 1 to 10) {
        val random = XorShiftRandom()
        Spout(largeText.iterator)
          .injectSequential()
          .flatMap(_.take(random.nextLong(32)).drainToMkString(32))
          .utf8Encode
          .async()
          .drainFolding(ByteVector.empty)(_ ++ _)
          .await() shouldEqual ByteVector(largeText getBytes UTF8)
      }
    }

    "lines" in {
      for (_ <- 1 to 1) {
        val random = XorShiftRandom()
        Spout(largeText.iterator)
          .injectSequential()
          .flatMap(_.take(random.nextLong(32)).drainToMkString(32))
          .lines
          .async()
          .drainToVector(1000)
          .await() shouldEqual largeText.split('\n')
      }
    }
  }
} 
Example 10
Source File: FileDrainSpec.scala    From swave   with Mozilla Public License 2.0 5 votes vote down vote up
package swave.core.io.files

import java.nio.file.{Files, Path}
import scala.concurrent.duration._
import scodec.bits.ByteVector
import swave.compat.scodec._
import swave.core.util._
import swave.core._

class FileDrainSpec extends SwaveSpec {
  import swave.core.io.files._

  implicit val env = StreamEnv()

  val TestLines = List[String](
    "a" * 1000 + "\n",
    "b" * 1000 + "\n",
    "c" * 1000 + "\n",
    "d" * 1000 + "\n",
    "e" * 1000 + "\n",
    "f" * 1000 + "\n")

  val TestBytes = TestLines.map(ByteVector.encodeAscii(_).right.get)

  "Drain.toPath must" - {

    "write lines to a short file" in withTempPath(create = true) { path ⇒
      val result = Spout.one(ByteVector("abc" getBytes UTF8)).drainTo(Drain.toPath(path, chunkSize = 512))
      result.await(5.seconds) shouldEqual 3
      verifyFileContents(path, "abc")
    }

    "write lines to a long file" in withTempPath(create = true) { path ⇒
      val result = Spout(TestBytes).drainTo(Drain.toPath(path, chunkSize = 512))
      result.await(5.seconds) shouldEqual 6006
      verifyFileContents(path, TestLines mkString "")
    }

    "create new file if required" in withTempPath(create = false) { path ⇒
      val result = Spout(TestBytes).drainTo(Drain.toPath(path, chunkSize = 512))
      result.await(5.seconds) shouldEqual 6006
      verifyFileContents(path, TestLines mkString "")
    }
  }

  private def withTempPath(create: Boolean)(block: Path ⇒ Unit): Unit = {
    val targetFile = Files.createTempFile("file-sink", ".tmp")
    if (!create) Files.delete(targetFile)
    try block(targetFile)
    finally Files.delete(targetFile)
  }

  private def verifyFileContents(path: Path, contents: String): Unit = {
    val out = Files.readAllBytes(path)
    new String(out) shouldEqual contents
  }
} 
Example 11
Source File: ElectrumEclairWallet.scala    From eclair   with Apache License 2.0 5 votes vote down vote up
package fr.acinq.eclair.blockchain.electrum

import akka.actor.{ActorRef, ActorSystem}
import akka.pattern.ask
import fr.acinq.bitcoin.{ByteVector32, Crypto, Satoshi, Script, Transaction, TxOut}
import fr.acinq.eclair.addressToPublicKeyScript
import fr.acinq.eclair.blockchain.electrum.ElectrumClient.BroadcastTransaction
import fr.acinq.eclair.blockchain.electrum.ElectrumWallet._
import fr.acinq.eclair.blockchain.{EclairWallet, MakeFundingTxResponse, OnChainBalance}
import grizzled.slf4j.Logging
import scodec.bits.ByteVector

import scala.concurrent.{ExecutionContext, Future}

class ElectrumEclairWallet(val wallet: ActorRef, chainHash: ByteVector32)(implicit system: ActorSystem, ec: ExecutionContext, timeout: akka.util.Timeout) extends EclairWallet with Logging {

  override def getBalance: Future[OnChainBalance] = (wallet ? GetBalance).mapTo[GetBalanceResponse].map(balance => OnChainBalance(balance.confirmed, balance.unconfirmed))

  override def getReceiveAddress: Future[String] = (wallet ? GetCurrentReceiveAddress).mapTo[GetCurrentReceiveAddressResponse].map(_.address)

  override def getReceivePubkey(receiveAddress: Option[String] = None): Future[Crypto.PublicKey] = Future.failed(new RuntimeException("Not implemented"))

  def getXpub: Future[GetXpubResponse] = (wallet ? GetXpub).mapTo[GetXpubResponse]

  override def makeFundingTx(pubkeyScript: ByteVector, amount: Satoshi, feeRatePerKw: Long): Future[MakeFundingTxResponse] = {
    val tx = Transaction(version = 2, txIn = Nil, txOut = TxOut(amount, pubkeyScript) :: Nil, lockTime = 0)
    (wallet ? CompleteTransaction(tx, feeRatePerKw)).mapTo[CompleteTransactionResponse].map {
      case CompleteTransactionResponse(tx1, fee1, None) => MakeFundingTxResponse(tx1, 0, fee1)
      case CompleteTransactionResponse(_, _, Some(error)) => throw error
    }
  }

  override def commit(tx: Transaction): Future[Boolean] =
    (wallet ? BroadcastTransaction(tx)) flatMap {
      case ElectrumClient.BroadcastTransactionResponse(tx, None) =>
        //tx broadcast successfully: commit tx
        wallet ? CommitTransaction(tx)
      case ElectrumClient.BroadcastTransactionResponse(tx, Some(error)) if error.message.contains("transaction already in block chain") =>
        // tx was already in the blockchain, that's weird but it is OK
        wallet ? CommitTransaction(tx)
      case ElectrumClient.BroadcastTransactionResponse(_, Some(error)) =>
        //tx broadcast failed: cancel tx
        logger.error(s"cannot broadcast tx ${tx.txid}: $error")
        wallet ? CancelTransaction(tx)
      case ElectrumClient.ServerError(ElectrumClient.BroadcastTransaction(tx), error) =>
        //tx broadcast failed: cancel tx
        logger.error(s"cannot broadcast tx ${tx.txid}: $error")
        wallet ? CancelTransaction(tx)
    } map {
      case CommitTransactionResponse(_) => true
      case CancelTransactionResponse(_) => false
    }

  def sendPayment(amount: Satoshi, address: String, feeRatePerKw: Long): Future[String] = {
    val publicKeyScript = Script.write(addressToPublicKeyScript(address, chainHash))
    val tx = Transaction(version = 2, txIn = Nil, txOut = TxOut(amount, publicKeyScript) :: Nil, lockTime = 0)
    (wallet ? CompleteTransaction(tx, feeRatePerKw))
      .mapTo[CompleteTransactionResponse]
      .flatMap {
        case CompleteTransactionResponse(tx, _, None) => commit(tx).map {
          case true => tx.txid.toString()
          case false => throw new RuntimeException(s"could not commit tx=$tx")
        }
        case CompleteTransactionResponse(_, _, Some(error)) => throw error
      }
  }

  def sendAll(address: String, feeRatePerKw: Long): Future[(Transaction, Satoshi)] = {
    val publicKeyScript = Script.write(addressToPublicKeyScript(address, chainHash))
    (wallet ? SendAll(publicKeyScript, feeRatePerKw))
      .mapTo[SendAllResponse]
      .map {
        case SendAllResponse(tx, fee) => (tx, fee)
      }
  }

  override def rollback(tx: Transaction): Future[Boolean] = (wallet ? CancelTransaction(tx)).map(_ => true)

  override def doubleSpent(tx: Transaction): Future[Boolean] = {
    (wallet ? IsDoubleSpent(tx)).mapTo[IsDoubleSpentResponse].map(_.isDoubleSpent)
  }

} 
Example 12
Source File: ReprFormat.scala    From polynote   with Apache License 2.0 5 votes vote down vote up
package polynote.data

import scodec.bits.{BitVector, ByteVector}
import shapeless.{Generic, HList, HNil, Lazy, ::}

import scala.collection.GenTraversable

trait ReprFormat[T] extends (T => ByteVector)

object ReprFormat extends ReprFormat0 {

  final case class instance[T](fn: T => ByteVector) extends ReprFormat[T] {
    def apply(t: T): ByteVector = fn(t)
  }

  private val one = ByteVector.fromByte(1)
  private val zero = ByteVector.fromByte(0)

  implicit val byteFormat: ReprFormat[Byte] = instance(ByteVector.fromByte)
  implicit val boolFormat: ReprFormat[Boolean] = instance(b => if (b) one else zero)
  implicit val shortFormat: ReprFormat[Short] = instance(ByteVector.fromShort(_))
  implicit val intFormat: ReprFormat[Int] = instance(ByteVector.fromInt(_))
  implicit val longFormat: ReprFormat[Long] = instance(ByteVector.fromLong(_))
  implicit val floatFormat: ReprFormat[Float] = instance(f => ByteVector.fromInt(java.lang.Float.floatToIntBits(f)))
  implicit val doubleFormat: ReprFormat[Double] = instance(d => ByteVector.fromLong(java.lang.Double.doubleToLongBits(d)))
  implicit val stringFormat: ReprFormat[String] = instance(str => ByteVector.encodeUtf8(str).fold(throw _, identity))
  implicit val byteArrayFormat: ReprFormat[Array[Byte]] = instance(ByteVector(_))
  implicit val byteVectorFormat: ReprFormat[ByteVector] = instance(identity)
  implicit val bitVectorFormat: ReprFormat[BitVector] = instance(_.toByteVector)

  implicit def arrayFormat[A](implicit elFormat: ReprFormat[A]): ReprFormat[Array[A]] = instance {
    arr => arr.foldLeft(ByteVector.fromInt(arr.length)) {
      (accum: ByteVector, next: A) => accum ++ elFormat(next)
    }
  }

  implicit def traversableFormat[F[X] <: GenTraversable[X], A](implicit elFormat: ReprFormat[A]): ReprFormat[F[A]] = instance {
    arr => arr.foldLeft(ByteVector.fromInt(arr.size)) {
      (accum, next) => accum ++ elFormat(next)
    }
  }

  implicit def optionalFormat[A](implicit elFormat: ReprFormat[A]): ReprFormat[Option[A]] = instance {
    case Some(el) => one ++ elFormat(el)
    case None => zero
  }

  implicit val hnilFormat: ReprFormat[HNil] = instance(_ => ByteVector.empty)

  implicit def hlistFormat[H, T <: HList](implicit formatH: ReprFormat[H], formatT: ReprFormat[T]): ReprFormat[H :: T] =
    instance {
      case h :: t => formatH(h) ++ formatT(t)
    }


}

private[data] trait ReprFormat0 { self: ReprFormat.type =>
  implicit def struct[A, L <: HList](implicit gen: Generic.Aux[A, L], formatL: Lazy[ReprFormat[L]]): ReprFormat[A] =
    instance(a => formatL.value(gen.to(a)))
} 
Example 13
Source File: DataTypeCodec.scala    From polynote   with Apache License 2.0 5 votes vote down vote up
package polynote.kernel

import java.nio.ByteBuffer
import java.nio.charset.StandardCharsets

import polynote.runtime._
import scodec.Codec
import scodec.bits.ByteVector
import scodec.codecs._
import scodec.codecs.implicits._
import shapeless.cachedImplicit

object DataTypeCodec {

  implicit val byteDiscriminator: Discriminator[DataType, ByteType.type, Byte] = Discriminator(0)
  implicit val boolDiscriminator: Discriminator[DataType, BoolType.type, Byte] = Discriminator(1)
  implicit val shortDiscriminator: Discriminator[DataType, ShortType.type, Byte] = Discriminator(2)
  implicit val intDiscriminator: Discriminator[DataType, IntType.type, Byte] = Discriminator(3)
  implicit val longDiscriminator: Discriminator[DataType, LongType.type, Byte] = Discriminator(4)
  implicit val floatDiscriminator: Discriminator[DataType, FloatType.type, Byte] = Discriminator(5)
  implicit val doubleDiscriminator: Discriminator[DataType, DoubleType.type, Byte] = Discriminator(6)
  implicit val binaryDiscriminator: Discriminator[DataType, BinaryType.type, Byte] = Discriminator(7)
  implicit val stringDiscriminator: Discriminator[DataType, StringType.type, Byte] = Discriminator(8)
  implicit val structDiscriminator: Discriminator[DataType, StructType, Byte] = Discriminator(9)
  implicit val optionalDiscriminator: Discriminator[DataType, OptionalType, Byte] = Discriminator(10)
  implicit val arrayDiscriminator: Discriminator[DataType, ArrayType, Byte] = Discriminator(11)
  //implicit val dateDiscriminator: Discriminator[DataType, DateType.type, Byte] = Discriminator(12)
  //implicit val timestampDiscriminator: Discriminator[DataType, TimestampType.type, Byte] = Discriminator(13)
  implicit val typeDiscriminator: Discriminator[DataType, TypeType.type, Byte] = Discriminator(14)
  implicit val mapDiscriminator: Discriminator[DataType, MapType, Byte] = Discriminator(15)

  implicit val dataTypeDiscriminated: Discriminated[DataType, Byte] = Discriminated(byte)

  implicit val dataTypeCodec: Codec[DataType] = cachedImplicit
}

object ValueReprCodec {
  import DataTypeCodec.dataTypeCodec

  implicit val valueReprDiscriminated: Discriminated[ValueRepr, Byte] = Discriminated(byte)
  implicit val stringRepr: Discriminator[ValueRepr, StringRepr, Byte] = Discriminator(0)
  implicit val mimeRepr: Discriminator[ValueRepr, MIMERepr, Byte] =  Discriminator(1)
  implicit val dataRepr: Discriminator[ValueRepr, DataRepr, Byte] = Discriminator(2)
  implicit val lazyDataRepr: Discriminator[ValueRepr, LazyDataRepr, Byte] = Discriminator(3)
  implicit val updatingDataRepr: Discriminator[ValueRepr, UpdatingDataRepr, Byte] = Discriminator(4)
  implicit val streamingDataRepr: Discriminator[ValueRepr, StreamingDataRepr, Byte] = Discriminator(5)

  implicit val streamingDataReprCodec: Codec[StreamingDataRepr] = cachedImplicit
  implicit val byteBufferCodec: Codec[ByteBuffer] = variableSizeBytes(int32, bytes).xmap(_.toByteBuffer, ByteVector.apply)

  implicit val codec: Codec[ValueRepr] = cachedImplicit
}

object TableOpCodec {
  implicit val tableOpDiscriminated: Discriminated[TableOp, Byte] = Discriminated(byte)
  implicit val groupAgg: Discriminator[TableOp, GroupAgg, Byte] = Discriminator(0)
  implicit val quantileBin: Discriminator[TableOp, QuantileBin, Byte] = Discriminator(1)
  implicit val select: Discriminator[TableOp, Select, Byte] = Discriminator(2)

  implicit val tableOpCodec: Codec[TableOp] = cachedImplicit
} 
Example 14
Source File: RecoverLog.scala    From polynote   with Apache License 2.0 5 votes vote down vote up
package polynote

import java.nio.channels.FileChannel
import java.nio.file.{Files, Paths, StandardOpenOption}
import java.time.Instant

import cats.effect.Effect
import polynote.app.{Args, MainArgs}
import polynote.kernel.logging.Logging
import polynote.messages.{Message, Notebook, NotebookUpdate, ShortList}
import polynote.server.AppEnv
import zio.{Ref, Runtime, Task, UIO, ZIO}
import zio.ZIO.effectTotal
import zio.blocking.effectBlocking
import fs2.Stream
import polynote.server.repository.{FileBasedRepository, NotebookContent}
import polynote.server.repository.format.ipynb.IPythonFormat
import polynote.server.repository.fs.WAL
import polynote.server.taskConcurrent
import scodec.bits.ByteVector
import scodec.stream.decode
import scodec.codecs
import scodec.stream.decode.StreamDecoder

object RecoverLog {

  def replay(messages: Stream[Task, (Instant, Message)], ref: Ref[Notebook], log: Logging.Service): UIO[Unit] = messages.map(_._2).evalMap {
    case nb: Notebook => ref.set(nb)
    case upd: NotebookUpdate => ref.update {
      nb => try {
        upd.applyTo(nb)
      } catch {
        case err: Throwable =>
          log.errorSync(Some("Dropped update because an error occurred when applying it"), err)
          nb
      }
    }
    case _ => ZIO.unit
  }.compile.drain.catchAll {
    err =>
      log.error(Some("Error occurred while replaying the log; printing the final state anyway."), err)
  }

  def main(implicit ev: Effect[Task]): ZIO[AppEnv, String, Int] = for {
    args     <- ZIO.access[MainArgs](_.get[Args].rest)
    path     <- ZIO(args.head).flatMap(pathStr => effectBlocking(Paths.get(pathStr).toRealPath())).orDie
    is       <- effectBlocking(FileChannel.open(path, StandardOpenOption.READ)).orDie
    log      <- Logging.access
    _        <- Logging.info(s"Reading log entries from ${path}...")
    messages  = WAL.decoder.decodeMmap(is)
    ref      <- Ref.make(Notebook("", ShortList.Nil, None))
    _        <- replay(messages, ref, log)
    format    = new IPythonFormat
    result   <- ref.get
    encoded  <- format.encodeNotebook(NotebookContent(result.cells, result.config)).orDie
    _        <- effectTotal(println(encoded))
  } yield 0
} 
Example 15
Source File: WAL.scala    From polynote   with Apache License 2.0 5 votes vote down vote up
package polynote.server
package repository.fs

import java.nio.ByteBuffer
import java.nio.charset.StandardCharsets
import java.time.Instant

import polynote.messages.{Message, Notebook}
import scodec.bits.{BitVector, ByteVector}
import scodec.{Attempt, Codec, codecs}
import scodec.stream.decode
import scodec.stream.decode.StreamDecoder
import zio.{RIO, Task, ZIO}
import zio.blocking.Blocking
import zio.clock.{Clock, currentDateTime}

import scala.util.Try

object WAL {

  val WALMagicNumber: Array[Byte] = "PNWAL".getBytes(StandardCharsets.US_ASCII)
  val WALVersion: Short = 1

  // Timestamp for each update is stored in 32 bits unsigned, epoch UTC seconds.
  // So we'll have to change the format by February of 2106. Apologies to my great-great-great grandchildren.
  private val instantCodec = codecs.uint32.exmap[Instant](
    epochSeconds => Attempt.fromTry(Try(Instant.ofEpochSecond(epochSeconds))),
    instant      => Attempt.successful(instant.getEpochSecond)
  )

  def encodeTimestamp(instant: Instant): Task[BitVector] =
    ZIO.fromEither(instantCodec.encode(instant).toEither)
      .mapError(err => new RuntimeException(err.message))

  val messageCodec: Codec[(Instant, Message)] = codecs.variableSizeBytes(codecs.int32, instantCodec ~ Message.codec)

  val decoder: StreamDecoder[(Instant, Message)] = {
    val readMagic = decode.once(codecs.constant(ByteVector(WALMagicNumber)))
    val readVersion = decode.once(codecs.int16)
    def readMessages(version: Int): StreamDecoder[(Instant, Message)] = version match {
      case 1 => decode.many(messageCodec)
      case v => decode.raiseError(new Exception(s"Unknown WAL version $v"))
    }

    for {
      _       <- readMagic
      ver     <- readVersion
      message <- readMessages(ver)
    } yield message
  }

  trait WALWriter {
    protected def append(bytes: Array[Byte]): RIO[Blocking, Unit] = append(ByteBuffer.wrap(bytes))
    protected def append(bytes: BitVector): RIO[Blocking, Unit] = append(bytes.toByteBuffer)
    protected def append(bytes: ByteBuffer): RIO[Blocking, Unit]

    def writeHeader(notebook: Notebook): RIO[Blocking with Clock, Unit] =
      append(WALMagicNumber) *>
        append(BitVector.fromShort(WALVersion)) *>
        appendMessage(notebook.withoutResults)

    def appendMessage(message: Message): RIO[Blocking with Clock, Unit] = for {
      ts    <- currentDateTime.map(_.toInstant)
      bytes <- ZIO.fromEither(messageCodec.encode((ts, message)).toEither).mapError(err => new RuntimeException(err.message))
      _     <- append(bytes)
    } yield ()

    def sync(): RIO[Blocking, Unit]

    def close(): RIO[Blocking, Unit]
  }

  object WALWriter {
    object NoWAL extends WALWriter {
      override protected def append(bytes: ByteBuffer): RIO[Blocking, Unit] = ZIO.unit
      override def sync(): RIO[Blocking, Unit] = ZIO.unit
      override def close(): RIO[Blocking, Unit] = ZIO.unit
    }
  }
} 
Example 16
Source File: Netty.scala    From scalaz-netty   with Apache License 2.0 5 votes vote down vote up
package scalaz
package netty

import java.net.InetSocketAddress
import java.util.concurrent.ExecutorService

import _root_.io.netty.channel._
import scodec.bits.ByteVector

import scalaz.concurrent._
import scalaz.stream._

object Netty {

  def server(bind: InetSocketAddress, config: ServerConfig = ServerConfig.Default)(implicit pool: ExecutorService = Strategy.DefaultExecutorService, S: Strategy): Process[Task, Process[Task, Exchange[ByteVector, ByteVector]]] = {
    Process.bracket(Server(bind, config))(s => Process.eval(s.shutdown).drain) { server: Server =>
      server.listen
    }
  }

  def connect(to: InetSocketAddress, config: ClientConfig = ClientConfig.Default)(implicit pool: ExecutorService = Strategy.DefaultExecutorService, S: Strategy): Process[Task, Exchange[ByteVector, ByteVector]] = {
    Process.bracket(Client(to, config))(_.shutdown) { client: Client =>
      Process(Exchange(client.read, client.write))
    }
  }

  private[netty] def toTask(f: ChannelFuture)(implicit pool: ExecutorService): Task[Unit] = fork {
    Task async { (cb: (Throwable \/ Unit) => Unit) =>
      f.addListener(new ChannelFutureListener {
        def operationComplete(f: ChannelFuture): Unit = {
          if (f.isSuccess)
            cb(\/-(()))
          else
            cb(-\/(f.cause))
        }
      })
    }
  }

  private def fork[A](t: Task[A])(implicit pool: ExecutorService = Strategy.DefaultExecutorService): Task[A] = {
    Task async { cb =>
      t unsafePerformAsync { either =>
        pool.submit(new Runnable {
          def run(): Unit = cb(either)
        })

        ()
      }
    }
  }
} 
Example 17
Source File: ModelMatrixEncoding.scala    From modelmatrix   with Apache License 2.0 5 votes vote down vote up
package com.collective.modelmatrix

import java.nio.ByteBuffer

import scodec.bits.ByteVector



private[modelmatrix] trait Encode[T] {
  def encode(obj: T): ByteVector
}

private[modelmatrix] object Encode {
  def apply[T](f: T => ByteVector): Encode[T] = new Encode[T] {
    def encode(obj: T): ByteVector = f(obj)
  }

  implicit val EncodeShort: Encode[Short] =
    Encode((short: Short) => ByteVector(ByteBuffer.allocate(2).putShort(short).array()))
  implicit val EncodeInt: Encode[Int] =
    Encode((integer: Int) => ByteVector(ByteBuffer.allocate(4).putInt(integer).array()))
  implicit val EncodeLong: Encode[Long] =
    Encode((long: Long) => ByteVector(ByteBuffer.allocate(8).putLong(long).array()))
  implicit val EncodeDouble: Encode[Double] =
    Encode((double: Double) => ByteVector(ByteBuffer.allocate(8).putDouble(double).array()))
  implicit val EncodeString: Encode[String] =
    Encode((string: String) => ByteVector(string.getBytes))

}

private[modelmatrix] trait Decode[T] {
  def decode(bytes: ByteVector): T
}

private[modelmatrix] object Decode {
  def apply[T](f: ByteVector => T): Decode[T] = new Decode[T] {
    def decode(bytes: ByteVector): T = f(bytes)
  }

  implicit val DecodeShort: Decode[Short] =
    Decode(_.toByteBuffer.getShort)
  implicit val DecodeInt: Decode[Int] =
    Decode(_.toByteBuffer.getInt)
  implicit val DecodeLong: Decode[Long] =
    Decode(_.toByteBuffer.getLong)
  implicit val DecodeDouble: Decode[Double] =
    Decode(_.toByteBuffer.getDouble)
  implicit val DecodeString: Decode[String] =
    Decode(b => new String(b.toArray))

}

class ModelMatrixEncoding {

  def encode[T: Encode](obj: T): ByteVector = implicitly[Encode[T]].encode(obj)

  def decode[T: Decode](obj: ByteVector): T = implicitly[Decode[T]].decode(obj)

}

object ModelMatrixEncoding extends ModelMatrixEncoding 
Example 18
Source File: package.scala    From modelmatrix   with Apache License 2.0 5 votes vote down vote up
package com.collective.modelmatrix

import java.sql.Timestamp
import java.time.Instant

import org.apache.spark.sql.types._
import scodec.bits.ByteVector
import slick.driver.PostgresDriver.api._

package object catalog {

  implicit val instantColumnType =
    MappedColumnType.base[Instant, java.sql.Timestamp](
      instant => Timestamp.from(instant),
      _.toInstant
    )

  implicit val dataTypeColumnType =
    MappedColumnType.base[DataType, String]({
      case ShortType => "short"
      case IntegerType => "integer"
      case LongType => "long"
      case DoubleType => "double"
      case StringType => "string"
    }, {
      case "short" => ShortType
      case "integer" => IntegerType
      case "long" => LongType
      case "double" => DoubleType
      case "string" => StringType
    })

  implicit val byteVectorColumnType =
    MappedColumnType.base[ByteVector, Array[Byte]](
      _.toArray,
      ByteVector.apply
    )
} 
Example 19
Source File: CategoricalColumn.scala    From modelmatrix   with Apache License 2.0 5 votes vote down vote up
package com.collective.modelmatrix

import scodec.bits.ByteVector

sealed trait CategoricalColumn {
  type Self <: CategoricalColumn

  def columnId: Int
  def count: Long
  def cumulativeCount: Long

  def rebaseColumnId(base: Int): Self
}

object CategoricalColumn {

  case class CategoricalValue(
    columnId: Int,
    sourceName: String,
    sourceValue: ByteVector,
    count: Long,
    cumulativeCount: Long
  ) extends CategoricalColumn {
    type Self = CategoricalValue
    def rebaseColumnId(base: Int): CategoricalValue = copy(columnId = columnId + base)
  }

  case class AllOther(
    columnId: Int,
    count: Long,
    cumulativeCount: Long
  ) extends CategoricalColumn {
    type Self = AllOther
    def rebaseColumnId(base: Int): AllOther = copy(columnId = columnId + base)
  }

} 
Example 20
Source File: EventSerializerSpec.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package akka.persistence.kafka.journal

import java.io.FileOutputStream

import akka.persistence.PersistentRepr
import akka.persistence.serialization.Snapshot
import cats.effect.{IO, Sync}
import com.evolutiongaming.kafka.journal.FromBytes.implicits._
import com.evolutiongaming.kafka.journal.IOSuite._
import com.evolutiongaming.kafka.journal._
import com.evolutiongaming.kafka.journal.util.CatsHelper._
import org.scalatest.funsuite.AsyncFunSuite
import org.scalatest.matchers.should.Matchers
import play.api.libs.json.JsString
import scodec.bits.ByteVector
import TestJsonCodec.instance
import cats.implicits._

import scala.util.Try

class EventSerializerSpec extends AsyncFunSuite with ActorSuite with Matchers {

  for {
    (name, payloadType, payload) <- List(
      ("PersistentRepr.bin",       PayloadType.Binary, Snapshot("binary")),
      ("PersistentRepr.text.json", PayloadType.Json, "text"),
      ("PersistentRepr.json",      PayloadType.Json, JsString("json")))
  } {

    test(s"toEvent & toPersistentRepr, payload: $payload") {
      val persistenceId = "persistenceId"
      val persistentRepr = PersistentRepr(
        payload = payload,
        sequenceNr = 1,
        persistenceId = persistenceId,
        manifest = "manifest",
        writerUuid = "writerUuid")

      val fa = for {
        serializer <- EventSerializer.of[IO](actorSystem)
        event      <- serializer.toEvent(persistentRepr)
        actual     <- serializer.toPersistentRepr(persistenceId, event)
        _          <- Sync[IO].delay { actual shouldEqual persistentRepr }
        payload    <- event.payload.getOrError[IO]("Event.payload is not defined")
        _           = payload.payloadType shouldEqual payloadType
        
        bytes      <- ByteVectorOf[IO](getClass, name)
      } yield {
        payload match {
          case payload: Payload.Binary => payload.value shouldEqual bytes
          case payload: Payload.Text   => payload.value shouldEqual bytes.fromBytes[Try, String].get
          case payload: Payload.Json   => payload.value shouldEqual JsonCodec.summon[Try].decode.fromBytes(bytes).get
        }
      }

      fa.run()
    }
  }

  def writeToFile[F[_] : Sync](bytes: ByteVector, path: String): F[Unit] = {
    Sync[F].delay {
      val os = new FileOutputStream(path)
      os.write(bytes.toArray)
      os.close()
    }
  }
} 
Example 21
Source File: ConsRecordToActionHeader.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal.conversions

import cats.data.OptionT
import cats.implicits._
import com.evolutiongaming.catshelper.MonadThrowable
import com.evolutiongaming.kafka.journal._
import com.evolutiongaming.kafka.journal.util.CatsHelper._
import com.evolutiongaming.skafka.Header
import scodec.bits.ByteVector

trait ConsRecordToActionHeader[F[_]] {

  def apply(consRecord: ConsRecord): OptionT[F, ActionHeader]
}

object ConsRecordToActionHeader {

  implicit def apply[F[_] : MonadThrowable](implicit
    fromBytes: FromBytes[F, Option[ActionHeader]]
  ): ConsRecordToActionHeader[F] = {

    consRecord: ConsRecord => {
      def header = consRecord
        .headers
        .find { _.key === ActionHeader.key }

      def actionHeader(header: Header) = {
        val byteVector = ByteVector.view(header.value)
        fromBytes(byteVector).adaptError { case e =>
          JournalError(s"ConsRecordToActionHeader failed for $consRecord: $e", e)
        }
      }

      for {
        header       <- header.toOptionT[F]
        actionHeader <- actionHeader(header).toOptionT
      } yield actionHeader

    }
  }
} 
Example 22
Source File: ActionToProducerRecord.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal.conversions

import cats.implicits._
import com.evolutiongaming.catshelper.MonadThrowable
import com.evolutiongaming.kafka.journal.{Action, JournalError}
import com.evolutiongaming.skafka.Header
import com.evolutiongaming.skafka.producer.ProducerRecord
import scodec.bits.ByteVector

trait ActionToProducerRecord[F[_]] {

  def apply(action: Action): F[ProducerRecord[String, ByteVector]]
}

object ActionToProducerRecord {

  implicit def apply[F[_] : MonadThrowable](implicit
    actionHeaderToHeader: ActionHeaderToHeader[F],
    tupleToHeader: TupleToHeader[F]
  ): ActionToProducerRecord[F] = {

    action: Action => {
      val key = action.key
      val result = for {
        header  <- actionHeaderToHeader(action.header)
        headers <- action match {
          case a: Action.Append => a.headers.toList.traverse { case (k, v) => tupleToHeader(k, v) }
          case _: Action.Mark   => List.empty[Header].pure[F]
          case _: Action.Delete => List.empty[Header].pure[F]
          case _: Action.Purge  => List.empty[Header].pure[F]
        }
      } yield {
        val payload = action match {
          case a: Action.Append => a.payload.some
          case _: Action.Mark   => none
          case _: Action.Delete => none
          case _: Action.Purge  => none
        }

        ProducerRecord(
          topic = key.topic,
          value = payload,
          key = key.id.some,
          timestamp = action.timestamp.some,
          headers = header :: headers)
      }
      result.handleErrorWith { cause =>
        JournalError(s"ActionToProducerRecord failed for $action: $cause", cause)
          .raiseError[F, ProducerRecord[String, ByteVector]]
      }
    }
  }
} 
Example 23
Source File: HeaderToTuple.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal.conversions

import cats.implicits._
import com.evolutiongaming.catshelper.ApplicativeThrowable
import com.evolutiongaming.kafka.journal.{FromBytes, JournalError}
import com.evolutiongaming.skafka.Header
import scodec.bits.ByteVector

trait HeaderToTuple[F[_]] {

  def apply(header: Header): F[(String, String)]
}

object HeaderToTuple {

  implicit def apply[F[_] : ApplicativeThrowable](implicit
    stringFromBytes: FromBytes[F, String],
  ): HeaderToTuple[F] = {
    header: Header => {
      val bytes = ByteVector.view(header.value)
      stringFromBytes(bytes)
        .map { value => (header.key, value) }
        .adaptErr { case e => JournalError(s"HeaderToTuple failed for $header: $e", e) }
    }
  }
} 
Example 24
Source File: JsonCodecTest.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal

import cats.implicits._
import org.scalatest.FunSuite
import org.scalatest.matchers.should.Matchers
import play.api.libs.json.{JsString, Json}
import scodec.bits.ByteVector

import scala.util.{Failure, Try}

class JsonCodecTest extends FunSuite with Matchers {

  private val malformed = ByteVector.view(Json.toBytes(JsString("\ud83d\ude18\ud83d")))

  test("JsonCodec.jsoniter") {

    JsonCodec.jsoniter[Try].decode.fromBytes(malformed) should matchPattern {
      case Failure(_: JournalError) =>
    }
  }

  test("JsonCodec.playJson") {
    JsonCodec.playJson[Try].decode.fromBytes(malformed).isSuccess shouldEqual true
  }

  test("JsonCodec.default") {
    JsonCodec.default[Try].decode.fromBytes(malformed).isSuccess shouldEqual true
  }
} 
Example 25
Source File: PayloadSpec.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal

import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers
import play.api.libs.json.JsString
import scodec.bits.ByteVector

class PayloadSpec extends AnyFunSuite with Matchers {

  test("apply text") {
    Payload("text") shouldEqual Payload.text("text")
  }

  test("apply binary") {
    Payload(ByteVector.empty) shouldEqual Payload.binary(ByteVector.empty)
  }

  test("apply json") {
    Payload(JsString("json")) shouldEqual Payload.json(JsString("json"))
  }
} 
Example 26
Source File: EventsTest.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal

import cats.data.{NonEmptyList => Nel}
import cats.implicits._
import com.evolutiongaming.kafka.journal.Event._
import com.evolutiongaming.kafka.journal.util.ScodecHelper.{nelCodec, _}
import org.scalatest.FunSuite
import org.scalatest.matchers.should.Matchers
import scodec.bits.ByteVector
import scodec.{Attempt, codecs}

import scala.util.Try

class EventsTest extends FunSuite with Matchers {

  test("decode newer version") {
    implicit val jsonCodec = JsonCodec.jsoniter[Try]
    val codec = {
      val eventsCodec = nelCodec(codecs.listOfN(codecs.int32, codecs.variableSizeBytes(codecs.int32, Event.codecEventPayload)))
      val version = ByteVector.fromByte(100)
      (codecs.constant(version) ~> eventsCodec)
        .xmap[Events[Payload]](a => Events(a, PayloadMetadata.empty), _.events)
    }

    val events = Events(Nel.of(Event(SeqNr.min, payload = Payload.text("text").some)), PayloadMetadata.empty)
    val actual = for {
      bits   <- codec.encode(events)
      result <- Events.codecEvents[Payload].decode(bits)
    } yield {
      result.value
    }
    actual shouldEqual events.pure[Attempt]
  }
} 
Example 27
Source File: EventualPayloadAndTypeSpec.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal.eventual


import cats.implicits._
import com.evolutiongaming.kafka.journal._
import org.scalatest.EitherValues
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers
import play.api.libs.json.{Json => PlayJson}
import scodec.bits.ByteVector

import scala.util.Try

class EventualPayloadAndTypeSpec extends AnyFunSuite with Matchers with EitherValues {

  implicit val jsonCodec: JsonCodec[Try] = JsonCodec.default[Try]

  private val eventualWrite = EventualWrite.summon[Try, Payload]
  private val eventualRead = EventualRead.summon[Try, Payload]

  for {
    (name, payload) <- List(
      ("text", Payload.text("text")),
      ("binary", PayloadBinaryFromStr("binary")),
      ("json", Payload.json("json"))
    )
  } {
    test(s"toEventual & fromEventual, payload: $name") {
      val actual = for {
        payloadAndType <- eventualWrite(payload)
        actual <- eventualRead(payloadAndType)
      } yield actual

      actual shouldBe payload.pure[Try]
    }
  }

  test("toEventual: binary") {
    val payload = PayloadBinaryFromStr("binary")

    val eventual = eventualWrite(payload)

    eventual shouldBe EventualPayloadAndType(payload.value.asRight, PayloadType.Binary).pure[Try]
  }

  test("toEventual: text") {
    val payload = Payload.Text("text")

    val eventual = eventualWrite(payload)

    eventual shouldBe EventualPayloadAndType("text".asLeft, PayloadType.Text).pure[Try]
  }

  test("toEventual: json") {
    val payload = Payload.Json(PlayJson.obj("key" -> "value"))

    val eventual = eventualWrite(payload)

    eventual shouldBe EventualPayloadAndType("""{"key":"value"}""".asLeft, PayloadType.Json).pure[Try]
  }

  test("fromEventual: returns an error for payload type binary and payload string") {
    val payloadAndType = EventualPayloadAndType("text".asLeft, PayloadType.Binary)

    val result = eventualRead(payloadAndType).toEither

    result.left.value shouldBe a[JournalError]
    result.left.value.getMessage should include("Bytes expected")
  }

  test("fromEventual: returns an error for payload type text and payload bytes") {
    val payloadAndType = EventualPayloadAndType(ByteVector.empty.asRight, PayloadType.Text)

    val result = eventualRead(payloadAndType).toEither

    result.left.value shouldBe a[JournalError]
    result.left.value.getMessage should include("String expected")
  }

  test("fromEventual: returns an error for payload type json and payload bytes") {
    val payloadAndType = EventualPayloadAndType(ByteVector.empty.asRight, PayloadType.Json)

    val result = eventualRead(payloadAndType).toEither

    result.left.value shouldBe a[JournalError]
    result.left.value.getMessage should include("String expected")
  }
} 
Example 28
Source File: ByteVectorOf.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal

import cats.Monad
import cats.implicits._
import com.evolutiongaming.kafka.journal.util.CatsHelper._
import com.evolutiongaming.kafka.journal.util.Fail
import scodec.bits.ByteVector

object ByteVectorOf {

  def apply[F[_] : Monad : Fail](clazz: Class[_], path: String): F[ByteVector] = {
    for {
      is <- Option(clazz.getResourceAsStream(path)).getOrError[F](s"file not found at $path")
    } yield {
      val bytes = new Array[Byte](is.available())
      is.read(bytes)
      ByteVector.view(bytes)
    }
  }
} 
Example 29
Source File: PersistentBinaryToBytesSpec.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package akka.persistence.kafka.journal

import cats.implicits._
import com.evolutiongaming.kafka.journal.FromBytes.implicits._
import com.evolutiongaming.kafka.journal.ToBytes.implicits._
import com.evolutiongaming.kafka.journal.ByteVectorOf
import com.evolutiongaming.serialization.SerializedMsg
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers
import scodec.bits.ByteVector

import scala.util.{Success, Try}

class PersistentBinaryToBytesSpec extends AnyFunSuite with Matchers {
  import PersistentBinaryToBytesSpec._

  test("toBytes & fromBytes") {

    val expected = PersistentBinary(
      manifest = "persistentManifest".some,
      writerUuid = "writerUuid",
      payload = SerializedMsg(
        identifier = 2,
        manifest = "manifest",
        bytes = "payload".encodeStr))

    def verify(bytes: ByteVector) = {
      val actual = bytes.fromBytes[Try, PersistentBinary]
      actual shouldEqual Success(expected)
    }

    verify(expected.toBytes[Try].get)
    verify(ByteVectorOf[Try](getClass, "PersistentBinary.bin").get)
  }
}

object PersistentBinaryToBytesSpec {

  implicit class StrOps(val self: String) extends AnyVal {
    
    def encodeStr: ByteVector = {
      ByteVector
        .encodeUtf8(self)
        .fold(throw _, identity)
    }
  }
} 
Example 30
Source File: Event.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal

import cats._
import cats.implicits._
import scodec.bits.ByteVector
import scodec.{Attempt, Codec, Err, codecs}

import scala.util.Try

final case class Event[A](
  seqNr: SeqNr,
  tags: Tags = Tags.empty,
  payload: Option[A] = None)

object Event {

  implicit def codecEvent[A](implicit payloadCodec: Codec[Option[A]]): Codec[Event[A]] =
    (SeqNr.codecSeqNr :: Tags.codecTags :: payloadCodec).as[Event[A]]

  implicit def codecEventPayload(implicit jsonCodec: JsonCodec[Try]): Codec[Event[Payload]] = {

    val codecJson: Codec[Payload.Json] = Payload.Json.codecJson

    implicit val payloadCodec: Codec[Option[Payload]] = {

      val errEmpty = Err("")

      def codecSome[A](implicit codec: Codec[A]) = {
        codec.exmap[Option[A]](
          a => Attempt.successful(a.some),
          a => Attempt.fromOption(a, errEmpty))
      }

      def codecOpt[A](payloadType: Byte, codec: Codec[Option[A]]) = {
        val byteVector = ByteVector.fromByte(payloadType)
        codecs.constant(byteVector) ~> codecs.variableSizeBytes(codecs.int32, codec)
      }

      val emptyCodec = codecOpt(0, codecs.provide(none[Payload]))

      val binaryCodec = codecOpt(1, codecSome[Payload.Binary])

      val jsonCodec = codecOpt(2, codecSome[Payload.Json](codecJson))

      val textCodec = codecOpt(3, codecSome[Payload.Text])

      codecs.choice[Option[Payload]](
        binaryCodec.upcast,
        jsonCodec.upcast,
        textCodec.upcast,
        emptyCodec)
    }

    codecEvent[Payload]
  }

  implicit val traverseEvent: Traverse[Event] = new Traverse[Event] {
    override def traverse[G[_] : Applicative, A, B](fa: Event[A])(f: A => G[B]): G[Event[B]] =
      fa.payload.traverse(f)
        .map(newPayload => fa.copy(payload = newPayload))

    override def foldLeft[A, B](fa: Event[A], b: B)(f: (B, A) => B): B =
      fa.payload.fold(b)(a => f(b, a))

    override def foldRight[A, B](fa: Event[A], lb: Eval[B])(f: (A, Eval[B]) => Eval[B]): Eval[B] =
      fa.payload.fold(lb)(a => f(a, lb))
  }
} 
Example 31
Source File: Instances.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal.circe

import java.nio.charset.StandardCharsets

import cats.implicits._
import com.evolutiongaming.catshelper._
import com.evolutiongaming.kafka.journal.PayloadAndType._
import com.evolutiongaming.kafka.journal._
import com.evolutiongaming.kafka.journal.circe.Codecs._
import com.evolutiongaming.kafka.journal.conversions._
import com.evolutiongaming.kafka.journal.eventual.EventualRead
import io.circe._
import io.circe.jawn._
import io.circe.syntax._
import scodec.bits.ByteVector

object Instances {

  implicit def kafkaWrite[F[_] : MonadThrowable](
    implicit payloadJsonToBytes: ToBytes[F, PayloadJson[Json]]
  ): KafkaWrite[F, Json] =
    KafkaWrite.writeJson(EventJsonPayloadAndType(_, PayloadType.Json), payloadJsonToBytes)

  implicit def kafkaRead[F[_] : MonadThrowable](
    implicit payloadJsonFromBytes: FromBytes[F, PayloadJson[Json]]
  ): KafkaRead[F, Json] =
    KafkaRead.readJson(payloadJsonFromBytes, (json: EventJsonPayloadAndType[Json]) => json.payload.pure[F])

  implicit def eventualRead[F[_] : MonadThrowable]: EventualRead[F, Json] =
    EventualRead.readJson(str => FromCirceResult.summon[F].apply(parse(str)))

  implicit def payloadJsonToBytes[F[_]: FromTry]: ToBytes[F, PayloadJson[Json]] = fromEncoder

  implicit def payloadJsonFromBytes[F[_]: ApplicativeThrowable]: FromBytes[F, PayloadJson[Json]] = fromDecoder

  private def fromEncoder[F[_] : FromTry, A : Encoder]: ToBytes[F, A] =
    a => FromTry[F].unsafe {
      val json = a.asJson
      val byteBuffer = Printer.noSpaces.printToByteBuffer(json, StandardCharsets.UTF_8)
      ByteVector.view(byteBuffer)
    }

  private def fromDecoder[F[_] : ApplicativeThrowable, A : Decoder]: FromBytes[F, A] =
    bytes =>
      FromCirceResult.summon[F].apply(decodeByteBuffer[A](bytes.toByteBuffer))
        .adaptErr { case e => JournalError(s"Failed to parse $bytes json: $e", e) }

} 
Example 32
Source File: EventualPayloadAndTypeSpec.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal.circe

import cats.implicits._
import com.evolutiongaming.kafka.journal.TestJsonCodec.instance
import com.evolutiongaming.kafka.journal._
import com.evolutiongaming.kafka.journal.circe.Instances._
import com.evolutiongaming.kafka.journal.eventual._
import io.circe.{Json => CirceJson}
import org.scalatest.EitherValues
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers
import play.api.libs.json.{Json => PlayJson}
import scodec.bits.ByteVector

import scala.util.Try

class EventualPayloadAndTypeSpec extends AnyFunSuite with Matchers with EitherValues {

  private val playEventualWrite = EventualWrite.summon[Try, Payload]
  private val circeEventualRead = EventualRead.summon[Try, CirceJson]

  for {
    (playPayload, circePayload) <- List(
      (Payload.json(PlayJson.obj(("key", "value"))), CirceJson.obj("key" -> CirceJson.fromString("value")))
    )
  } {
    test(s"toEventual with Play, fromEventual with Circe") {
      val actual = for {
        payloadAndType <- playEventualWrite(playPayload)
        actual         <- circeEventualRead(payloadAndType)
      } yield actual

      actual shouldBe circePayload.pure[Try]
    }
  }

  for {
    (name, payloadAndType) <- List(
      ("binary", EventualPayloadAndType(ByteVector.empty.asRight, PayloadType.Binary)),
      ("text", EventualPayloadAndType("text".asLeft, PayloadType.Text))
    )
  } {
    test(s"fromEventual: returns an error for non-json payload type: $name") {
      val result = circeEventualRead(payloadAndType).toEither

      result.left.value shouldBe a[JournalError]
      result.left.value.getMessage should include(payloadAndType.payloadType.toString)
    }
  }

  test("fromEventual: returns an error for payload type json and payload bytes") {
    val payloadAndType = EventualPayloadAndType(ByteVector.empty.asRight, PayloadType.Json)

    val result = circeEventualRead(payloadAndType).toEither

    result.left.value shouldBe a[JournalError]
    result.left.value.getMessage should include("String expected")
  }

  test("fromEventual: returns an error for malformed json") {
    val malformed = "{\"key\": {sss}}"
    val payloadAndType = EventualPayloadAndType(malformed.asLeft, PayloadType.Json)

    val result = circeEventualRead(payloadAndType).toEither

    result.left.value shouldBe a[JournalError]
    result.left.value.getMessage should (include("ParsingFailure") and include("sss"))
  }

} 
Example 33
Source File: Binary.scala    From docspell   with GNU General Public License v3.0 5 votes vote down vote up
package docspell.common

import java.nio.charset.Charset
import java.nio.charset.StandardCharsets

import cats.effect._
import fs2.{Chunk, Pipe, Stream}

import scodec.bits.ByteVector

final case class Binary[F[_]](name: String, mime: MimeType, data: Stream[F, Byte]) {

  def withMime(mime: MimeType): Binary[F] =
    copy(mime = mime)
}

object Binary {

  def apply[F[_]](name: String, data: Stream[F, Byte]): Binary[F] =
    Binary[F](name, MimeType.octetStream, data)

  def utf8[F[_]](name: String, content: String): Binary[F] =
    Binary[F](
      name,
      MimeType.octetStream,
      Stream.emit(content).through(fs2.text.utf8Encode)
    )

  def text[F[_]](name: String, content: String): Binary[F] =
    utf8(name, content).withMime(MimeType.plain.withUtf8Charset)

  def text[F[_]](name: String, content: ByteVector, cs: Charset): Binary[F] =
    Binary(name, MimeType.plain.withCharset(cs), Stream.chunk(Chunk.byteVector(content)))

  def html[F[_]](name: String, content: String): Binary[F] =
    utf8(name, content).withMime(MimeType.html.withUtf8Charset)

  def html[F[_]](name: String, content: ByteVector, cs: Charset): Binary[F] =
    Binary(name, MimeType.html.withCharset(cs), Stream.chunk(Chunk.byteVector(content)))

  def decode[F[_]](cs: Charset): Pipe[F, Byte, String] =
    if (cs == StandardCharsets.UTF_8)
      fs2.text.utf8Decode
    else
      util.decode[F](cs)

  def loadAllBytes[F[_]: Sync](data: Stream[F, Byte]): F[ByteVector] =
    data.chunks.map(_.toByteVector).compile.fold(ByteVector.empty)((r, e) => r ++ e)

  // This is a copy from org.http4s.util
  // Http4s is licensed under the Apache License 2.0
  private object util {
    import fs2._
    import java.nio._

    private val utf8Bom: Chunk[Byte] = Chunk(0xef.toByte, 0xbb.toByte, 0xbf.toByte)

    def decode[F[_]](charset: Charset): Pipe[F, Byte, String] = {
      val decoder         = charset.newDecoder
      val maxCharsPerByte = math.ceil(decoder.maxCharsPerByte().toDouble).toInt
      val avgBytesPerChar = math.ceil(1.0 / decoder.averageCharsPerByte().toDouble).toInt
      val charBufferSize  = 128

      _.repeatPull[String] {
        _.unconsN(charBufferSize * avgBytesPerChar, allowFewer = true).flatMap {
          case None =>
            val charBuffer = CharBuffer.allocate(1)
            decoder.decode(ByteBuffer.allocate(0), charBuffer, true)
            decoder.flush(charBuffer)
            val outputString = charBuffer.flip().toString
            if (outputString.isEmpty) Pull.done.as(None)
            else Pull.output1(outputString).as(None)
          case Some((chunk, stream)) =>
            if (chunk.nonEmpty) {
              val chunkWithoutBom = skipByteOrderMark(chunk)
              val bytes           = chunkWithoutBom.toArray
              val byteBuffer      = ByteBuffer.wrap(bytes)
              val charBuffer      = CharBuffer.allocate(bytes.length * maxCharsPerByte)
              decoder.decode(byteBuffer, charBuffer, false)
              val nextStream = stream.consChunk(Chunk.byteBuffer(byteBuffer.slice()))
              Pull.output1(charBuffer.flip().toString).as(Some(nextStream))
            } else
              Pull.output(Chunk.empty[String]).as(Some(stream))
        }
      }
    }

    private def skipByteOrderMark[F[_]](chunk: Chunk[Byte]): Chunk[Byte] =
      if (chunk.size >= 3 && chunk.take(3) == utf8Bom)
        chunk.drop(3)
      else chunk

  }
} 
Example 34
Source File: Ident.scala    From docspell   with GNU General Public License v3.0 5 votes vote down vote up
package docspell.common

import java.security.SecureRandom
import java.util.UUID

import cats.Eq
import cats.effect.Sync
import cats.implicits._

import io.circe.{Decoder, Encoder}
import scodec.bits.ByteVector

case class Ident(id: String) {
  def isEmpty: Boolean =
    id.trim.isEmpty

  def nonEmpty: Boolean =
    !isEmpty

  def /(next: Ident): Ident =
    new Ident(id + "." + next.id)
}

object Ident {
  implicit val identEq: Eq[Ident] =
    Eq.by(_.id)

  val chars: Set[Char] = (('A' to 'Z') ++ ('a' to 'z') ++ ('0' to '9') ++ "-_.").toSet

  def randomUUID[F[_]: Sync]: F[Ident] =
    Sync[F].delay(unsafe(UUID.randomUUID.toString))

  def randomId[F[_]: Sync]: F[Ident] =
    Sync[F].delay {
      val random = new SecureRandom()
      val buffer = new Array[Byte](32)
      random.nextBytes(buffer)
      unsafe(ByteVector.view(buffer).toBase58.grouped(11).mkString("-"))
    }

  def apply(str: String): Either[String, Ident] =
    fromString(str)

  def fromString(s: String): Either[String, Ident] =
    if (s.forall(chars.contains)) Right(new Ident(s))
    else Left(s"Invalid identifier: '$s'. Allowed chars: ${chars.toList.sorted.mkString}")

  def fromBytes(bytes: ByteVector): Ident =
    unsafe(bytes.toBase58)

  def fromByteArray(bytes: Array[Byte]): Ident =
    fromBytes(ByteVector.view(bytes))

  def unsafe(s: String): Ident =
    fromString(s) match {
      case Right(id) => id
      case Left(err) => sys.error(err)
    }

  def unapply(arg: String): Option[Ident] =
    fromString(arg).toOption

  implicit val encodeIdent: Encoder[Ident] =
    Encoder.encodeString.contramap(_.id)

  implicit val decodeIdent: Decoder[Ident] =
    Decoder.decodeString.emap(Ident.fromString)

} 
Example 35
Source File: Implicits.scala    From docspell   with GNU General Public License v3.0 5 votes vote down vote up
package docspell.common.config

import scala.reflect.ClassTag

import docspell.common._

import com.github.eikek.calev.CalEvent
import pureconfig._
import pureconfig.error.{CannotConvert, FailureReason}
import scodec.bits.ByteVector

object Implicits {
  implicit val lenientUriReader: ConfigReader[LenientUri] =
    ConfigReader[String].emap(reason(LenientUri.parse))

  implicit val durationReader: ConfigReader[Duration] =
    ConfigReader[scala.concurrent.duration.Duration].map(sd => Duration(sd))

  implicit val passwordReader: ConfigReader[Password] =
    ConfigReader[String].map(Password(_))

  implicit val mimeTypeReader: ConfigReader[MimeType] =
    ConfigReader[String].emap(reason(MimeType.parse))

  implicit val identReader: ConfigReader[Ident] =
    ConfigReader[String].emap(reason(Ident.fromString))

  implicit val byteVectorReader: ConfigReader[ByteVector] =
    ConfigReader[String].emap(reason { str =>
      if (str.startsWith("hex:"))
        ByteVector.fromHex(str.drop(4)).toRight("Invalid hex value.")
      else if (str.startsWith("b64:"))
        ByteVector.fromBase64(str.drop(4)).toRight("Invalid Base64 string.")
      else
        ByteVector
          .encodeUtf8(str)
          .left
          .map(ex => s"Invalid utf8 string: ${ex.getMessage}")
    })

  implicit val caleventReader: ConfigReader[CalEvent] =
    ConfigReader[String].emap(reason(CalEvent.parse))

  implicit val priorityReader: ConfigReader[Priority] =
    ConfigReader[String].emap(reason(Priority.fromString))

  def reason[A: ClassTag](
      f: String => Either[String, A]
  ): String => Either[FailureReason, A] =
    in =>
      f(in).left.map(str =>
        CannotConvert(in, implicitly[ClassTag[A]].runtimeClass.toString, str)
      )
} 
Example 36
Source File: AuthToken.scala    From docspell   with GNU General Public License v3.0 5 votes vote down vote up
package docspell.backend.auth

import java.time.Instant
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec

import cats.effect._
import cats.implicits._

import docspell.backend.Common
import docspell.backend.auth.AuthToken._
import docspell.common._

import scodec.bits.ByteVector

case class AuthToken(millis: Long, account: AccountId, salt: String, sig: String) {
  def asString = s"$millis-${b64enc(account.asString)}-$salt-$sig"

  def sigValid(key: ByteVector): Boolean = {
    val newSig = AuthToken.sign(this, key)
    AuthToken.constTimeEq(sig, newSig)
  }
  def sigInvalid(key: ByteVector): Boolean =
    !sigValid(key)

  def notExpired(validity: Duration): Boolean =
    !isExpired(validity)

  def isExpired(validity: Duration): Boolean = {
    val ends = Instant.ofEpochMilli(millis).plusMillis(validity.millis)
    Instant.now.isAfter(ends)
  }

  def validate(key: ByteVector, validity: Duration): Boolean =
    sigValid(key) && notExpired(validity)
}

object AuthToken {
  private val utf8 = java.nio.charset.StandardCharsets.UTF_8

  def fromString(s: String): Either[String, AuthToken] =
    s.split("\\-", 4) match {
      case Array(ms, as, salt, sig) =>
        for {
          millis <- asInt(ms).toRight("Cannot read authenticator data")
          acc    <- b64dec(as).toRight("Cannot read authenticator data")
          accId  <- AccountId.parse(acc)
        } yield AuthToken(millis, accId, salt, sig)

      case _ =>
        Left("Invalid authenticator")
    }

  def user[F[_]: Sync](accountId: AccountId, key: ByteVector): F[AuthToken] =
    for {
      salt <- Common.genSaltString[F]
      millis = Instant.now.toEpochMilli
      cd     = AuthToken(millis, accountId, salt, "")
      sig    = sign(cd, key)
    } yield cd.copy(sig = sig)

  private def sign(cd: AuthToken, key: ByteVector): String = {
    val raw = cd.millis.toString + cd.account.asString + cd.salt
    val mac = Mac.getInstance("HmacSHA1")
    mac.init(new SecretKeySpec(key.toArray, "HmacSHA1"))
    ByteVector.view(mac.doFinal(raw.getBytes(utf8))).toBase64
  }

  private def b64enc(s: String): String =
    ByteVector.view(s.getBytes(utf8)).toBase64

  private def b64dec(s: String): Option[String] =
    ByteVector.fromValidBase64(s).decodeUtf8.toOption

  private def asInt(s: String): Option[Long] =
    Either.catchNonFatal(s.toLong).toOption

  private def constTimeEq(s1: String, s2: String): Boolean =
    s1.zip(s2)
      .foldLeft(true)({ case (r, (c1, c2)) => r & c1 == c2 }) & s1.length == s2.length

} 
Example 37
Source File: Login.scala    From docspell   with GNU General Public License v3.0 5 votes vote down vote up
package docspell.backend.auth

import cats.effect._
import cats.implicits._

import docspell.backend.auth.Login._
import docspell.common._
import docspell.store.Store
import docspell.store.queries.QLogin
import docspell.store.records.RUser

import org.log4s._
import org.mindrot.jbcrypt.BCrypt
import scodec.bits.ByteVector

trait Login[F[_]] {

  def loginSession(config: Config)(sessionKey: String): F[Result]

  def loginUserPass(config: Config)(up: UserPass): F[Result]

}

object Login {
  private[this] val logger = getLogger

  case class Config(serverSecret: ByteVector, sessionValid: Duration)

  case class UserPass(user: String, pass: String) {
    def hidePass: UserPass =
      if (pass.isEmpty) copy(pass = "<none>")
      else copy(pass = "***")
  }

  sealed trait Result {
    def toEither: Either[String, AuthToken]
  }
  object Result {
    case class Ok(session: AuthToken) extends Result {
      val toEither = Right(session)
    }
    case object InvalidAuth extends Result {
      val toEither = Left("Authentication failed.")
    }
    case object InvalidTime extends Result {
      val toEither = Left("Authentication failed.")
    }

    def ok(session: AuthToken): Result = Ok(session)
    def invalidAuth: Result            = InvalidAuth
    def invalidTime: Result            = InvalidTime
  }

  def apply[F[_]: Effect](store: Store[F]): Resource[F, Login[F]] =
    Resource.pure[F, Login[F]](new Login[F] {

      def loginSession(config: Config)(sessionKey: String): F[Result] =
        AuthToken.fromString(sessionKey) match {
          case Right(at) =>
            if (at.sigInvalid(config.serverSecret)) Result.invalidAuth.pure[F]
            else if (at.isExpired(config.sessionValid)) Result.invalidTime.pure[F]
            else Result.ok(at).pure[F]
          case Left(_) =>
            Result.invalidAuth.pure[F]
        }

      def loginUserPass(config: Config)(up: UserPass): F[Result] =
        AccountId.parse(up.user) match {
          case Right(acc) =>
            val okResult =
              store.transact(RUser.updateLogin(acc)) *>
                AuthToken.user(acc, config.serverSecret).map(Result.ok)
            for {
              data <- store.transact(QLogin.findUser(acc))
              _    <- Sync[F].delay(logger.trace(s"Account lookup: $data"))
              res <-
                if (data.exists(check(up.pass))) okResult
                else Result.invalidAuth.pure[F]
            } yield res
          case Left(_) =>
            Result.invalidAuth.pure[F]
        }

      private def check(given: String)(data: QLogin.Data): Boolean = {
        val collOk = data.collectiveState == CollectiveState.Active ||
          data.collectiveState == CollectiveState.ReadOnly
        val userOk = data.userState == UserState.Active
        val passOk = BCrypt.checkpw(given, data.password.pass)
        collOk && userOk && passOk
      }
    })
} 
Example 38
Source File: Generators.scala    From eclair   with Apache License 2.0 5 votes vote down vote up
package fr.acinq.eclair.crypto

import fr.acinq.bitcoin.Crypto.{PrivateKey, PublicKey}
import fr.acinq.bitcoin.{ByteVector32, Crypto}
import scodec.bits.ByteVector


object Generators {

  def fixSize(data: ByteVector): ByteVector32 = data.length match {
    case 32 => ByteVector32(data)
    case length if length < 32 => ByteVector32(data.padLeft(32))
  }

  def perCommitSecret(seed: ByteVector32, index: Long): PrivateKey = PrivateKey(ShaChain.shaChainFromSeed(seed, 0xFFFFFFFFFFFFL - index))

  def perCommitPoint(seed: ByteVector32, index: Long): PublicKey = perCommitSecret(seed, index).publicKey

  def derivePrivKey(secret: PrivateKey, perCommitPoint: PublicKey): PrivateKey = {
    // secretkey = basepoint-secret + SHA256(per-commitment-point || basepoint)
    secret.add(PrivateKey(Crypto.sha256(perCommitPoint.value ++ secret.publicKey.value)))
  }

  def derivePubKey(basePoint: PublicKey, perCommitPoint: PublicKey): PublicKey = {
    //pubkey = basepoint + SHA256(per-commitment-point || basepoint)*G
    val a = PrivateKey(Crypto.sha256(perCommitPoint.value ++ basePoint.value))
    basePoint.add(a.publicKey)
  }

  def revocationPubKey(basePoint: PublicKey, perCommitPoint: PublicKey): PublicKey = {
    val a = PrivateKey(Crypto.sha256(basePoint.value ++ perCommitPoint.value))
    val b = PrivateKey(Crypto.sha256(perCommitPoint.value ++ basePoint.value))
    basePoint.multiply(a).add(perCommitPoint.multiply(b))
  }

  def revocationPrivKey(secret: PrivateKey, perCommitSecret: PrivateKey): PrivateKey = {
    val a = PrivateKey(Crypto.sha256(secret.publicKey.value ++ perCommitSecret.publicKey.value))
    val b = PrivateKey(Crypto.sha256(perCommitSecret.publicKey.value ++ secret.publicKey.value))
    secret.multiply(a).add(perCommitSecret.multiply(b))
  }

} 
Example 39
Source File: HmacAuthMiddlewareSpec.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.network.http.server.middleware

import java.time.Instant

import cats.Id
import cats.effect.IO
import cats.implicits._
import jbok.common.CommonSpec
import jbok.network.http.server.authentication.HMAC
import org.http4s.dsl.io._
import org.http4s.headers.Authorization
import org.http4s.implicits._
import org.http4s.{AuthScheme, Credentials, Header, HttpRoutes, Request, Status, Uri}
import scodec.bits.ByteVector
import tsec.mac.jca.{HMACSHA256, MacSigningKey}

import scala.concurrent.duration._

class HmacAuthMiddlewareSpec extends CommonSpec {
  "HmacAuthMiddleware" should {
    val key = HMACSHA256.buildKey[Id](
      ByteVector.fromValidHex("70ea14ac30939a972b5a67cab952d6d7d474727b05fe7f9283abc1e505919e83").toArray
    )

    def sign(url: String): (String, String) = {
      val datetime  = Instant.now().toString
      val signature = HMAC.http.signForHeader("GET", url, datetime, key).unsafeRunSync()
      (signature, datetime)
    }

    val routes = HttpRoutes.of[IO] {
      case GET -> Root / "ping" => Ok("pong")
    }

    val service = routes.orNotFound
    val req     = Request[IO](uri = Uri.uri("/ping"))
    service.run(req).unsafeRunSync().status shouldBe Status.Ok
    val authedService = HmacAuthMiddleware(key)(routes).orNotFound

    "403 if no Authorization header" in {
      val resp = authedService.run(req).unsafeRunSync()
      val text = resp.bodyAsText.compile.foldMonoid.unsafeRunSync()
      resp.status shouldBe Status.Forbidden
      text shouldBe HmacAuthError.NoAuthHeader.message
    }

    "403 if no X-Datetime header" in {
      val signature = HMAC.http.signForHeader("GET", "/ping", Instant.now().toString, key).unsafeRunSync()
      val req =
        Request[IO](uri = Uri.uri("/ping")).putHeaders(Authorization(Credentials.Token(AuthScheme.Bearer, signature)))
      val resp = authedService.run(req).unsafeRunSync()
      val text = resp.bodyAsText.compile.foldMonoid.unsafeRunSync()
      resp.status shouldBe Status.Forbidden
      text shouldBe HmacAuthError.NoDatetimeHeader.message
    }

    "403 if time window is closed" in {
      val authedService = HmacAuthMiddleware(key, 2.seconds)(routes).orNotFound
      val now           = Instant.now()
      val signature     = HMAC.http.signForHeader("GET", "/ping", now.toString, key).unsafeRunSync()
      val req =
        Request[IO](uri = Uri.uri("/ping"))
          .putHeaders(
            Authorization(Credentials.Token(AuthScheme.Bearer, signature)),
            Header("X-Datetime", now.toString)
          )

      val resp = authedService.run(req).unsafeRunSync()
      resp.status shouldBe Status.Ok

      IO.sleep(3.seconds).unsafeRunSync()
      val resp2 = authedService.run(req).unsafeRunSync()
      val text  = resp2.bodyAsText.compile.foldMonoid.unsafeRunSync()
      resp2.status shouldBe Status.Forbidden
      text shouldBe HmacAuthError.Timeout.message
    }

    "helper" in {
      val (sig, date) = sign("/v1/blocks")
      println(("Authorization", s"Bearer $sig"))
      println(("X-Datetime", date))
      println(("Random key", ByteVector(MacSigningKey.toJavaKey[HMACSHA256](HMACSHA256.generateKey[Id]).getEncoded).toHex))
    }
  }
} 
Example 40
Source File: PersonalService.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.app.service

import cats.effect.Sync
import cats.implicits._
import jbok.common.math.N
import jbok.core.api.PersonalAPI
import jbok.core.config.HistoryConfig
import jbok.core.keystore.KeyStore
import jbok.core.ledger.History
import jbok.core.models.{Address, Transaction}
import jbok.core.pool.TxPool
import scodec.bits.ByteVector

import scala.util.Try

final class PersonalService[F[_]](
    historyConfig: HistoryConfig,
    keyStore: KeyStore[F],
    history: History[F],
    txPool: TxPool[F]
)(implicit F: Sync[F])
    extends PersonalAPI[F] {

  override def importRawKey(privateKey: ByteVector, passphrase: String): F[Address] =
    keyStore.importPrivateKey(privateKey, passphrase)

  override def newAccount(passphrase: String): F[Address] =
    keyStore.newAccount(passphrase)

  override def delAccount(address: Address): F[Boolean] =
    keyStore.deleteAccount(address)

  override def listAccounts: F[List[Address]] =
    keyStore.listAccounts

  override def sendTransaction(
      from: Address,
      passphrase: String,
      to: Option[Address],
      value: Option[N],
      gasLimit: Option[N],
      gasPrice: Option[N],
      nonce: Option[N],
      data: Option[ByteVector]
  ): F[ByteVector] = {

    val defaultGasPrice: N = 2 * N(10).pow(10)
    val defaultGasLimit: N = N(90000)

    for {
      wallet  <- keyStore.unlockAccount(from, passphrase)
      pending <- txPool.getPendingTransactions
      latestNonceOpt = Try(pending.collect {
        case (stx, _) if stx.senderAddress.contains(wallet.address) => stx.nonce
      }.max).toOption
      bn              <- history.getBestBlockNumber
      currentNonceOpt <- history.getAccount(from, bn).map(_.map(_.nonce.toN))
      maybeNextTxNonce = latestNonceOpt.map(_ + 1).orElse(currentNonceOpt)
      tx = Transaction(
        nonce = nonce.getOrElse(maybeNextTxNonce.getOrElse(historyConfig.accountStartNonce)),
        gasPrice = gasPrice.getOrElse(defaultGasPrice),
        gasLimit = gasLimit.getOrElse(defaultGasLimit),
        receivingAddress = to,
        value = value.getOrElse(N(0)),
        payload = data.getOrElse(ByteVector.empty)
      )
      stx <- wallet.signTx[F](tx, history.chainId)
      _   <- txPool.addOrUpdateTransaction(stx)
    } yield stx.hash
  }

  override def changePassphrase(address: Address, oldPassphrase: String, newPassphrase: String): F[Boolean] =
    keyStore.changePassphrase(address, oldPassphrase, newPassphrase)
} 
Example 41
Source File: AccountService.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.app.service

import cats.effect.Sync
import cats.implicits._
import jbok.app.service.store.TransactionStore
import jbok.common.math.N
import jbok.core.config.HistoryConfig
import jbok.core.ledger.History
import jbok.core.models.{Account, Address, SignedTransaction}
import jbok.core.pool.TxPool
import jbok.core.api.{AccountAPI, BlockTag, HistoryTransaction}
import scodec.bits.ByteVector

final class AccountService[F[_]](config: HistoryConfig, history: History[F], txPool: TxPool[F], helper: ServiceHelper[F], txStore: TransactionStore[F])(implicit F: Sync[F])
    extends AccountAPI[F] {

  override def getAccount(address: Address, tag: BlockTag): F[Account] =
    for {
      account <- helper.resolveAccount(address, tag)
    } yield account

  override def getCode(address: Address, tag: BlockTag): F[ByteVector] =
    for {
      block <- helper.resolveBlock(tag)
      world <- history.getWorldState(config.accountStartNonce, block.map(_.header.stateRoot))
      code  <- world.getCode(address)
    } yield code

  override def getBalance(address: Address, tag: BlockTag): F[N] =
    for {
      account <- helper.resolveAccount(address, tag)
    } yield account.balance.toN

  override def getStorageAt(address: Address, position: N, tag: BlockTag): F[ByteVector] =
    for {
      account <- helper.resolveAccount(address, tag)
      storage <- history.getStorage(account.storageRoot, position)
    } yield storage

  override def getTransactions(address: Address, page: Int, size: Int): F[List[HistoryTransaction]] = {
    val validSize = if (size < 0) 100 else 1000000.min(size)
    txStore.findTransactionsByAddress(address.toString, page.max(1), validSize)
  }

  override def getTransactionsByNumber(number: Int): F[List[HistoryTransaction]] =
    txStore.findTransactionsByNumber(number)

  override def getPendingTxs(address: Address): F[List[SignedTransaction]] =
    txPool.getPendingTransactions.map(_.keys.toList.filter(_.senderAddress.exists(_ == address)))

  override def getEstimatedNonce(address: Address): F[N] =
    for {
      pending <- txPool.getPendingTransactions
      latestNonceOpt = scala.util
        .Try(pending.collect {
          case (stx, _) if stx.senderAddress contains address => stx.nonce
        }.max)
        .toOption
      bn              <- history.getBestBlockNumber
      currentNonceOpt <- history.getAccount(address, bn).map(_.map(_.nonce.toN))
      defaultNonce     = config.accountStartNonce.toN
      maybeNextTxNonce = latestNonceOpt.map(_ + 1).getOrElse(defaultNonce) max currentNonceOpt.getOrElse(defaultNonce)
    } yield maybeNextTxNonce
} 
Example 42
Source File: ContractService.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.app.service

import cats.effect.Sync
import cats.implicits._
import jbok.common.math.N
import jbok.core.ledger.{BlockExecutor, History}
import jbok.core.models.{Address, Block, SignedTransaction, Transaction}
import jbok.core.api.{BlockTag, CallTx, ContractAPI}
import scodec.bits.ByteVector
import spire.syntax.all._
import spire.compat._

final class ContractService[F[_]](history: History[F], executor: BlockExecutor[F], helper: ServiceHelper[F])(implicit F: Sync[F]) extends ContractAPI[F] {
//  override def getABI(address: Address): F[Option[Ast.ContractDef]] = ???
//
//  override def getSourceCode(address: Address): F[Option[String]] = ???

  override def call(callTx: CallTx, tag: BlockTag): F[ByteVector] =
    for {
      (stx, block) <- doCall(callTx, tag)
      txResult     <- executor.simulateTransaction(stx, callTx.from.getOrElse(Address.empty), block.header)
    } yield txResult.vmReturnData

  override def getEstimatedGas(callTx: CallTx, tag: BlockTag): F[N] =
    for {
      (stx, block) <- doCall(callTx, tag)
      gas          <- executor.binarySearchGasEstimation(stx, callTx.from.getOrElse(Address.empty), block.header)
    } yield gas

  override def getGasPrice: F[N] = {
    val blockDifference = N(30)
    for {
      bestBlock <- history.getBestBlockNumber
      gasPrices <- List
        .range(bestBlock - blockDifference, bestBlock)
        .filter(_ >= N(0))
        .traverse(history.getBlockByNumber)
        .map(_.flatten.flatMap(_.body.transactionList).map(_.gasPrice))
      gasPrice = if (gasPrices.nonEmpty) {
        gasPrices.qsum / gasPrices.length
      } else {
        N(0)
      }
    } yield gasPrice
  }

  private def doCall[A](callTx: CallTx, tag: BlockTag): F[(SignedTransaction, Block)] =
    for {
      stx      <- prepareTransaction(callTx, tag)
      blockOpt <- helper.resolveBlock(tag)
      block    <- F.fromOption(blockOpt, new Exception())
    } yield (stx, block)

  private def prepareTransaction(callTx: CallTx, tag: BlockTag): F[SignedTransaction] =
    for {
      gasLimit <- getGasLimit(callTx, tag)
      tx = Transaction(0, callTx.gasPrice, gasLimit, callTx.to, callTx.value, callTx.data)
    } yield SignedTransaction(tx, 0.toByte, ByteVector(0), ByteVector(0))

  private def getGasLimit(callTx: CallTx, tag: BlockTag): F[N] =
    callTx.gas match {
      case Some(gas) => gas.pure[F]
      case None      => helper.resolveBlock(tag).map(_.map(_.header.gasLimit).getOrElse(N(0)))
    }
} 
Example 43
Source File: BlockService.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.app.service

import cats.effect.Concurrent
import cats.implicits._
import jbok.common.math.N
import jbok.core.config.SyncConfig
import jbok.core.ledger.History
import jbok.core.models.{Block, BlockBody, BlockHeader}
import jbok.core.api.BlockAPI
import jbok.core.messages.Status
import scodec.bits.ByteVector
import spire.compat._

final class BlockService[F[_]](history: History[F], config: SyncConfig)(implicit F: Concurrent[F]) extends BlockAPI[F] {
  override def getStatus: F[Status] =
    for {
      genesis <- history.genesisHeader
      number  <- history.getBestBlockNumber
      td      <- history.getTotalDifficultyByNumber(number).map(_.getOrElse(N(0)))
    } yield Status(history.chainId, genesis.hash, number, td, "")

  override def getBestBlockNumber: F[N] =
    history.getBestBlockNumber

  override def getBlockHeaderByNumber(number: N): F[Option[BlockHeader]] =
    history.getBlockHeaderByNumber(number)

  override def getBlockHeadersByNumber(start: N, limit: Int): F[List[BlockHeader]] = {
    val headersCount = math.min(limit, config.maxBlockHeadersPerRequest)
    val range        = List.range(start, start + headersCount)
    range.traverse(history.getBlockHeaderByNumber).map(_.flatten)
  }

  override def getBlockHeaderByHash(hash: ByteVector): F[Option[BlockHeader]] =
    history.getBlockHeaderByHash(hash)

  override def getBlockBodyByHash(hash: ByteVector): F[Option[BlockBody]] =
    history.getBlockBodyByHash(hash)

  override def getBlockBodies(hashes: List[ByteVector]): F[List[BlockBody]] =
    hashes
      .take(config.maxBlockBodiesPerRequest)
      .traverse(hash => history.getBlockBodyByHash(hash))
      .map(_.flatten)

  override def getBlockByNumber(number: N): F[Option[Block]] =
    history.getBlockByNumber(number)

  override def getBlockByHash(hash: ByteVector): F[Option[Block]] =
    history.getBlockByHash(hash)

  override def getTransactionCountByHash(hash: ByteVector): F[Option[Int]] =
    history.getBlockBodyByHash(hash).map(_.map(_.transactionList.length))

  override def getTotalDifficultyByNumber(number: N): F[Option[N]] =
    history.getTotalDifficultyByNumber(number)

  override def getTotalDifficultyByHash(hash: ByteVector): F[Option[N]] =
    history.getTotalDifficultyByHash(hash)
} 
Example 44
Source File: TransactionService.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.app.service

import cats.data.OptionT
import cats.effect.Sync
import cats.implicits._
import jbok.codec.rlp.RlpEncoded
import jbok.core.ledger.History
import jbok.core.models.{Receipt, SignedTransaction}
import jbok.core.pool.TxPool
import jbok.core.api.{BlockTag, TransactionAPI}
import scodec.bits.ByteVector

final class TransactionService[F[_]](history: History[F], txPool: TxPool[F], helper: ServiceHelper[F])(implicit F: Sync[F]) extends TransactionAPI[F] {
  override def getTx(hash: ByteVector): F[Option[SignedTransaction]] =
    (for {
      loc   <- OptionT(history.getTransactionLocation(hash))
      block <- OptionT(history.getBlockByHash(loc.blockHash))
      stx   <- OptionT.fromOption[F](block.body.transactionList.lift(loc.txIndex))
    } yield stx).value

  override def getPendingTx(hash: ByteVector): F[Option[SignedTransaction]] =
    txPool.getPendingTransactions.map(_.keys.toList.find(_.hash == hash))

  override def getReceipt(hash: ByteVector): F[Option[Receipt]] =
    (for {
      loc      <- OptionT(history.getTransactionLocation(hash))
      block    <- OptionT(history.getBlockByHash(loc.blockHash))
      _        <- OptionT.fromOption[F](block.body.transactionList.lift(loc.txIndex))
      receipts <- OptionT(history.getReceiptsByHash(loc.blockHash))
      receipt  <- OptionT.fromOption[F](receipts.lift(loc.txIndex))
    } yield receipt).value

  override def getTxByBlockHashAndIndex(hash: ByteVector, index: Int): F[Option[SignedTransaction]] =
    (for {
      block <- OptionT(history.getBlockByHash(hash))
      stx   <- OptionT.fromOption[F](block.body.transactionList.lift(index))
    } yield stx).value

  override def getTxByBlockTagAndIndex(tag: BlockTag, index: Int): F[Option[SignedTransaction]] =
    (for {
      block <- OptionT(helper.resolveBlock(tag))
      stx   <- OptionT.fromOption[F](block.body.transactionList.lift(index))
    } yield stx).value

  override def sendTx(stx: SignedTransaction): F[ByteVector] =
    txPool.addOrUpdateTransaction(stx).as(stx.hash)

  override def sendRawTx(data: RlpEncoded): F[ByteVector] =
    for {
      stx <- F.fromEither(data.decoded[SignedTransaction])
      _   <- txPool.addOrUpdateTransaction(stx)
    } yield stx.hash
} 
Example 45
Source File: DoobieBlockStore.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.app.service.store.doobie

import cats.effect.Sync
import cats.implicits._
import doobie.implicits._
import doobie.util.transactor.Transactor
import jbok.app.service.store.BlockStore
import jbok.common.math.N
import scodec.bits.ByteVector

final class DoobieBlockStore[F[_]](xa: Transactor[F])(implicit F: Sync[F]) extends BlockStore[F] with DoobieSupport {
  override def getBestBlockNumber: F[Option[N]] =
    sql"""
      SELECT blockNumber
      FROM blocks
      ORDER BY blockNumber DESC
      LIMIT 1
      """
      .query[N]
      .option
      .transact(xa)

  override def getBestBlockNumberAndHash: F[(N, ByteVector)] =
    sql"""
      SELECT blockNumber, blockHash
      FROM blocks
      ORDER BY blockNumber DESC
      LIMIT 1
      """
      .query[(N, ByteVector)]
      .unique
      .transact(xa)

  override def getBlockHashByNumber(number: N): F[Option[ByteVector]] =
    sql"""
      SELECT blockHash
      FROM blocks
      WHERE blockNumber = $number
      """
      .query[ByteVector]
      .option
      .transact(xa)

  override def delByBlockNumber(number: N): F[Unit] =
    sql"""
      DELETE FROM blocks where blockNumber = $number
      """.update.run
      .transact(xa)
      .void

  override def insert(number: N, hash: ByteVector): F[Unit] =
    sql"""
      INSERT INTO blocks (blockNumber, blockHash) VALUES ($number, $hash)
      """.update.run.void.transact(xa)
} 
Example 46
Source File: TransactionAPISpec.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.app.service

import cats.effect.IO
import jbok.app.AppSpec
import jbok.core.StatefulGen
import jbok.core.api.{BlockTag, TransactionAPI}
import jbok.core.ledger.History
import jbok.core.mining.BlockMiner
import jbok.core.models.{Address, SignedTransaction, Transaction}
import scodec.bits.ByteVector

class TransactionAPISpec extends AppSpec {
  "TransactionAPI" should {
    "return tx by hash & number" in check { objects =>
      val history     = objects.get[History[IO]]
      val miner       = objects.get[BlockMiner[IO]]
      val transaction = objects.get[TransactionAPI[IO]]
      val txs         = random(StatefulGen.transactions(10, 10))
      val stx         = txs.head

      for {
        parent <- history.getBestBlock
        _      <- transaction.sendTx(stx)
        res    <- transaction.getTx(stx.hash)
        _ = res shouldBe None
        res <- transaction.getPendingTx(stx.hash)
        _ = res shouldBe Some(stx)
        minedBlock <- miner.mine()
        res        <- transaction.getTx(stx.hash)
        _ = res shouldBe Some(stx)
        res <- transaction.getPendingTx(stx.hash)
        _ = res shouldBe None
        res <- transaction.getReceipt(stx.hash).map(_.nonEmpty)
        _ = res shouldBe true
        res <- transaction.getTxByBlockHashAndIndex(minedBlock.block.header.hash, 0)
        _ = res shouldBe Some(stx)
        res <- transaction getTxByBlockTagAndIndex (BlockTag(1), 0)
        _ = res shouldBe Some(stx)
        res <- transaction.getTxByBlockTagAndIndex(BlockTag.latest, 0)
        _ = res shouldBe Some(stx)
        res <- transaction.getTxByBlockTagAndIndex(BlockTag(2), 0)
        _ = res shouldBe None
      } yield ()
    }

    "return tx by hash & number send a bad stx" in check { objects =>
      val miner       = objects.get[BlockMiner[IO]]
      val transaction = objects.get[TransactionAPI[IO]]

      val tx = Transaction(1, 1, 21000, Some(Address.empty), 100000, ByteVector.empty)

      for {
        stx <- SignedTransaction.sign[IO](tx, testKeyPair, chainId)
        _   <- transaction.sendTx(stx)
        res <- transaction.getTx(stx.hash)
        _ = res shouldBe None
        res <- transaction.getPendingTx(stx.hash)
        _ = res shouldBe Some(stx)
        _   <- miner.mine()
        res <- transaction.getTx(stx.hash)
        _ = res shouldBe None
        res <- transaction.getPendingTx(stx.hash).map(_.isEmpty)
        _ = res shouldBe false
        res <- transaction.getReceipt(stx.hash).map(_.isEmpty)
        _ = res shouldBe true
      } yield ()
    }

    "sendTx" in check { objects =>
      val history     = objects.get[History[IO]]
      val miner       = objects.get[BlockMiner[IO]]
      val transaction = objects.get[TransactionAPI[IO]]

      val stx = random(StatefulGen.transactions(1, 1)).head

      for {
        res <- transaction.sendTx(stx)
        _ = res shouldBe stx.hash
        _   <- miner.mine()
        res <- history.getBestBlock.map(_.body.transactionList.head)
        _ = res shouldBe stx
      } yield ()
    }

    "sendRawTx" in check { objects =>
      val history     = objects.get[History[IO]]
      val miner       = objects.get[BlockMiner[IO]]
      val transaction = objects.get[TransactionAPI[IO]]

      val stx = random(StatefulGen.transactions(1, 1)).head

      for {
        res <- transaction.sendRawTx(stx.bytes)
        _ = res shouldBe stx.hash
        _   <- miner.mine()
        res <- history.getBestBlock.map(_.body.transactionList.head)
        _ = res shouldBe stx
      } yield ()
    }
  }
} 
Example 47
Source File: ContractAPISpec.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.app.service

import cats.effect.IO
import cats.implicits._
import jbok.app.AppSpec
import jbok.common.math.N
import jbok.core.api.{CallTx, ContractAPI}
import jbok.core.mining.BlockMiner
import scodec.bits.ByteVector

class ContractAPISpec extends AppSpec {
  "ContractAPI" should {
    "return gasPrice" in {
      List(15, 45).foreach { blockN =>
        check { objects =>
          val miner    = objects.get[BlockMiner[IO]]
          val contract = objects.get[ContractAPI[IO]]

          for {
            _   <- miner.mineN(blockN)
            res <- contract.getGasPrice
            _ = res shouldBe N(0)
          } yield ()
        }
      }
    }

    "call transaction" in check { objects =>
      val contract = objects.get[ContractAPI[IO]]

      val callTx = CallTx(
        from = None,
        to = None,
        gas = None,
        gasPrice = 0,
        value = 0,
        data = ByteVector.fromValidHex(
          "60806040526040805190810160405280600c81526020017f494f54206f6e20436861696e000000000000000000000000000000000000000081525060009080519060200190620000519291906200010e565b506040805190810160405280600381526020017f4954430000000000000000000000000000000000000000000000000000000000815250600190805190602001906200009f9291906200010e565b506012600255600254600a0a6305f5e10002600355348015620000c157600080fd5b50600354600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550620001bd565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200015157805160ff191683800117855562000182565b8280016001018555821562000182579182015b828111156200018157825182559160200191906001019062000164565b5b50905062000191919062000195565b5090565b620001ba91905b80821115620001b65760008160009055506001016200019c565b5090565b90565b6110c080620001cd6000396000f3006080604052600436106100ba576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100bf578063095ea7b31461014f57806318160ddd146101b457806323b872dd146101df578063313ce5671461026457806342966c681461028f57806370a08231146102d457806379cc67901461032b57806395d89b4114610390578063a9059cbb14610420578063cae9ca511461046d578063dd62ed3e14610518575b600080fd5b3480156100cb57600080fd5b506100d461058f565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101145780820151818401526020810190506100f9565b50505050905090810190601f1680156101415780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561015b57600080fd5b5061019a600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061062d565b604051808215151515815260200191505060405180910390f35b3480156101c057600080fd5b506101c96106ba565b6040518082815260200191505060405180910390f35b3480156101eb57600080fd5b5061024a600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506106c0565b604051808215151515815260200191505060405180910390f35b34801561027057600080fd5b506102796107ed565b6040518082815260200191505060405180910390f35b34801561029b57600080fd5b506102ba600480360381019080803590602001909291905050506107f3565b604051808215151515815260200191505060405180910390f35b3480156102e057600080fd5b50610315600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506108f7565b6040518082815260200191505060405180910390f35b34801561033757600080fd5b50610376600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061090f565b604051808215151515815260200191505060405180910390f35b34801561039c57600080fd5b506103a5610b29565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103e55780820151818401526020810190506103ca565b50505050905090810190601f1680156104125780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561042c57600080fd5b5061046b600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610bc7565b005b34801561047957600080fd5b506104fe600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610bd6565b604051808215151515815260200191505060405180910390f35b34801561052457600080fd5b50610579600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610d59565b6040518082815260200191505060405180910390f35b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156106255780601f106105fa57610100808354040283529160200191610625565b820191906000526020600020905b81548152906001019060200180831161060857829003601f168201915b505050505081565b600081600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506001905092915050565b60035481565b6000600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054821115151561074d57600080fd5b81600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055506107e2848484610d7e565b600190509392505050565b60025481565b600081600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015151561084357600080fd5b81600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816003600082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5836040518082815260200191505060405180910390a260019050919050565b60046020528060005260406000206000915090505481565b600081600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015151561095f57600080fd5b600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482111515156109ea57600080fd5b81600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816003600082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5836040518082815260200191505060405180910390a26001905092915050565b60018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610bbf5780601f10610b9457610100808354040283529160200191610bbf565b820191906000526020600020905b815481529060010190602001808311610ba257829003601f168201915b505050505081565b610bd2338383610d7e565b5050565b600080849050610be6858561062d565b15610d50578073ffffffffffffffffffffffffffffffffffffffff16638f4ffcb1338630876040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610ce0578082015181840152602081019050610cc5565b50505050905090810190601f168015610d0d5780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015610d2f57600080fd5b505af1158015610d43573d6000803e3d6000fd5b5050505060019150610d51565b5b509392505050565b6005602052816000526040600020602052806000526040600020600091509150505481565b6000808373ffffffffffffffffffffffffffffffffffffffff1614151515610da557600080fd5b81600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610df357600080fd5b600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401111515610e8157600080fd5b600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401905081600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a380600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020540114151561108e57fe5b505050505600a165627a7a7230582012e3b4c1ec46ba19f4ea45d28ee4b34b34393f066d96bfc404b036b13c8d0f1b0029")
      )

      for {
        res <- contract.call(callTx)
        _ = res shouldBe ByteVector.fromValidHex(
          "0x6080604052600436106100ba576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100bf578063095ea7b31461014f57806318160ddd146101b457806323b872dd146101df578063313ce5671461026457806342966c681461028f57806370a08231146102d457806379cc67901461032b57806395d89b4114610390578063a9059cbb14610420578063cae9ca511461046d578063dd62ed3e14610518575b600080fd5b3480156100cb57600080fd5b506100d461058f565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101145780820151818401526020810190506100f9565b50505050905090810190601f1680156101415780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561015b57600080fd5b5061019a600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061062d565b604051808215151515815260200191505060405180910390f35b3480156101c057600080fd5b506101c96106ba565b6040518082815260200191505060405180910390f35b3480156101eb57600080fd5b5061024a600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506106c0565b604051808215151515815260200191505060405180910390f35b34801561027057600080fd5b506102796107ed565b6040518082815260200191505060405180910390f35b34801561029b57600080fd5b506102ba600480360381019080803590602001909291905050506107f3565b604051808215151515815260200191505060405180910390f35b3480156102e057600080fd5b50610315600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506108f7565b6040518082815260200191505060405180910390f35b34801561033757600080fd5b50610376600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061090f565b604051808215151515815260200191505060405180910390f35b34801561039c57600080fd5b506103a5610b29565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103e55780820151818401526020810190506103ca565b50505050905090810190601f1680156104125780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561042c57600080fd5b5061046b600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610bc7565b005b34801561047957600080fd5b506104fe600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610bd6565b604051808215151515815260200191505060405180910390f35b34801561052457600080fd5b50610579600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610d59565b6040518082815260200191505060405180910390f35b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156106255780601f106105fa57610100808354040283529160200191610625565b820191906000526020600020905b81548152906001019060200180831161060857829003601f168201915b505050505081565b600081600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506001905092915050565b60035481565b6000600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054821115151561074d57600080fd5b81600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055506107e2848484610d7e565b600190509392505050565b60025481565b600081600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015151561084357600080fd5b81600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816003600082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5836040518082815260200191505060405180910390a260019050919050565b60046020528060005260406000206000915090505481565b600081600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015151561095f57600080fd5b600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482111515156109ea57600080fd5b81600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816003600082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5836040518082815260200191505060405180910390a26001905092915050565b60018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610bbf5780601f10610b9457610100808354040283529160200191610bbf565b820191906000526020600020905b815481529060010190602001808311610ba257829003601f168201915b505050505081565b610bd2338383610d7e565b5050565b600080849050610be6858561062d565b15610d50578073ffffffffffffffffffffffffffffffffffffffff16638f4ffcb1338630876040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610ce0578082015181840152602081019050610cc5565b50505050905090810190601f168015610d0d5780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015610d2f57600080fd5b505af1158015610d43573d6000803e3d6000fd5b5050505060019150610d51565b5b509392505050565b6005602052816000526040600020602052806000526040600020600091509150505481565b6000808373ffffffffffffffffffffffffffffffffffffffff1614151515610da557600080fd5b81600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610df357600080fd5b600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401111515610e8157600080fd5b600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401905081600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a380600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020540114151561108e57fe5b505050505600a165627a7a7230582012e3b4c1ec46ba19f4ea45d28ee4b34b34393f066d96bfc404b036b13c8d0f1b0029")
      } yield ()
    }

    "getEstimatedGas" in check { objects =>
      val contract = objects.get[ContractAPI[IO]]

      val callTx = CallTx(
        from = None,
        to = None,
        gas = None,
        gasPrice = 0,
        value = 0,
        data = ByteVector.fromValidHex(
          "60806040526040805190810160405280600c81526020017f494f54206f6e20436861696e000000000000000000000000000000000000000081525060009080519060200190620000519291906200010e565b506040805190810160405280600381526020017f4954430000000000000000000000000000000000000000000000000000000000815250600190805190602001906200009f9291906200010e565b506012600255600254600a0a6305f5e10002600355348015620000c157600080fd5b50600354600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550620001bd565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200015157805160ff191683800117855562000182565b8280016001018555821562000182579182015b828111156200018157825182559160200191906001019062000164565b5b50905062000191919062000195565b5090565b620001ba91905b80821115620001b65760008160009055506001016200019c565b5090565b90565b6110c080620001cd6000396000f3006080604052600436106100ba576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806306fdde03146100bf578063095ea7b31461014f57806318160ddd146101b457806323b872dd146101df578063313ce5671461026457806342966c681461028f57806370a08231146102d457806379cc67901461032b57806395d89b4114610390578063a9059cbb14610420578063cae9ca511461046d578063dd62ed3e14610518575b600080fd5b3480156100cb57600080fd5b506100d461058f565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156101145780820151818401526020810190506100f9565b50505050905090810190601f1680156101415780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561015b57600080fd5b5061019a600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061062d565b604051808215151515815260200191505060405180910390f35b3480156101c057600080fd5b506101c96106ba565b6040518082815260200191505060405180910390f35b3480156101eb57600080fd5b5061024a600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803590602001909291905050506106c0565b604051808215151515815260200191505060405180910390f35b34801561027057600080fd5b506102796107ed565b6040518082815260200191505060405180910390f35b34801561029b57600080fd5b506102ba600480360381019080803590602001909291905050506107f3565b604051808215151515815260200191505060405180910390f35b3480156102e057600080fd5b50610315600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506108f7565b6040518082815260200191505060405180910390f35b34801561033757600080fd5b50610376600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291908035906020019092919050505061090f565b604051808215151515815260200191505060405180910390f35b34801561039c57600080fd5b506103a5610b29565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156103e55780820151818401526020810190506103ca565b50505050905090810190601f1680156104125780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561042c57600080fd5b5061046b600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190505050610bc7565b005b34801561047957600080fd5b506104fe600480360381019080803573ffffffffffffffffffffffffffffffffffffffff16906020019092919080359060200190929190803590602001908201803590602001908080601f0160208091040260200160405190810160405280939291908181526020018383808284378201915050505050509192919290505050610bd6565b604051808215151515815260200191505060405180910390f35b34801561052457600080fd5b50610579600480360381019080803573ffffffffffffffffffffffffffffffffffffffff169060200190929190803573ffffffffffffffffffffffffffffffffffffffff169060200190929190505050610d59565b6040518082815260200191505060405180910390f35b60008054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156106255780601f106105fa57610100808354040283529160200191610625565b820191906000526020600020905b81548152906001019060200180831161060857829003601f168201915b505050505081565b600081600560003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055506001905092915050565b60035481565b6000600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054821115151561074d57600080fd5b81600560008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825403925050819055506107e2848484610d7e565b600190509392505050565b60025481565b600081600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015151561084357600080fd5b81600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816003600082825403925050819055503373ffffffffffffffffffffffffffffffffffffffff167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5836040518082815260200191505060405180910390a260019050919050565b60046020528060005260406000206000915090505481565b600081600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020541015151561095f57600080fd5b600560008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482111515156109ea57600080fd5b81600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600560008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282540392505081905550816003600082825403925050819055508273ffffffffffffffffffffffffffffffffffffffff167fcc16f5dbb4873280815c1ee09dbd06736cffcc184412cf7a71a0fdb75d397ca5836040518082815260200191505060405180910390a26001905092915050565b60018054600181600116156101000203166002900480601f016020809104026020016040519081016040528092919081815260200182805460018160011615610100020316600290048015610bbf5780601f10610b9457610100808354040283529160200191610bbf565b820191906000526020600020905b815481529060010190602001808311610ba257829003601f168201915b505050505081565b610bd2338383610d7e565b5050565b600080849050610be6858561062d565b15610d50578073ffffffffffffffffffffffffffffffffffffffff16638f4ffcb1338630876040518563ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018481526020018373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200180602001828103825283818151815260200191508051906020019080838360005b83811015610ce0578082015181840152602081019050610cc5565b50505050905090810190601f168015610d0d5780820380516001836020036101000a031916815260200191505b5095505050505050600060405180830381600087803b158015610d2f57600080fd5b505af1158015610d43573d6000803e3d6000fd5b5050505060019150610d51565b5b509392505050565b6005602052816000526040600020602052806000526040600020600091509150505481565b6000808373ffffffffffffffffffffffffffffffffffffffff1614151515610da557600080fd5b81600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410151515610df357600080fd5b600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205482600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401111515610e8157600080fd5b600460008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205401905081600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254039250508190555081600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040518082815260200191505060405180910390a380600460008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002054600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020540114151561108e57fe5b505050505600a165627a7a7230582012e3b4c1ec46ba19f4ea45d28ee4b34b34393f066d96bfc404b036b13c8d0f1b0029")
      )
      contract.getEstimatedGas(callTx).map(_ shouldBe N(1319766)).void
    }
  }
} 
Example 48
Source File: BlockView.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.app.views

import com.thoughtworks.binding
import com.thoughtworks.binding.Binding
import com.thoughtworks.binding.Binding.Var
import jbok.app.AppState
import jbok.app.components.{TabPane, Tabs}
import jbok.core.api.HistoryTransaction
import jbok.core.models._
import org.scalajs.dom._
import scodec.bits.ByteVector

import scala.scalajs.js.Date

final case class BlockView(state: AppState, block: Block) {
  val stxs: Var[List[HistoryTransaction]] = Var(List.empty)
  val stxsView                            = StxsView(state, stxs)

  private def fetch() = {
    val nodeId = state.activeNode.value.getOrElse("")
    val client = state.clients.value.get(nodeId)
    client.foreach { jbokClient =>
      val p = for {
        txs <- jbokClient.account.getTransactionsByNumber(block.header.number.toInt)
        _ = stxs.value = txs
      } yield ()

      p.unsafeToFuture()
    }
  }

  fetch()

  @binding.dom
  val overview: Binding[Element] =
    <div>
      <table class="table-view"> {
      val header = block.header
      val size   = block.body.transactionList.size
      <tr>
          <th>Height:</th>
          <td>{header.number.toString}</td>
        </tr>
        <tr>
          <th>TimeStamp:</th>
          <td>{new Date(header.unixTimestamp).toDateString()}</td>
        </tr>
        <tr>
          <th>Transactions:</th>
          <td>{s"${size.toLong} transactions in this Block"}</td>
        </tr>
        <tr>
          <th>This Block Hash:</th>
          <td>{header.hash.toHex}</td>
        </tr>
        <tr>
          <th>Parent Hash:</th>
          <td><a onclick={(e: Event) => state.searchBlockHash(header.parentHash.toHex)}>{header.parentHash.toHex}</a></td>
        </tr>
        <tr>
          <th>Mined By:</th>
          <td>{header.beneficiary.toHex}</td>
        </tr>
        <tr>
          <th>Difficulty:</th>
          <td>{header.difficulty.toString}</td>
        </tr>
        <tr>
          <th>Gas Used:</th>
          <td>{header.gasUsed.toString}</td>
        </tr>
        <tr>
          <th>Gas Limit:</th>
          <td>{header.gasLimit.toString}</td>
        </tr>
        <tr>
          <th>Extra Data:</th>
          <td>{header.extra.bytes.toHex}</td>
        </tr>
    }
      </table>
    </div>

  @binding.dom
  val txsView: Binding[Element] =
    <div>
      {stxsView.render.bind}
    </div>

  val tabView = Tabs(
    List(TabPane("Overview", overview), TabPane("Transactions", txsView)),
    className = "tab-small"
  )

  @binding.dom
  def render: Binding[Element] =
    <div>
      {tabView.render.bind}
    </div>
} 
Example 49
Source File: RegisterView.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.app.views

import cats.implicits._
import com.thoughtworks.binding
import com.thoughtworks.binding.Binding
import com.thoughtworks.binding.Binding.Var
import fastparse.Parsed.Failure
import jbok.app.{AppState, Contract}
import jbok.app.components.{Input, Notification}
import jbok.app.helper.InputValidator
import jbok.core.models.Address
import jbok.evm.solidity.SolidityParser
import org.scalajs.dom.{Element, Event}
import scodec.bits.ByteVector

final case class RegisterView(state: AppState) {
  val currentId = state.activeNode.value

  val contractAddress = Input("Address", "address", validator = InputValidator.isValidAddress)
  val contractCode = Input(
    "Code",
    """pragma solidity ^0.4.0;
      |
      |contract SimpleStorage {
      |    uint storedData;
      |
      |    function set(uint x) public {
      |        storedData = x;
      |    }
      |
      |    function get() public view returns (uint) {
      |        return storedData;
      |    }
      |}
    """.stripMargin,
    `type` = "textarea"
  )
  val statusMessage: Var[Option[String]] = Var(None)

  def checkAndGenerateInput() = {
    statusMessage.value = None
    for {
      address <- if (contractAddress.isValid) Right(contractAddress.value) else Left("not valid contract address.")
      code    <- if (contractCode.isValid) Right(contractCode.value) else Left("not valid contract code.")
    } yield _submit(address, code)
  }

  def _submit(address: String, code: String) = {
    val parseResult     = SolidityParser.parseSource(code)
    val contractAddress = Address(ByteVector.fromValidHex(address))
    parseResult.fold(
      (s, i, e) => {
        val msg = s match {
          case "" =>
            "Position " + e.input.prettyIndex(i) +
              ", found " + Failure.formatTrailing(e.input, i)
          case s => Failure.formatMsg(e.input, List(s -> i), i)
        }
        statusMessage.value = Some(s"parse error: ${msg}")
      },
      (r, i) =>
        currentId.foreach(id => {
          state.nodes.value.get(id).foreach(_.contractsABI.value += contractAddress -> Contract(contractAddress, r.ABI.last.methods))
          statusMessage.value = Some("register success.")
        })
    )
  }

  val registerOnClick = (_: Event) => checkAndGenerateInput().leftMap(error => statusMessage.value = Some(error))

  @binding.dom
  def render: Binding[Element] =
    <div>
      <div>
        <label for="address"><b>Address</b></label>
        {contractAddress.render.bind}
      </div>
      <div>
        <label for="code"><b>Address</b></label>
        {contractCode.render.bind}
      </div>

      {
        val onclose = (_: Event) => statusMessage.value = None
        @binding.dom def content(status: String):Binding[Element] =
          <div style="padding-left: 10px">{status}</div>
        statusMessage.bind match {
          case None => <div/>
          case Some(status) if status =="register success." =>
            Notification.renderSuccess(content(status), onclose).bind
          case Some(status) =>
            Notification.renderWarning(content(status), onclose).bind
        }
      }

      <div>
        <button id="register-contract" onclick={registerOnClick} style={"width: 100%"} >register</button>
      </div>
    </div>

} 
Example 50
Source File: BouncyHash.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.crypto.hash
import java.security.{MessageDigest, Security}

import org.bouncycastle.jcajce.provider.digest.Keccak
import org.bouncycastle.jce.provider.BouncyCastleProvider
import scodec.bits.ByteVector

object BouncyHash {
  if (Security.getProvider("BC") == null) {
    Security.addProvider(new BouncyCastleProvider())
  }

  def genInstance(algorithm: String): MessageDigest = MessageDigest.getInstance(algorithm, "BC")

  val sha256                    = genInstance("SHA-256")
  val ripemd160                 = genInstance("RipeMD160")
  def kec256(bytes: ByteVector) = new Keccak.Digest256().digest(bytes.toArray)
  def kec512(bytes: ByteVector) = new Keccak.Digest512().digest(bytes.toArray)
} 
Example 51
Source File: CryptoHasherPlatform.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.crypto.hash

import scodec.bits.ByteVector

trait CryptoHasherPlatform {
  implicit val kec256Platform: CryptoHasher[Keccak256] = new CryptoHasher[Keccak256] {
    override def hash(bytes: ByteVector): ByteVector = ByteVector(BouncyHash.kec256(bytes))
  }

  implicit val kec512Platform: CryptoHasher[Keccak512] = new CryptoHasher[Keccak512] {
    override def hash(bytes: ByteVector): ByteVector = ByteVector(BouncyHash.kec512(bytes))
  }

  implicit val sha256Platform: CryptoHasher[SHA256] = new CryptoHasher[SHA256] {
    override def hash(bytes: ByteVector): ByteVector = ByteVector(BouncyHash.sha256.digest(bytes.toArray))
  }

  implicit val ripemd160Platform: CryptoHasher[RipeMD160] = new CryptoHasher[RipeMD160] {
    override def hash(bytes: ByteVector): ByteVector = ByteVector(BouncyHash.ripemd160.digest(bytes.toArray))
  }
} 
Example 52
Source File: SCryptSpec.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.crypto

import java.nio.charset.StandardCharsets

import jbok.common.CommonSpec
import jbok.crypto.password._
import scodec.bits.ByteVector

class SCryptSpec extends CommonSpec {
  "SCrypt" should {
    "correctly evaluate for the test vectors" in {
      // https://datatracker.ietf.org/doc/rfc7914/?include_text=1
      val testVectors = Table[String, String, Int, Int, Int, Int, String](
        ("passphrase", "salt", "n", "r", "p", "dklen", "derivedKey"),
        ("", "", 16, 1, 1, 64,
          "77d6576238657b203b19ca42c18a0497f16b4844e3074ae8dfdffa3fede21442fcd0069ded0948f8326a753a0fc81f17e8d3e0fb2e0d3628cf35e20c38d18906"),

        ("password", "NaCl", 1024, 8, 16, 64,
          "fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b3731622eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640"),

        // takes a bit too long to be run on the CI
        // leaving this around as it's a valid test if we want to examine this function in the future
        // ("pleaseletmein", "SodiumChloride", 1048576, 8, 1, 64,
        //   "2101cb9b6a511aaeaddbbe09cf70f881ec568d574a2ffd4dabe5ee9820adaa478e56fd8f4ba5d09ffa1c6d927c40f4c337304049e8a952fbcbf45c6fa77a41a4"),

        ("pleaseletmein", "SodiumChloride", 16384, 8, 1, 64,
          "7023bdcb3afd7348461c06cd81fd38ebfda8fbba904f8e3ea9b543f6545da1f2d5432955613f0fcf62d49705242a9af9e61e85dc0d651e40dfcf017b45575887")
      )

      forAll(testVectors) { case (pass, s, n, r, p, dklen, dk) =>
        val salt = ByteVector(s.getBytes(StandardCharsets.US_ASCII))
        val derivedKey = ByteVector.fromValidHex(dk)


        SCrypt.derive(pass, salt, n, r, p, dklen) shouldBe derivedKey
      }
    }
  }
} 
Example 53
Source File: CryptoHasher.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.crypto.hash

import scodec.bits.ByteVector

sealed trait Keccak256
sealed trait Keccak512
sealed trait SHA256
sealed trait RipeMD160

trait CryptoHasher[A] {
  def hash(bytes: ByteVector): ByteVector
}

object CryptoHasher {
  def apply[A](implicit ev: CryptoHasher[A]): CryptoHasher[A] = ev
} 
Example 54
Source File: KeyPair.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.crypto.signature

import java.math.BigInteger

import cats.effect.IO
import jbok.codec.json.implicits._
import io.circe.generic.extras.ConfiguredJsonCodec
import scodec.bits.ByteVector

@ConfiguredJsonCodec
final case class KeyPair(public: KeyPair.Public, secret: KeyPair.Secret)

object KeyPair {
  @ConfiguredJsonCodec
  final case class Public(bytes: ByteVector) extends AnyVal

  object Public {
    def apply(hex: String): Public        = Public(ByteVector.fromValidHex(hex))
    def apply(bytes: Array[Byte]): Public = Public(ByteVector(bytes))
  }

  @ConfiguredJsonCodec
  final case class Secret(bytes: ByteVector) extends AnyVal {
    def d: BigInteger = new BigInteger(1, bytes.toArray)
  }

  object Secret {
    def apply(d: BigInteger): Secret      = apply(ByteVector(d.toByteArray))
    def apply(hex: String): Secret        = apply(ByteVector.fromValidHex(hex))
    def apply(bytes: Array[Byte]): Secret = apply(ByteVector(bytes))
    def apply(bv: ByteVector): Secret     = new Secret(bv.takeRight(32).padLeft(32))
  }

  def fromSecret(secret: ByteVector): KeyPair = {
    val sec = KeyPair.Secret(secret)
    val pub = Signature[ECDSA].generatePublicKey[IO](sec).unsafeRunSync()
    KeyPair(pub, sec)
  }
} 
Example 55
Source File: CryptoSignature.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.crypto.signature

import io.circe.generic.extras.ConfiguredJsonCodec
import jbok.codec.json.implicits._
import scodec.bits.ByteVector

@ConfiguredJsonCodec
final case class CryptoSignature(r: BigInt, s: BigInt, v: BigInt) {
  def bytes: Array[Byte] =
    CryptoSignature.unsignedPadding(r) ++ CryptoSignature.unsignedPadding(s) ++ CryptoSignature.unsigned(v)
}

object CryptoSignature {
  def unsigned(bigInteger: BigInt): Array[Byte] = {
    val asByteArray = bigInteger.toByteArray
    if (asByteArray.head == 0) asByteArray.tail else asByteArray
  }

  def unsignedPadding(bigInt: BigInt): Array[Byte] = {
    val bytes = unsigned(bigInt)
    ByteVector(bytes).take(32).padLeft(32).toArray
  }

  def apply(bytes: Array[Byte]): CryptoSignature = {
    require(bytes.length >= 65, s"signature length should be 65 instead of ${bytes.length}")
    CryptoSignature(
      BigInt(1, bytes.slice(0, 32)),
      BigInt(1, bytes.slice(32, 64)),
      BigInt(1, bytes.slice(64, bytes.length))
    )
  }

  def apply(r: ByteVector, s: ByteVector, v: ByteVector): CryptoSignature =
    CryptoSignature(BigInt(1, r.toArray), BigInt(1, s.toArray), BigInt(1, v.toArray))
} 
Example 56
Source File: package.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok

import java.nio.charset.StandardCharsets
import java.util.Random

import jbok.crypto.hash._
import scodec.bits.ByteVector
import jbok.crypto.signature.SignatureInstances

trait StringSyntax {
  implicit final def stringSyntax(a: String): StringOps = new StringOps(a)
}

final class StringOps(val a : String) extends AnyVal {
  def utf8bytes: ByteVector = ByteVector(a.getBytes(StandardCharsets.UTF_8))
}

trait CryptoSyntax extends CryptoHasherSyntax with StringSyntax
trait CryptoInstances extends CryptoHasherInstances with SignatureInstances

package object crypto extends CryptoSyntax with CryptoInstances {
  def randomByteString(random: Random, length: Int): ByteVector =
    ByteVector(randomByteArray(random, length))

  def randomByteArray(random: Random, length: Int): Array[Byte] = {
    val bytes = Array.ofDim[Byte](length)
    random.nextBytes(bytes)
    bytes
  }
} 
Example 57
Source File: CryptoHasherPlatform.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.crypto.hash

import jbok.crypto.facade.CryptoJs
import scodec.bits.ByteVector

import scala.scalajs.js

trait CryptoHasherPlatform {
  implicit val kec256Platform: CryptoHasher[Keccak256] = new CryptoHasher[Keccak256] {
    override def hash(bytes: ByteVector): ByteVector = {
      val bin = CryptoJs.sha3(CryptoJs.Hex.parse(bytes.toHex), js.Dynamic.literal(outputLength = 256))
      val hex = CryptoJs.Hex.stringify(bin)
      ByteVector.fromValidHex(hex)
    }
  }

  implicit val kec512Platform: CryptoHasher[Keccak512] = new CryptoHasher[Keccak512] {
    override def hash(bytes: ByteVector): ByteVector = {
      val bin = CryptoJs.sha3(CryptoJs.Hex.parse(bytes.toHex), js.Dynamic.literal(outputLength = 512))
      val hex = CryptoJs.Hex.stringify(bin)
      ByteVector.fromValidHex(hex)
    }
  }

  implicit val sha256Platform: CryptoHasher[SHA256] = new CryptoHasher[SHA256] {
    override def hash(bytes: ByteVector): ByteVector = {
      val bin = CryptoJs.sha256(CryptoJs.Hex.parse(bytes.toHex))
      val hex = CryptoJs.Hex.stringify(bin)
      ByteVector.fromValidHex(hex)
    }
  }

  implicit val ripemd160Platform: CryptoHasher[RipeMD160] = new CryptoHasher[RipeMD160] {
    override def hash(bytes: ByteVector): ByteVector = {
      val bin = CryptoJs.ripemd160(CryptoJs.Hex.parse(bytes.toHex))
      val hex = CryptoJs.Hex.stringify(bin)
      ByteVector.fromValidHex(hex)
    }
  }
} 
Example 58
Source File: testkit.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.codec

import jbok.codec.rlp.RlpCodec
import jbok.codec.rlp.implicits._
import org.scalatest.{Assertion, Matchers}
import scodec.bits.{BitVector, ByteVector}
import scodec.{Attempt, DecodeResult, Err}

object testkit extends testkit
trait testkit extends Matchers {
  def roundtripAndMatch[A](a: A, expected: ByteVector)(implicit c: RlpCodec[A]): Assertion = {
    roundtrip[A](a)
    a.encoded.bits.bytes shouldBe expected
  }

  def roundtripLen[A](a: A, expectedNumBytes: Int)(implicit c: RlpCodec[A]): Assertion = {
    roundtrip[A](a)
    a.encoded.bits.bytes.length shouldBe expectedNumBytes
  }

  def roundtrip[A](a: A)(implicit c: RlpCodec[A]): Assertion =
    roundtrip(c, a)

  def roundtrip[A](codec: RlpCodec[A], value: A): Assertion = {
    val encoded = codec.encode(value)
    encoded.isSuccessful shouldBe true
    val Attempt.Successful(DecodeResult(decoded, remainder)) = codec.decode(encoded.require)
    remainder shouldBe BitVector.empty
    decoded shouldBe value
  }

  def roundtripAll[A](codec: RlpCodec[A], as: collection.Iterable[A]): Unit =
    as foreach { a =>
      roundtrip(codec, a)
    }

  def encodeError[A](codec: RlpCodec[A], a: A, err: Err): Assertion = {
    val encoded = codec.encode(a)
    encoded shouldBe Attempt.Failure(err)
  }

  def shouldDecodeFullyTo[A](codec: RlpCodec[A], buf: BitVector, expected: A): Assertion = {
    val Attempt.Successful(DecodeResult(actual, rest)) = codec decode buf
    rest shouldBe BitVector.empty
    actual shouldBe expected
  }
} 
Example 59
Source File: RlpEncoded.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.codec.rlp

import scodec.bits.{BitVector, ByteVector}

// normally we construct `RlpEncoded` via rlp encoding
// to avoid dumb problems
final class RlpEncoded private (val bits: BitVector) extends AnyVal {
  def bytes: ByteVector = bits.bytes

  def byteArray: Array[Byte] = bits.toByteArray

  def decoded[A](implicit codec: RlpCodec[A]): Either[Throwable, A] =
    codec.decode(bits).toEither match {
      case Left(err)     => Left(new Exception(err.messageWithContext))
      case Right(result) => Right(result.value)
    }

  def isItem: Boolean =
    bits.bytes.headOption match {
      case Some(byte) => (0xff & byte) < RlpCodecHelper.listOffset
      case None       => false
    }

  def isList: Boolean =
    !isItem

  def isEmptyItem: Boolean =
    this == RlpEncoded.emptyItem

  def isEmptyList: Boolean =
    this == RlpEncoded.emptyList

  override def toString: String = s"RlpEncoded(${bits.bytes})"
}

object RlpEncoded {
  def coerce(bits: BitVector): RlpEncoded = new RlpEncoded(bits)

  val emptyItem: RlpEncoded = RlpEncoded.coerce(BitVector(RlpCodecHelper.itemOffset.toByte))

  val emptyList: RlpEncoded = RlpEncoded.coerce(BitVector(RlpCodecHelper.listOffset.toByte))
} 
Example 60
Source File: implicits.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.codec.json

import io.circe._
import io.circe.generic.extras._
import jbok.codec.rlp.RlpEncoded
import scodec.bits.ByteVector
import shapeless._
import spire.math.SafeLong

import scala.concurrent.duration.{Duration, FiniteDuration}
import scala.util.Try

@SuppressWarnings(Array("org.wartremover.warts.AsInstanceOf"))
trait implicits {
  implicit val jsonConfig: Configuration = Configuration.default

  implicit val bytesJsonEncoder: Encoder[ByteVector] = Encoder.encodeString.contramap[ByteVector](_.toHex)
  implicit val bytesJsonDecoder: Decoder[ByteVector] = Decoder.decodeString.emap[ByteVector](ByteVector.fromHexDescriptive(_))

  implicit val rlpJsonEncoder: Encoder[RlpEncoded] = bytesJsonEncoder.contramap(_.bytes)
  implicit val rlpJsonDecoder: Decoder[RlpEncoded] = bytesJsonDecoder.map(bytes => RlpEncoded.coerce(bytes.bits))

  implicit val finiteDurationJsonEncoder: Encoder[FiniteDuration] = Encoder.encodeString.contramap[FiniteDuration](d => s"${d.length} ${d.unit.toString.toLowerCase}")
  implicit val finiteDurationJsonDecoder: Decoder[FiniteDuration] = Decoder.decodeString.emapTry[FiniteDuration](s => Try(Duration.apply(s).asInstanceOf[FiniteDuration]))

  implicit val bigIntJsonEncoder: Encoder[BigInt] = Encoder.encodeString.contramap[BigInt](_.toString(10))
  implicit val bigIntJsonDecoder: Decoder[BigInt] = Decoder.decodeString.emapTry[BigInt](s => Try(BigInt(s)))

  implicit val safeLongJsonEncoder: Encoder[SafeLong] = Encoder.encodeString.contramap[SafeLong](_.toString)
  implicit val safeLongJsonDecoder: Decoder[SafeLong] = Decoder.decodeString.emapTry[SafeLong](
    s =>
      if (s.startsWith("0x")) Try(SafeLong(BigInt(s.drop(2), 16)))
      else Try(SafeLong(BigInt(s)))
  )

  // key codecs
  implicit val bigIntKeyEncoder: KeyEncoder[BigInt] = KeyEncoder.encodeKeyString.contramap[BigInt](_.toString(10))
  implicit val bigIntKeyDecoder: KeyDecoder[BigInt] = KeyDecoder.decodeKeyString.map[BigInt](BigInt.apply)

  implicit val safeLongKeyEncoder: KeyEncoder[SafeLong] = KeyEncoder.encodeKeyString.contramap[SafeLong](_.toString)
  implicit val safeLongKeyDecoder: KeyDecoder[SafeLong] = KeyDecoder.decodeKeyString.map[SafeLong](s => SafeLong(BigInt(s)))

  // codec for value classes
  implicit def decoderJsonValueClass[T <: AnyVal, V](
      implicit
      g: Lazy[Generic.Aux[T, V :: HNil]],
      d: Decoder[V]
  ): Decoder[T] = Decoder.instance { cursor ⇒
    d(cursor).map { value ⇒
      g.value.from(value :: HNil)
    }
  }

  implicit def encoderJsonValueClass[T <: AnyVal, V](
      implicit
      g: Lazy[Generic.Aux[T, V :: HNil]],
      e: Encoder[V]
  ): Encoder[T] = Encoder.instance { value ⇒
    e(g.value.to(value).head)
  }
}

object implicits extends implicits 
Example 61
Source File: Contract.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.sdk

import fastparse.Parsed
import io.circe.generic.extras._
import jbok.evm.solidity.SolidityParser
import jbok.evm.solidity.ABIDescription
import jbok.evm.solidity.ABIDescription.ContractDescription
import scodec.bits.ByteVector
import _root_.io.circe.syntax._
import jbok.codec.json.implicits._

import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel}
import scala.scalajs.js.JSConverters._
import scala.scalajs.js.UndefOr

@JSExportTopLevel("Contracts")
@JSExportAll
@ConfiguredJsonCodec
final case class Contracts(contractDescriptions: List[ContractDescription]) {
  private lazy val contracts = contractDescriptions.map(cd => cd.name -> cd).toMap

  private def methods(name: String): Option[Map[String, ABIDescription.FunctionDescription]] =
    contracts.get(name).map(_.methods.map(method => method.name -> method).toMap)

  def encode(contractName: String, method: String, param: String): UndefOr[String] =
    (for {
      function <- methods(contractName).flatMap(_.get(method))
      returns = function.encode(param) match {
        case Right(value) => value.toHex
        case Left(e)      => e.toString
      }
    } yield returns).orUndefined

  def decode(contractName: String, method: String, param: String): UndefOr[String] =
    (for {
      function <- methods(contractName).flatMap(_.get(method))
      result   <- ByteVector.fromHex(param)
      returns = function.decode(result) match {
        case Right(value) => value.noSpaces
        case Left(e)      => e.toString
      }
    } yield returns).orUndefined
}

@ConfiguredJsonCodec
final case class ParsedResult(contracts: Option[Contracts], error: String)

@JSExportTopLevel("ContractParser")
@JSExportAll
object ContractParser {
  def parse(code: String): String = {
    val result = SolidityParser.parseSource(code)

    if (result.isSuccess) {
      ParsedResult(Some(Contracts(result.get.value.ABI)), "").asJson.noSpaces
    } else {
      ParsedResult(None, result.asInstanceOf[Parsed.Failure].trace().longAggregateMsg).asJson.noSpaces
    }
  }
} 
Example 62
Source File: ByteUtils.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.common

import java.nio.{ByteBuffer, ByteOrder}

import scodec.bits.ByteVector

object ByteUtils {
  def or(arrays: ByteVector*): ByteVector = {
    require(arrays.map(_.length).distinct.length <= 1, "All the arrays should have the same length")
    require(arrays.nonEmpty, "There should be one or more arrays")

    val zeroes = ByteVector.fill(arrays.headOption.map(_.length).getOrElse(0))(0.toByte)
    arrays.foldLeft[ByteVector](zeroes) {
      case (acc, cur) => acc or cur
    }
  }

  def and(arrays: ByteVector*): ByteVector = {
    require(arrays.map(_.length).distinct.length <= 1, "All the arrays should have the same length")
    require(arrays.nonEmpty, "There should be one or more arrays")

    val ones = ByteVector.fill(arrays.headOption.map(_.length).getOrElse(0))(0xFF.toByte)
    arrays.foldLeft[ByteVector](ones) {
      case (acc, cur) => acc and cur
    }
  }

  def bytesToInts(bytes: Array[Byte]): Array[Int] =
    bytes.grouped(4).map(getIntFromWord).toArray

  def intsToBytes(input: Array[Int]): Array[Byte] =
    input.flatMap { i =>
      Array(
        (i & 0xFF).toByte,
        ((i >> 8) & 0xFF).toByte,
        ((i >> 16) & 0xFF).toByte,
        ((i >> 24) & 0xFF).toByte
      )
    }

  def getIntFromWord(arr: Array[Byte]): Int =
    ByteBuffer.wrap(arr, 0, 4).order(ByteOrder.LITTLE_ENDIAN).getInt
} 
Example 63
Source File: gen.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.common

import jbok.common.math.N
import org.scalacheck.Arbitrary._
import org.scalacheck.Gen
import org.scalacheck.Gen.Choose
import scodec.bits.ByteVector
import spire.laws.{gen => SpireGen}
import spire.math.{Natural, SafeLong}

object gen {
  def int(min: Int = Int.MinValue, max: Int = Int.MaxValue): Gen[Int] =
    Gen.choose(min, max)

  val hexChar: Gen[Char] = Gen.oneOf("0123456789abcdef")

  def hex(min: Int, max: Int): Gen[String] =
    for {
      size  <- Gen.chooseNum(min, max)
      chars <- Gen.listOfN(size, hexChar)
    } yield chars.mkString

  val natural: Gen[Natural] =
    SpireGen.natural

  val safeLong: Gen[SafeLong] =
    SpireGen.safeLong

  val N: Gen[N] =
    safeLong.map(_.abs)

  val bigInt: Gen[BigInt] =
    arbitrary[BigInt].map(_.abs)

  val byteArray: Gen[Array[Byte]] =
    Gen.listOf(arbitrary[Byte]).map(_.toArray)

  val byteVector: Gen[ByteVector] =
    byteArray.map(ByteVector.apply)

  def boundedByteArray(l: Int, u: Int): Gen[Array[Byte]] =
    Gen.choose(l, u).flatMap(size => sizedByteArray(size))

  def boundedByteVector(l: Int, u: Int): Gen[ByteVector] =
    Gen.choose(l, u).flatMap(size => sizedByteVector(size))

  def sizedByteArray(size: Int): Gen[Array[Byte]] =
    Gen.listOfN(size, arbitrary[Byte]).map(_.toArray)

  def sizedByteVector(size: Int): Gen[ByteVector] =
    Gen.listOfN(size, arbitrary[Byte]).map(ByteVector.apply)

  def posNum[T](implicit num: Numeric[T], c: Choose[T]): Gen[T] = Gen.posNum[T]

  def boundedList[T](minSize: Int, maxSize: Int, gen: Gen[T]): Gen[List[T]] =
    Gen.choose(minSize, maxSize).flatMap(size => Gen.listOfN(size, gen))
} 
Example 64
Source File: testkit.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.persistent

import cats.effect.{IO, Resource}
import jbok.codec.HexPrefix
import jbok.common.{gen, FileUtil}
import jbok.persistent.rocksdb.RocksKVStore
import org.scalacheck.{Arbitrary, Gen}
import scodec.bits.ByteVector
import jbok.codec.rlp.implicits._
import jbok.persistent.mpt.MptNode
import jbok.persistent.mpt.MptNode._
import cats.implicits._

object testkit {
  implicit def arbColumnFamily: Arbitrary[ColumnFamily] = Arbitrary {
    Gen.alphaNumStr.map(ColumnFamily.apply)
  }

  def testRocksKVStore(cfs: List[ColumnFamily] = List(ColumnFamily.default)): Resource[IO, KVStore[IO]] =
    FileUtil[IO].temporaryDir().flatMap { dir =>
      RocksKVStore.resource[IO](dir.path, cfs)
    }

  val testMemoryKVStore: Resource[IO, KVStore[IO]] =
    Resource.liftF(MemoryKVStore[IO])

  def testRocksStageStore(cfs: List[ColumnFamily] = List(ColumnFamily.default)): Resource[IO, StageKVStore[IO, ByteVector, ByteVector]] =
    testRocksKVStore(cfs).map(inner => StageKVStore(SingleColumnKVStore[IO, ByteVector, ByteVector](ColumnFamily.default, inner)))

  val testMemoryStageStore: Resource[IO, StageKVStore[IO, ByteVector, ByteVector]] =
    testMemoryKVStore.map(inner => StageKVStore(SingleColumnKVStore[IO, ByteVector, ByteVector](ColumnFamily.default, inner)))

  implicit lazy val arbLeafNode: Arbitrary[LeafNode] = Arbitrary {
    for {
      key   <- gen.boundedByteVector(0, 1024)
      value <- gen.boundedByteVector(0, 1024)
    } yield LeafNode(HexPrefix.encodedToNibbles(key.encoded), value.encoded)
  }

  implicit lazy val arbBranchNode: Arbitrary[BranchNode] = Arbitrary {
    for {
      children <- Gen
        .listOfN(16, Gen.oneOf(gen.sizedByteVector(32).map(_.asLeft), arbMptNode.arbitrary.map(_.asRight)))
        .map(childrenList => childrenList.map(child => Some(child)))
      value <- gen.byteVector
    } yield BranchNode(children, Some(value.encoded))
  }

  implicit lazy val arbExtensionNode: Arbitrary[ExtensionNode] = Arbitrary {
    for {
      key   <- gen.boundedByteVector(0, 1024)
      value <- gen.boundedByteVector(0, 1024)
    } yield ExtensionNode(HexPrefix.encodedToNibbles(key.encoded), Left(value))
  }

  implicit lazy val arbMptNode: Arbitrary[MptNode] = Arbitrary {
    Gen.oneOf[MptNode](arbLeafNode.arbitrary, arbExtensionNode.arbitrary, arbBranchNode.arbitrary)
  }
} 
Example 65
Source File: KVStoreSpec.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.persistent

import cats.effect.{IO, Resource}
import cats.implicits._
import jbok.common.CommonSpec
import jbok.persistent.testkit._
import scodec.bits.ByteVector

class KVStoreSpec extends CommonSpec {
  val default = ColumnFamily.default
  val cfa     = ColumnFamily("a")
  val cfb     = ColumnFamily("b")
  val cfs     = List(default, cfa, cfb)

  def test(name: String, resource: Resource[IO, KVStore[IO]]): Unit =
    s"KVStore ${name}" should {
      "respect column family" in withResource(resource) { store =>
        val key = "key".getBytes
        val a   = "a".getBytes
        val b   = "b".getBytes
        for {
          _ <- store.put(cfa, key, a)
          _ <- store.put(cfb, key, b)

          value <- store.get(default, key)
          _ = value shouldBe None
          size <- store.size(default)
          _ = size shouldBe 0

          value <- store.get(cfa, key)
          _ = value.get shouldEqual a
          size <- store.size(cfa)
          _ = size shouldBe 1

          value <- store.get(cfb, key)
          _ = value.get shouldEqual b
          size <- store.size(cfb)
          _ = size shouldBe 1
        } yield ()
      }

      "write batch" in {
        val cf = default
        forAll { m: Map[ByteVector, ByteVector] =>
          val p = resource.use { store =>
            val kvs = m.toList.map { case (k, v) => k.toArray -> v.toArray }
            for {
              _   <- store.writeBatch(cf, kvs, Nil)
              res <- store.toList(cf)
              _ = res.map { case (k, v) => ByteVector(k) -> ByteVector(v) }.toMap shouldBe m

              res <- store.size(cf)
              _ = res shouldBe kvs.size
            } yield ()
          }
          p.unsafeRunSync()
        }
      }

      "toList" in {
        forAll { (m1: Map[ByteVector, ByteVector], m2: Map[ByteVector, ByteVector]) =>
          val kvs1 = m1.toList.map { case (k, v) => k.toArray -> v.toArray }
          val kvs2 = m2.toList.map { case (k, v) => k.toArray -> v.toArray }
          val p = resource.use { store =>
            for {
              _   <- kvs1.traverse(t => store.put(cfa, t._1, t._2))
              _   <- kvs2.traverse(t => store.put(cfb, t._1, t._2))
              res <- store.toList(cfa)
              _ = res.map { case (k, v) => ByteVector(k) -> ByteVector(v) }.toMap shouldBe m1
              res <- store.toList(cfb)
              _ = res.map { case (k, v) => ByteVector(k) -> ByteVector(v) }.toMap shouldBe m2
            } yield ()
          }
          p.unsafeRunSync()
        }
      }
    }

  test("rocksdb", testRocksKVStore(cfs))
  test("memory", testMemoryKVStore)
} 
Example 66
Source File: StageKVStoreSpec.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.persistent

import cats.effect.{IO, Resource}
import jbok.common.CommonSpec
import scodec.bits.ByteVector
import jbok.persistent.testkit._

class StageKVStoreSpec extends CommonSpec {
  def test(name: String, resource: Resource[IO, StageKVStore[IO, ByteVector, ByteVector]]): Unit =
    s"StageKVStore $name" should {
      val key   = ByteVector("key".getBytes)
      val value = ByteVector("value".getBytes)

      "not write inserts until commit" in withResource(resource) { stage =>
        val updated = stage
          .put(key, value)

        for {
          res <- updated.mustGet(key)
          _ = res shouldBe value

          res <- updated.inner.get(key)
          _ = res shouldBe None

          committed <- updated.commit

          res <- committed.inner.get(key)
          _ = res shouldBe Some(value)

          res <- stage.mustGet(key)
          _ = res shouldBe value
        } yield ()
      }
    }

  test("rocksdb", testRocksStageStore())
  test("memory", testMemoryStageStore)
} 
Example 67
Source File: ProgramSpec.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.evm

import jbok.common.{gen, CommonSpec}
import org.scalacheck.Arbitrary
import scodec.bits.ByteVector

class ProgramSpec extends CommonSpec {

  val CodeSize: Int = Byte.MaxValue
  val PositionsSize = 10

  val nonPushOp: Byte     = JUMP.code
  val invalidOpCode: Byte = 0xef.toByte

  implicit val arbPositionSet: Arbitrary[Set[Int]] =
    Arbitrary(gen.boundedList(0, PositionsSize, gen.int(0, CodeSize)).map(_.toSet))

  "program" should {

    "detect all jump destinations if there are no push op" in {
      forAll { jumpDestLocations: Set[Int] =>
        val code = ByteVector((0 to CodeSize).map { i =>
          if (jumpDestLocations.contains(i)) JUMPDEST.code
          else nonPushOp
        }.toArray)
        val program = Program(code)
        program.validJumpDestinations shouldBe jumpDestLocations
      }
    }

    "detect all jump destinations if there are push op" in {
      forAll { (jumpDestLocations: Set[Int], pushOpLocations: Set[Int]) =>
        val code = ByteVector((0 to CodeSize).map { i =>
          if (jumpDestLocations.contains(i)) JUMPDEST.code
          else if (pushOpLocations.contains(i)) PUSH1.code
          else nonPushOp
        }.toArray)
        val program = Program(code)

        //Removing the PUSH1 that would be used as a parameter of another PUSH1
        //  Example: In "PUSH1 PUSH1 JUMPDEST", the JUMPDEST is a valid jump destination
        val pushOpLocationsNotParameters = (pushOpLocations diff jumpDestLocations).toList.sorted
          .foldLeft(List.empty[Int]) {
            case (recPushOpLocations, i) =>
              if (recPushOpLocations.lastOption.contains(i - 1)) recPushOpLocations else recPushOpLocations :+ i
          }

        val jumpDestLocationsWithoutPushBefore = jumpDestLocations
          .filterNot(i => pushOpLocationsNotParameters.contains(i - 1))
          .filter(i => 0 <= i && i <= CodeSize)
        program.validJumpDestinations shouldBe jumpDestLocationsWithoutPushBefore
      }
    }

    "detect all jump destinations if there are invalid ops" in {
      forAll { (jumpDestLocations: Set[Int], invalidOpLocations: Set[Int]) =>
        val code = ByteVector((0 to CodeSize).map { i =>
          if (jumpDestLocations.contains(i)) JUMPDEST.code
          else if (invalidOpLocations.contains(i)) invalidOpCode
          else nonPushOp
        }.toArray)
        val program = Program(code)
        program.validJumpDestinations shouldBe jumpDestLocations
      }
    }

    "detect all instructions as jump destinations if they are" in {
      val code    = ByteVector((0 to CodeSize).map(_ => JUMPDEST.code).toArray)
      val program = Program(code)
      program.validJumpDestinations shouldBe (0 to CodeSize).toSet
    }
  }
} 
Example 68
Source File: Assembly.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.evm

import jbok.common.math.N
import jbok.evm.Assembly._
import scodec.bits.ByteVector

object Assembly {

  sealed trait ByteCode {
    def bytes: ByteVector
  }

  implicit class OpCodeAsByteCode(val op: OpCode) extends ByteCode {
    def bytes: ByteVector = ByteVector(op.code)
  }

  implicit class IntAsByteCode(val i: Int) extends ByteCode {
    def bytes: ByteVector = ByteVector(i.toByte)
  }

  implicit class ByteAsByteCode(val byte: Byte) extends ByteCode {
    def bytes: ByteVector = ByteVector(byte)
  }

  implicit class ByteVectorAsByteCode(val bytes: ByteVector) extends ByteCode
}

final case class Assembly(byteCode: ByteCode*) {
  val code: ByteVector = byteCode.foldLeft(ByteVector.empty)(_.bytes ++ _.bytes)

  val program: Program = Program(code)

  def linearConstGas(config: EvmConfig): N = byteCode.foldLeft(N(0)) {
    case (g, b: OpCodeAsByteCode) => g + b.op.constGasFn(config.feeSchedule)
    case (g, _)                   => g
  }
} 
Example 69
Source File: CallOpcodesSpecByzantium.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.evm

import cats.effect.IO
import jbok.core.CoreSpec
import jbok.core.ledger.History
import jbok.core.models.{Account, Address, UInt256}
import jbok.persistent.MemoryKVStore
import scodec.bits.ByteVector

class CallOpcodesSpecByzantium extends CoreSpec {
  val evmConfig  = EvmConfig.ByzantiumConfigBuilder(None)
  val store      = MemoryKVStore[IO].unsafeRunSync()
  val history    = History(store, chainId)
  val startState = history.getWorldState(noEmptyAccounts = true).unsafeRunSync()

  val fxt = new CallOpFixture(evmConfig, startState)

  "STATICCALL" should {

    "call a program that executes a SELFDESTRUCT" should {
      val context = fxt.context.copy(world = fxt.worldWithSelfDestructProgram)
      val call    = fxt.CallResult(op = STATICCALL, context)

      "return 0" in {
        call.stateOut.stack.pop._1 shouldBe UInt256.zero
      }
    }

    "call a precompiled contract" should {
      val contractAddress  = Address(1) // ECDSA recovery
      val invalidSignature = ByteVector(Array.fill(128)(0.toByte))
      val world            = fxt.worldWithoutExtAccount.putAccount(contractAddress, Account(balance = 1))
      val context          = fxt.context.copy(world = world)
      val call = fxt.CallResult(
        op = STATICCALL,
        context = context,
        to = contractAddress,
        inputData = invalidSignature,
        inOffset = 0,
        inSize = 128,
        outOffset = 0,
        outSize = 128
      )

      "compute a correct result" in {
        // For invalid signature the return data should be empty, so the memory should not be modified.
        // This is more interesting than checking valid signatures which are tested elsewhere
        val (result, _) = call.stateOut.memory.load(call.outOffset, call.outSize)
        val expected    = invalidSignature

        result shouldBe expected
      }

      "return 1" in {
        call.stateOut.stack.pop._1 shouldBe UInt256.one
      }

      "update precompiled contract's balance" in {
        call.extBalance shouldBe 1
      }
    }

    "call a program that executes a REVERT" should {
      val context = fxt.context.copy(world = fxt.worldWithRevertProgram)
      val call    = fxt.CallResult(op = STATICCALL, context)

      "return 0" in {
        call.stateOut.stack.pop._1 shouldBe UInt256.zero
      }

      "consume correct gas" in {
        call.stateOut.gasUsed shouldBe 709
      }
    }
  }
} 
Example 70
Source File: HistorySpec.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.core.ledger

import cats.effect.IO
import cats.implicits._
import jbok.core.ledger.TypedBlock.MinedBlock
import jbok.core.models._
import jbok.core.{CoreSpec, StatefulGen}
import scodec.bits.ByteVector
import jbok.crypto._

class HistorySpec extends CoreSpec {
  "History" should {
    val objects = locator.unsafeRunSync()
    val history = objects.get[History[IO]]

    "load genesis config" in {
      val addresses = genesis.alloc.keysIterator.toList
      val accounts  = addresses.flatMap(addr => history.getAccount(addr, 0).unsafeRunSync())
      accounts.length shouldBe addresses.length
    }

    // storage and codes
    "put and get code" in {
      forAll { code: ByteVector =>
        history.putCode(code).unsafeRunSync()
        history.getCode(code.kec256).unsafeRunSync().getOrElse(ByteVector.empty) shouldBe code
      }
    }

    // mapping
    "put block header should update number hash mapping" in {
      history.getHashByBlockNumber(0).unsafeRunSync() shouldBe history.genesisHeader.unsafeRunSync().hash.some
    }

    "put block body should update tx location mapping" in {
      val txs   = random(StatefulGen.transactions(1, 1, history))
      val block = random(StatefulGen.block(None, txs.some))
      history.putBlockBody(block.header.hash, block.body).unsafeRunSync()
      val location = history.getTransactionLocation(txs.head.hash).unsafeRunSync()
      location shouldBe Some(TransactionLocation(block.header.hash, 0))
    }

    "delBlock should delete all relevant parts" in check { objects =>
      val history = objects.get[History[IO]]
      val mined   = random[MinedBlock](StatefulGen.minedBlock())
      for {
        _ <- history.putBlockAndReceipts(mined.block, mined.receipts)

        res <- history.getBlockHeaderByHash(mined.block.header.hash)
        _ = res shouldBe Some(mined.block.header)

        res <- history.getBlockBodyByHash(mined.block.header.hash)
        _ = res shouldBe Some(mined.block.body)

        res <- history.getBlockByHash(mined.block.header.hash)
        _ = res shouldBe Some(mined.block)

        res <- history.getReceiptsByHash(mined.block.header.hash)
        _ = res shouldBe Some(mined.receipts)

        res <- history.getBestBlockNumber
        _ = res shouldBe mined.block.header.number

        res <- history.getTotalDifficultyByHash(mined.block.header.hash)
        _ = res shouldBe Some(mined.block.header.difficulty)

        res <- history.getHashByBlockNumber(mined.block.header.number)
        _ = res shouldBe Some(mined.block.header.hash)

        // del
        _ <- history.delBlock(mined.block.header.hash)

        res <- history.getBlockHeaderByHash(mined.block.header.hash)
        _ = res shouldBe None

        res <- history.getBlockBodyByHash(mined.block.header.hash)
        _ = res shouldBe None

        res <- history.getBlockByHash(mined.block.header.hash)
        _ = res shouldBe None

        res <- history.getReceiptsByHash(mined.block.header.hash)
        _ = res shouldBe None

        res <- history.getTotalDifficultyByHash(mined.block.header.hash)
        _ = res shouldBe None

        res <- history.getHashByBlockNumber(mined.block.header.number)
        _ = res shouldBe None
      } yield ()
    }
  }
} 
Example 71
Source File: ExecEnv.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.evm

import jbok.core.models._
import scodec.bits.ByteVector


final case class ExecEnv(
    ownerAddr: Address,
    callerAddr: Address,
    originAddr: Address,
    gasPrice: UInt256,
    inputData: ByteVector,
    value: UInt256,
    program: Program,
    blockHeader: BlockHeader,
    callDepth: Int,
    noSelfCall: Boolean = false
) 
Example 72
Source File: ProgramResult.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.evm

import jbok.common.math.N
import jbok.core.models.{Address, TxLogEntry}
import scodec.bits.ByteVector


final case class ProgramResult[F[_]](
    returnData: ByteVector,
    gasRemaining: N,
    world: WorldState[F],
    addressesToDelete: Set[Address],
    logs: List[TxLogEntry],
    internalTxs: List[InternalTransaction],
    gasRefund: N,
    error: Option[ProgramError],
    isRevert: Boolean = false,
    contractAddress: Option[Address] = None,
) 
Example 73
Source File: Program.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.evm

import scodec.bits.ByteVector

import scala.annotation.tailrec


  @tailrec
  private def validJumpDestinationsAfterPosition(pos: Int, accum: Set[Int] = Set.empty): Set[Int] =
    if (pos < 0 || pos >= length) accum
    else {
      val byte = code(pos)
      val opCode = frontierConfig.byteToOpCode.get(byte) // we only need to check PushOp and JUMPDEST, they are both present in Frontier
      opCode match {
        case Some(pushOp: PushOp) => validJumpDestinationsAfterPosition(pos + pushOp.i + 2, accum)
        case Some(JUMPDEST)       => validJumpDestinationsAfterPosition(pos + 1, accum + pos)
        case _                    => validJumpDestinationsAfterPosition(pos + 1, accum)
      }
    }
} 
Example 74
Source File: ProgramContext.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.evm

import cats.effect.Sync
import jbok.common.math.N
import jbok.core.models.{Address, BlockHeader, SignedTransaction, UInt256}
import scodec.bits.ByteVector

object ProgramContext {
  def apply[F[_]: Sync](
      stx: SignedTransaction,
      senderAddress: Address,
      recipientAddress: Address,
      program: Program,
      blockHeader: BlockHeader,
      world: WorldState[F],
      config: EvmConfig
  ): ProgramContext[F] = {

    // YP eq (91)
    val inputData =
      if (stx.isContractInit) ByteVector.empty
      else stx.payload

    val env = ExecEnv(
      recipientAddress,
      senderAddress,
      senderAddress,
      UInt256(stx.gasPrice),
      inputData,
      UInt256(stx.value),
      program,
      blockHeader,
      callDepth = 0
    )

    val gasLimit = stx.gasLimit - config.calcTransactionIntrinsicGas(stx.payload, stx.isContractInit)

    ProgramContext[F](env, recipientAddress, gasLimit, world, config)
  }
}


final case class ProgramContext[F[_]: Sync](
    env: ExecEnv,
    receivingAddr: Address,
    startGas: N,
    world: WorldState[F],
    config: EvmConfig,
    initialAddressesToDelete: Set[Address] = Set.empty,
    readOnly: Boolean = false
) 
Example 75
Source File: BloomFilter.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.core.ledger

import jbok.core.models.TxLogEntry
import jbok.common.ByteUtils
import scodec.bits.ByteVector
import jbok.crypto._

object BloomFilter {
  val BloomFilterByteSize: Int = 256
  val BloomFilterBitSize: Int = BloomFilterByteSize * 8
  val EmptyBloomFilter: ByteVector = ByteVector(Array.fill(BloomFilterByteSize)(0.toByte))
  private val IntIndexesToAccess: Set[Int] = Set(0, 2, 4)

  def containsAnyOf(bloomFilterBytes: ByteVector, toCheck: List[ByteVector]): Boolean =
    toCheck.exists { bytes =>
      val bloomFilterForBytes = bloomFilter(bytes)

      val andResult = ByteUtils.and(bloomFilterForBytes, bloomFilterBytes)
      andResult == bloomFilterForBytes
    }

  
  def create(logs: Seq[TxLogEntry]): ByteVector = {
    val bloomFilters = logs.map(createBloomFilterForLogEntry)
    if (bloomFilters.isEmpty)
      EmptyBloomFilter
    else
      ByteUtils.or(bloomFilters: _*)
  }

  // Bloom filter function that reduces a log to a single 256-byte hash based on equation 24 from the YP
  private def createBloomFilterForLogEntry(logEntry: TxLogEntry): ByteVector = {
    val dataForBloomFilter = logEntry.loggerAddress.bytes +: logEntry.logTopics
    val bloomFilters = dataForBloomFilter.map(bytes => bloomFilter(bytes))
    ByteUtils.or(bloomFilters: _*)
  }

  // Bloom filter that sets 3 bits out of 2048 based on equations 25-28 from the YP
  private def bloomFilter(bytes: ByteVector): ByteVector = {
    val hashedBytes = bytes.kec256
    val bitsToSet = IntIndexesToAccess.map { i =>
      val index16bit = (hashedBytes(i + 1) & 0xFF) + ((hashedBytes(i) & 0xFF) << 8)
      index16bit % BloomFilterBitSize //Obtain only 11 bits from the index
    }
    bitsToSet.foldLeft(EmptyBloomFilter) { case (prevBloom, index) => setBit(prevBloom, index) }.reverse
  }

  private def setBit(bytes: ByteVector, bitIndex: Int): ByteVector = {
    require(bitIndex / 8 < bytes.length, "Only bits between the bytes array should be set")

    val byteIndex = bitIndex / 8
    val newByte: Byte = (bytes(byteIndex) | 1 << (bitIndex % 8).toByte).toByte
    bytes.update(byteIndex, newByte)
  }
} 
Example 76
Source File: AccountAPI.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.core.api

import io.circe.generic.extras.ConfiguredJsonCodec
import jbok.core.models.{Account, Address, SignedTransaction}
import scodec.bits.ByteVector
import jbok.codec.json.implicits._
import jbok.common.math.N
import jbok.network.rpc.PathName

@ConfiguredJsonCodec
final case class HistoryTransaction(
    txHash: ByteVector,
    nonce: N,
    fromAddress: Address,
    toAddress: Address,
    value: N,
    payload: String,
    v: N,
    r: N,
    s: N,
    gasUsed: N,
    gasPrice: N,
    blockNumber: N,
    blockHash: ByteVector,
    location: Int
)

@PathName("account")
trait AccountAPI[F[_]] {
  def getAccount(address: Address, tag: BlockTag = BlockTag.latest): F[Account]

  def getCode(address: Address, tag: BlockTag = BlockTag.latest): F[ByteVector]

  def getBalance(address: Address, tag: BlockTag = BlockTag.latest): F[N]

  def getStorageAt(address: Address, position: N, tag: BlockTag = BlockTag.latest): F[ByteVector]

  def getTransactions(address: Address, page: Int, size: Int): F[List[HistoryTransaction]]

  def getTransactionsByNumber(number: Int): F[List[HistoryTransaction]]

//  def getTokenTransactions(address: Address, contract: Option[Address]): F[List[SignedTransaction]]

  def getPendingTxs(address: Address): F[List[SignedTransaction]]

  def getEstimatedNonce(address: Address): F[N]
} 
Example 77
Source File: PersonalAPI.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.core.api

import jbok.common.math.N
import jbok.core.models.Address
import jbok.network.rpc.PathName
import scodec.bits.ByteVector

@PathName("personal")
trait PersonalAPI[F[_]] {
  def importRawKey(privateKey: ByteVector, passphrase: String): F[Address]

  def newAccount(passphrase: String): F[Address]

  def delAccount(address: Address): F[Boolean]

  def listAccounts: F[List[Address]]

  def changePassphrase(address: Address, oldPassphrase: String, newPassphrase: String): F[Boolean]

  def sendTransaction(
      from: Address,
      passphrase: String,
      to: Option[Address] = None,
      value: Option[N] = None,
      gasLimit: Option[N] = None,
      gasPrice: Option[N] = None,
      nonce: Option[N] = None,
      data: Option[ByteVector] = None,
  ): F[ByteVector]
} 
Example 78
Source File: ContractAPI.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.core.api

import io.circe.generic.extras.ConfiguredJsonCodec
import jbok.core.models.Address
import scodec.bits.ByteVector
import jbok.codec.json.implicits._
import jbok.common.math.N
import jbok.network.rpc.PathName

import scala.scalajs.js.annotation.JSExportAll

@JSExportAll
@ConfiguredJsonCodec
final case class CallTx(
    from: Option[Address],
    to: Option[Address],
    gas: Option[N],
    gasPrice: N,
    value: N,
    data: ByteVector
)

@PathName("contract")
trait ContractAPI[F[_]] {
//  def getABI(address: Address): F[Option[ContractDef]]
//
//  def getSourceCode(address: Address): F[Option[String]]

  def call(callTx: CallTx, tag: BlockTag = BlockTag.latest): F[ByteVector]

  def getEstimatedGas(callTx: CallTx, tag: BlockTag = BlockTag.latest): F[N]

  def getGasPrice: F[N]
} 
Example 79
Source File: NewBlock.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.core.messages

import io.circe.generic.extras.ConfiguredJsonCodec
import jbok.codec.json.implicits._
import jbok.codec.rlp.RlpCodec
import jbok.common.math.N
import jbok.core.models.Block
import scodec.bits.ByteVector

@ConfiguredJsonCodec final case class BlockHash(hash: ByteVector, number: N)
object BlockHash {
  val name = "BlockHash"

  implicit val rlpCodec: RlpCodec[BlockHash] = RlpCodec.gen[BlockHash]
}

@ConfiguredJsonCodec final case class NewBlockHashes(hashes: List[BlockHash])
object NewBlockHashes {
  val name = "NewBlockHashes"

  implicit val rlpCodec: RlpCodec[NewBlockHashes] = RlpCodec.gen[NewBlockHashes]
}

@ConfiguredJsonCodec final case class NewBlock(block: Block)
object NewBlock {
  val name = "NewBlock"

  implicit val rlpCodec: RlpCodec[NewBlock] = RlpCodec.gen[NewBlock]
} 
Example 80
Source File: Account.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.core.models

import io.circe.generic.extras.ConfiguredJsonCodec
import jbok.codec.json.implicits._
import jbok.crypto._
import jbok.persistent.mpt.MerklePatriciaTrie
import scodec.bits.ByteVector

import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel}

@JSExportTopLevel("Account")
@JSExportAll
@ConfiguredJsonCodec
final case class Account(
    nonce: UInt256 = 0,
    balance: UInt256 = 0,
    storageRoot: ByteVector = Account.EmptyStorageRootHash,
    codeHash: ByteVector = Account.EmptyCodeHash
) {
  def increaseBalance(value: UInt256): Account =
    copy(balance = balance + value)

  def increaseNonce(value: UInt256 = 1): Account =
    copy(nonce = nonce + value)

  def withCode(codeHash: ByteVector): Account =
    copy(codeHash = codeHash)

  def withStorage(storageRoot: ByteVector): Account =
    copy(storageRoot = storageRoot)

  
  def nonEmptyCodeOrNonce(startNonce: UInt256 = UInt256.zero): Boolean =
    nonce != startNonce || codeHash != Account.EmptyCodeHash
}

object Account {
  val EmptyStorageRootHash: ByteVector = MerklePatriciaTrie.emptyRootHash

  val EmptyCodeHash: ByteVector = ByteVector.empty.kec256

  def empty(startNonce: UInt256 = UInt256.zero): Account =
    Account(nonce = startNonce, storageRoot = EmptyStorageRootHash, codeHash = EmptyCodeHash)
} 
Example 81
Source File: Transaction.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.core.models

import io.circe.generic.extras.ConfiguredJsonCodec
import scodec.bits.ByteVector
import jbok.codec.json.implicits._
import jbok.common.math.N

import scala.scalajs.js.annotation.{JSExportAll, JSExportTopLevel}

@JSExportTopLevel("Transaction")
@JSExportAll
@ConfiguredJsonCodec
final case class Transaction(
    nonce: N,
    gasPrice: N,
    gasLimit: N,
    receivingAddress: Option[Address],
    value: N,
    payload: ByteVector
) 
Example 82
Source File: Peer.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.core.peer

import cats.effect.concurrent.Ref
import cats.effect.{Concurrent, Sync}
import cats.implicits._
import fs2.concurrent.Queue
import jbok.core.messages.{SignedTransactions, Status}
import jbok.network.Message
import scodec.bits.ByteVector
import jbok.codec.rlp.implicits._
import jbok.common.log.Logger
import jbok.common.math.N
import jbok.crypto._

final case class Peer[F[_]](
    uri: PeerUri,
    queue: Queue[F, Message[F]],
    status: Ref[F, Status],
    knownBlocks: Ref[F, Set[ByteVector]],
    knownTxs: Ref[F, Set[ByteVector]]
)(implicit F: Sync[F]) {
  import Peer._

  private[this] val log = Logger[F]

  def hasBlock(blockHash: ByteVector): F[Boolean] =
    knownBlocks.get.map(_.contains(blockHash))

  def hasTxs(stxs: SignedTransactions): F[Boolean] =
    knownTxs.get.map(_.contains(stxs.encoded.bytes.kec256))

  def markBlock(blockHash: ByteVector, number: N): F[Unit] =
    knownBlocks.update(s => s.take(MaxKnownBlocks - 1) + blockHash) >>
      status.update(s => s.copy(bestNumber = s.bestNumber.max(number)))

  def markTxs(stxs: SignedTransactions): F[Unit] =
    knownTxs.update(known => known.take(MaxKnownTxs - 1) + stxs.encoded.bytes.kec256)

  def markStatus(newStatus: Status): F[Unit] =
    status.update(s => if (newStatus.td > s.td) s.copy(bestNumber = newStatus.bestNumber, td = newStatus.td) else s)
}

object Peer {
  val MaxKnownTxs    = 32768
  val MaxKnownBlocks = 1024

  def apply[F[_]: Concurrent](uri: PeerUri, status: Status): F[Peer[F]] =
    for {
      queue       <- Queue.circularBuffer[F, Message[F]](100000)
      status      <- Ref.of[F, Status](status)
      knownBlocks <- Ref.of[F, Set[ByteVector]](Set.empty)
      knownTxs    <- Ref.of[F, Set[ByteVector]](Set.empty)
    } yield Peer[F](uri, queue, status, knownBlocks, knownTxs)
} 
Example 83
Source File: KeyStore.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.core.keystore

import jbok.core.models.Address
import scodec.bits.ByteVector

object KeyStoreError {
  final case object KeyNotFound         extends Exception("KeyNotFound")
  final case object KeyAlreadyExist     extends Exception("KeyAlreadyExist")
  final case object DecryptionFailed    extends Exception("DecryptionFailed")
  final case object InvalidKeyFormat    extends Exception("InvalidKeyFormat")
  final case class IOError(msg: String) extends Exception(s"IO error, ${msg}")
}

trait KeyStore[F[_]] {
  def newAccount(passphrase: String): F[Address]

  def readPassphrase(prompt: String): F[String]

  def importPrivateKey(key: ByteVector, passphrase: String): F[Address]

  def listAccounts: F[List[Address]]

  def unlockAccount(address: Address, passphrase: String): F[Wallet]

  def deleteAccount(address: Address): F[Boolean]

  def changePassphrase(
      address: Address,
      oldPassphrase: String,
      newPassphrase: String
  ): F[Boolean]
} 
Example 84
Source File: MockingKeyStore.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.core.keystore

import cats.effect.Sync
import cats.implicits._
import cats.effect.concurrent.Ref
import jbok.core.models.Address
import jbok.crypto.signature.{ECDSA, KeyPair, Signature}
import scodec.bits.ByteVector

final class MockingKeyStore[F[_]](implicit F: Sync[F]) extends KeyStore[F] {
  private val m: Ref[F, Map[Address, KeyPair]] = Ref.unsafe(Map.empty)

  override def newAccount(passphrase: String): F[Address] =
    for {
      kp <- Signature[ECDSA].generateKeyPair[F]()
      _  <- m.update(_ + (Address(kp) -> kp))
    } yield Address(kp)

  override def readPassphrase(prompt: String): F[String] =
    ???

  override def importPrivateKey(key: ByteVector, passphrase: String): F[Address] =
    for {
      secret <- KeyPair.Secret(key).pure[F]
      public <- Signature[ECDSA].generatePublicKey[F](secret)
      kp      = KeyPair(public, secret)
      address = Address(kp)
      _ <- m.update(_ + (address -> kp))
    } yield address

  override def listAccounts: F[List[Address]] =
    m.get.map(_.keys.toList)

  override def unlockAccount(address: Address, passphrase: String): F[Wallet] =
    m.get.map(_(address)).map { kp =>
      Wallet(Address(kp), kp)
    }

  override def deleteAccount(address: Address): F[Boolean] =
    m.update(_ - address).as(true)

  override def changePassphrase(address: Address, oldPassphrase: String, newPassphrase: String): F[Boolean] =
    F.pure(true)
}

object MockingKeyStore {
  def withInitKeys[F[_]: Sync](initKeys: List[KeyPair]): F[MockingKeyStore[F]] = {
    val keystore = new MockingKeyStore[F]()
    initKeys.traverse(kp => keystore.importPrivateKey(kp.secret.bytes, "")).as(keystore)
  }
} 
Example 85
Source File: byteVector.scala    From refined   with MIT License 5 votes vote down vote up
package eu.timepit.refined.scodec

import eu.timepit.refined.api.Validate
import eu.timepit.refined.collection.Size
import eu.timepit.refined.internal.Resources
import scodec.bits.ByteVector


object byteVector extends ByteVectorValidate

private[refined] trait ByteVectorValidate {
  implicit def byteVectorSizeValidate[P, RP](
      implicit v: Validate.Aux[Long, P, RP]
  ): Validate.Aux[ByteVector, Size[P], Size[v.Res]] =
    new Validate[ByteVector, Size[P]] {
      override type R = Size[v.Res]

      override def validate(t: ByteVector): Res = {
        val r = v.validate(t.size)
        r.as(Size(r))
      }

      override def showExpr(t: ByteVector): String =
        v.showExpr(t.size)

      override def showResult(t: ByteVector, r: Res): String = {
        val size = t.size
        val nested = v.showResult(size, r.detail.p)
        Resources.predicateTakingResultDetail(s"size($t) = $size", r, nested)
      }
    }
} 
Example 86
Source File: ByteVectorValidateSpec.scala    From refined   with MIT License 5 votes vote down vote up
package eu.timepit.refined.scodec

import eu.timepit.refined.TestUtils._
import eu.timepit.refined.W
import eu.timepit.refined.collection.Size
import eu.timepit.refined.generic.Equal
import eu.timepit.refined.numeric.Greater
import eu.timepit.refined.scodec.byteVector._
import org.scalacheck.Prop._
import org.scalacheck.Properties
import scodec.bits.ByteVector

class ByteVectorValidateSpec extends Properties("ByteVectorValidate") {

  property("Size.isValid") = forAll { bytes: Array[Byte] =>
    val bv = ByteVector(bytes)
    isValid[Size[Greater[W.`5L`.T]]](bv) ?= (bv.size > 5L)
  }

  property("Size.showExpr") = secure {
    showExpr[Size[Equal[W.`5L`.T]]](ByteVector.fromValidHex("0xdeadbeef")) ?= "(4 == 5)"
  }

  property("Size.showResult") = secure {
    showResult[Size[Equal[W.`5L`.T]]](ByteVector.fromValidHex("0xdeadbeef")) ?=
      "Predicate taking size(ByteVector(4 bytes, 0xdeadbeef)) = 4 failed: Predicate failed: (4 == 5)."
  }

} 
Example 87
Source File: Text.scala    From benchmarks   with Apache License 2.0 5 votes vote down vote up
package com.rossabaker
package benchmarks

import org.openjdk.jmh.annotations._

@State(Scope.Thread)
@Fork(2)
@Measurement(iterations = 10)
@Warmup(iterations = 10)
@Threads(1)
class Text extends BenchmarkUtils {
  val LoremIpsum: String =
    scala.io.Source.fromFile("testdata/lorem-ipsum.txt")
      .getLines
      .mkString("\n")

  val LoremIpsumBytes: Array[Byte] =
    LoremIpsum.getBytes(java.nio.charset.StandardCharsets.UTF_8)

  @Benchmark
  def fs2EncodeDecode(): String = {
    import _root_.fs2._, Stream._
    emit(LoremIpsum)
      .covary[Task]
      .through(text.utf8Encode)
      .through(text.utf8Decode)
      .runFold("")(_ + _)
      .unsafeRun
  }

  @Benchmark
  def fs2Wc(): Int = {
    import _root_.fs2._, Stream._
    emit(LoremIpsum)
      .covary[Task]
      .through(text.lines)
      .fold(0)((acc, _) => acc + 1)
      .runLast
      .unsafeRun
      .getOrElse(0)
  }

  @Benchmark
  def scalazStreamEncodeDecode(): String = {
    import _root_.scalaz.stream._, Process._
    import scodec.bits.ByteVector
    import scalaz.std.string._
    emit(LoremIpsum)
      .toSource
      .pipe(text.utf8Encode)
      .pipe(text.utf8Decode)
      .runFoldMap(identity)
      .unsafePerformSync
  }

  @Benchmark
  def scalazStreamWc(): Int = {
    import _root_.scalaz.stream._, Process._
    import scodec.bits.ByteVector
    import scalaz.std.anyVal._
    emit(LoremIpsum)
      .toSource
      .pipe(text.lines())
      .fold(0)((acc, _) => acc + 1)
      .runLastOr(0)
      .unsafePerformSync
  }
} 
Example 88
Source File: UUIDUtils.scala    From seals   with Apache License 2.0 5 votes vote down vote up
package dev.tauri.seals
package core

import java.util.UUID
import java.nio.charset.StandardCharsets

import scala.language.implicitConversions

import scodec.bits.ByteVector

final object UUIDUtils {

  implicit final class UUIDSyntax(private val self: UUID) extends AnyVal {
    def / (sub: UUID): UUIDBuilder = UUIDBuilder(self) / sub
    def / (sub: ByteVector): UUIDBuilder = UUIDBuilder(self) / sub
    def / (sub: String): UUIDBuilder = UUIDBuilder(self) / sub
  }

  final case class UUIDBuilder(namespace: UUID, name: Vector[ByteVector] = Vector.empty) {
    def / (sub: UUID): UUIDBuilder = copy(name = name :+ NsUUID.bvFromUUID(sub))
    def / (sub: ByteVector): UUIDBuilder = copy(name = name :+ sub)
    def / (sub: String): UUIDBuilder = copy(name = name :+ ByteVector.view(sub.getBytes(StandardCharsets.UTF_8)))
    def uuid: UUID = NsUUID.uuid5nestedBv(namespace, name: _*)
  }

  implicit def uuidLiteralSyntax(sc: StringContext): macros.UUIDSyntax =
    new macros.UUIDSyntax(sc)
} 
Example 89
Source File: NsUUID.scala    From seals   with Apache License 2.0 5 votes vote down vote up
package dev.tauri.seals
package core

import java.util.UUID
import java.security.MessageDigest
import java.nio.{ ByteBuffer, Buffer }
import java.nio.charset.StandardCharsets

import scodec.bits.ByteVector

private[seals] object NsUUID {

  def uuid5(ns: UUID, name: String): UUID =
    uuid5bytes(ns, ByteBuffer.wrap(name.getBytes(StandardCharsets.UTF_8)))

  def uuid5bv(ns: UUID, name: ByteVector): UUID =
    uuid5bytes(ns, name.toByteBuffer)

  private def uuid5bytes(ns: UUID, name: ByteBuffer): UUID = {
    val buf = ByteBuffer.allocate(16) // network byte order by default
    putUUIDToBuf(ns, buf)
    (buf : Buffer).rewind()
    val h = sha1()
    h.update(buf)
    h.update(name)
    val arr: Array[Byte] = h.digest().take(16)
    arr(6) = (arr(6) & 0x0f).toByte // clear version
    arr(6) = (arr(6) | 0x50).toByte // version 5
    arr(8) = (arr(8) & 0x3f).toByte // clear variant
    arr(8) = (arr(8) | 0x80).toByte // variant RFC4122
    (buf : Buffer).rewind()
    buf.put(arr)
    (buf : Buffer).rewind()
    val msl = buf.getLong()
    val lsl = buf.getLong()
    new UUID(msl, lsl)
  }

  def uuid5nested(root: UUID, names: String*): UUID =
    names.foldLeft(root)(uuid5)

  def uuid5nestedBv(root: UUID, names: ByteVector*): UUID = {
    val buf = ByteVector.concat(names).toByteBuffer
    uuid5bytes(root, buf)
  }

  def uuid5nestedNsNm(name: String, ns1: UUID, nss: UUID*): UUID =
    uuid5(uuid5nestedNs(ns1, nss: _*), name)

  def uuid5nestedNs(ns1: UUID, nss: UUID*): UUID = {
    val buf = ByteBuffer.allocate(16)
    nss.foldLeft(ns1) { (st, u) =>
      putUUIDToBuf(u, buf)
      (buf : Buffer).rewind()
      val r = uuid5bytes(st, buf)
      (buf : Buffer).rewind()
      r
    }
  }

  private def putUUIDToBuf(u: UUID, buf: ByteBuffer): Unit = {
    buf.putLong(u.getMostSignificantBits)
    buf.putLong(u.getLeastSignificantBits)
  }

  def bvFromUUID(u: UUID): ByteVector = {
    val buf = ByteBuffer.allocate(16)
    putUUIDToBuf(u, buf)
    (buf : Buffer).rewind()
    ByteVector.view(buf)
  }

  private def sha1(): MessageDigest =
    MessageDigest.getInstance("SHA-1")
} 
Example 90
Source File: SignTest.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.crypto

import org.bitcoins.testkit.core.gen.CryptoGenerators
import org.bitcoins.testkit.util.BitcoinSUnitTest
import scodec.bits.ByteVector

import scala.concurrent.{ExecutionContext, Future}

class SignTest extends BitcoinSUnitTest {
  implicit val ec = ExecutionContext.global

  //ECPrivateKey implements the sign interface
  //so just use it for testing purposes
  val signTestImpl = new Sign {
    private val key = ECPrivateKey.freshPrivateKey

    override def signFunction: ByteVector => Future[ECDigitalSignature] = {
      key.signFunction
    }

    override def publicKey: ECPublicKey = key.publicKey
  }

  behavior of "Sign"

  it must "sign arbitrary pieces of data correctly" in {
    forAll(CryptoGenerators.sha256Digest) {
      case hash: Sha256Digest =>
        val pubKey = signTestImpl.publicKey
        val sigF = signTestImpl.signFunction(hash.bytes)

        sigF.map(sig => assert(pubKey.verify(hash.hex, sig)))
    }
  }
} 
Example 91
Source File: HashTypeTest.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.script.crypto

import org.bitcoins.core.number.Int32
import org.bitcoins.testkit.util.BitcoinSUnitTest
import scodec.bits.ByteVector


class HashTypeTest extends BitcoinSUnitTest {

  "HashType" must "combine hash types with SIGHASH_ANYONECANPAY" in {
    HashType.sigHashAllAnyoneCanPay.num must be(Int32(0x81))
    HashType.sigHashNoneAnyoneCanPay.num must be(Int32(0x82))
    HashType.sigHashSingleAnyoneCanPay.num must be(Int32(0x83))
  }

  it must "find a hash type by its hex value" in {
    HashType("00000001") must be(HashType.sigHashAll)
    HashType("00000002") must be(HashType.sigHashNone)
    HashType("00000003") must be(HashType.sigHashSingle)
    HashType("00000080") must be(HashType.sigHashAnyoneCanPay)
  }

  it must "find a hash type by its byte value" in {
    HashType(0.toByte) must be(SIGHASH_ALL(Int32.zero))
    HashType(1.toByte) must be(SIGHASH_ALL(Int32.one))
    HashType(2.toByte) must be(HashType.sigHashNone)
    HashType(3.toByte) must be(HashType.sigHashSingle)
    HashType(0x80) must be(HashType.sigHashAnyoneCanPay)

  }

  it must "default to SIGHASH_ALL if the given string/byte is not known" in {
    HashType(ByteVector(0x124.toByte)) must be(SIGHASH_ALL(Int32(36)))
  }

  it must "find hashType for number 1190874345" in {
    //1190874345 & 0x80 = 0x80
    val num = Int32(1190874345)
    HashType(num).isInstanceOf[SIGHASH_ANYONECANPAY] must be(true)
    HashType(num.bytes).isInstanceOf[SIGHASH_ANYONECANPAY] must be(true)
  }

  it must "determine if a given number is of hashType SIGHASH_ALL" in {
    HashType.isSigHashAll(Int32.zero) must be(true)
    HashType.isSigHashAll(Int32.one) must be(true)
    HashType.isSigHashAll(Int32(5)) must be(true)

    HashType.isSigHashAll(HashType.sigHashNone.num) must be(false)
    HashType.isSigHashAll(HashType.sigHashSingle.num) must be(false)
  }

  it must "return the correct byte for a given hashtype" in {
    SIGHASH_ALL(HashType.sigHashAllByte).byte must be(0x01.toByte)
    HashType.sigHashNone.byte must be(0x02.toByte)
    HashType.sigHashSingle.byte must be(0x03.toByte)
    HashType.sigHashAnyoneCanPay.byte must be(0x80.toByte)
    HashType.sigHashAllAnyoneCanPay.byte must be(0x81.toByte)
    HashType.sigHashNoneAnyoneCanPay.byte must be(0x82.toByte)
    HashType.sigHashSingleAnyoneCanPay.byte must be(0x83.toByte)
  }

  it must "intercept require statements for each hashType with illegal inputs" in {
    intercept[IllegalArgumentException] {
      SIGHASH_ALL(Int32(2))
    }
  }

  it must "find each specific hashType from byte sequence of default value" in {
    //tests each hashtypes overriding fromBytes function
    HashType(HashType.sigHashAll.num.bytes) must be(HashType.sigHashAll)
    HashType(HashType.sigHashNone.num.bytes) must be(HashType.sigHashNone)
    HashType(HashType.sigHashSingle.num.bytes) must be(HashType.sigHashSingle)
    HashType(HashType.sigHashAnyoneCanPay.num.bytes) must be(
      HashType.sigHashAnyoneCanPay)
    HashType(HashType.sigHashAllAnyoneCanPay.num.bytes) must be(
      HashType.sigHashAllAnyoneCanPay)
    HashType(HashType.sigHashNoneAnyoneCanPay.num.bytes) must be(
      HashType.sigHashNoneAnyoneCanPay)
    HashType(HashType.sigHashSingleAnyoneCanPay.num.bytes) must be(
      HashType.sigHashSingleAnyoneCanPay)
  }

  it must "find a hashtype with only an integer" in {
    HashType(105512910).isInstanceOf[SIGHASH_ANYONECANPAY] must be(true)
  }

} 
Example 92
Source File: ScriptSignatureFactoryTest.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.protocol.script

import org.bitcoins.core.util.BytesUtil
import org.bitcoins.crypto.{ECDigitalSignature, ECPublicKey}
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
import scodec.bits.ByteVector


class ScriptSignatureFactoryTest extends BitcoinSUnitTest {

  "ScriptSignatureFactory" must "give the exact same result whether parsing bytes or parsing hex" in {
    val signatureHex =
      "30450221008949f0cb400094ad2b5eb399d59d01c14d73d8fe6e96df1a7150deb388ab8935022079656090d7" +
        "f6bac4c9a94e0aad311a4268e082a725f8aeae0573fb12ff866a5f01"
    val signatureBytes: ByteVector = BytesUtil.decodeHex(signatureHex)

    val scriptSigFromHex = ScriptSignature(signatureHex)
    val scriptSigFromBytes = ScriptSignature(signatureBytes)

    scriptSigFromHex must be(scriptSigFromBytes)

  }

  it must "build a script signature from a digital signature and a public key" in {
    val digitalSignatureBytes = TestUtil.p2pkhInputScriptAsm(1).bytes
    val digitalSignature: ECDigitalSignature =
      ECDigitalSignature(digitalSignatureBytes)
    val publicKeyBytes = TestUtil.p2pkhInputScriptAsm(3).bytes
    val publicKey: ECPublicKey = ECPublicKey(publicKeyBytes)
    val actualScriptSig: ScriptSignature =
      P2PKHScriptSignature(digitalSignature, publicKey)
    actualScriptSig.asm must be(TestUtil.p2pkhInputScriptAsm)
  }

  it must "parse a p2pk scriptSignature from a raw scriptSig" in {
    val rawScriptSig = TestUtil.rawP2PKScriptSig
    val scriptSig = ScriptSignature(rawScriptSig)
    val result = scriptSig match {
      case s: P2PKScriptSignature => true
      case _                      => false
    }
    result must be(true)

  }

  it must "parse a p2sh scriptSignature from a raw scriptSig" in {
    val result = TestUtil.p2shInputScript2Of2 match {
      case s: P2SHScriptSignature => true
      case y                      => throw new RuntimeException("Should be p2sh input: " + y)
    }
    result must be(true)
  }
} 
Example 93
Source File: P2PKHScriptSignatureTest.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.protocol.script

import org.bitcoins.core.script.crypto.HashType
import org.bitcoins.crypto.ECDigitalSignature
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
import scodec.bits.ByteVector


class P2PKHScriptSignatureTest extends BitcoinSUnitTest {

  "P2PKHScriptSignature" must "be able to identify it's own hash type" in {
    val p2pkhScriptSig = TestUtil.p2pkhScriptSig match {
      case s: P2PKHScriptSignature => s
      case _                       => throw new RuntimeException("Must be p2pkh scriptSig")
    }
    HashType.fromBytes(
      ByteVector.fromByte(p2pkhScriptSig.signatures.head.bytes.last)) must be(
      HashType.sigHashAll)
  }

  it must "be able to identify the signature in a p2pkh scriptSig" in {
    val p2pkhScriptSig = TestUtil.p2pkhScriptSig match {
      case s: P2PKHScriptSignature => s
      case _                       => throw new RuntimeException("Must be p2pkh scriptSig")
    }
    p2pkhScriptSig.signature must be(ECDigitalSignature(
      "3044022016ffdbb7c57634903c5e018fcfc48d59f4e37dc4bc3bbc9ba4e6ee39150bca030220119c2241a931819bc1a75d3596e4029d803d1cd6de123bf8a1a1a2c3665e1fac01"))
  }

} 
Example 94
Source File: UInt64Test.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.number

import org.bitcoins.testkit.util.BitcoinSUnitTest
import scodec.bits.ByteVector


class UInt64Test extends BitcoinSUnitTest {

  "UInt64" must "hold the number 0" in {
    val uInt64 = UInt64(ByteVector.low(1))
    uInt64.hex must be("0000000000000000")
    uInt64.toBigInt must be(0)
  }

  it must "encode the number 1" in {
    val uInt64 = UInt64(1)
    uInt64.toBigInt must be(1)
    uInt64.hex must be("0000000000000001")
  }

  it must "hold the max for a uint32_t" in {
    //this is UInt32_t's max value
    val uInt64 =
      UInt64(ByteVector(0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
    uInt64.toBigInt must be(4294967295L)
  }

  it must "hold the max for uint32_t + 1" in {
    val uInt64 =
      UInt64(ByteVector(1.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte))
    uInt64.toBigInt must be(4294967296L)
  }

  it must "hold the max number for uint64_t" in {
    val uInt64 = UInt64(
      ByteVector(0xff.toByte,
                 0xff.toByte,
                 0xff.toByte,
                 0xff.toByte,
                 0xff.toByte,
                 0xff.toByte,
                 0xff.toByte,
                 0xff.toByte))
    uInt64.toBigInt must be(BigInt("18446744073709551615"))
    uInt64.hex must be("ffffffffffffffff")
  }

  it must "throw an exception if we try and create a number larger than 8 bytes" in {
    intercept[IllegalArgumentException] {
      UInt64(
        ByteVector(1.toByte,
                   0.toByte,
                   0.toByte,
                   0.toByte,
                   0.toByte,
                   0.toByte,
                   0.toByte,
                   0.toByte,
                   0.toByte))
    }
  }

  it must "have the correct representation for 0" in {
    UInt64.zero.toBigInt must be(0)
  }

  it must "have the correct representation for 1" in {
    UInt64.one.toBigInt must be(1)
  }

  it must "have the correct min number for a UInt64" in {
    UInt64.min.toBigInt must be(0)
  }

  it must "have the correct max number for a UInt64" in {
    UInt64.max.toBigInt must be(BigInt("18446744073709551615"))
  }

  it must "throw an exception if we try to create a BigInt outside the range of UInt64" in {
    intercept[IllegalArgumentException] {
      UInt64(UInt64.max.toBigInt + 1)
    }
  }
} 
Example 95
Source File: UInt32Test.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.number

import org.bitcoins.testkit.util.BitcoinSUnitTest
import scodec.bits.ByteVector


class UInt32Test extends BitcoinSUnitTest {

  "UInt32" must "create the number zero as an unsigned 32 bit integer" in {
    val zero = UInt32(ByteVector(0x0.toByte))
    zero.toLong must be(0)
  }

  it must "create the max number for an unsigned byte" in {
    val maxByteValue = UInt32(ByteVector(0xff.toByte))
    maxByteValue.toLong must be(255)
  }

  it must "create the number 256" in {
    val uInt32 = UInt32(ByteVector(0x01.toByte, 0x00.toByte))
    uInt32.toLong must be(256)
  }

  it must "create the number 65535" in {
    val uInt32 = UInt32(ByteVector(0xff.toByte, 0xff.toByte))
    uInt32.toLong must be(65535)
  }

  it must "create the number 65536" in {
    val uInt32 = UInt32(ByteVector(0x01.toByte, 0x0.toByte, 0x0.toByte))
    uInt32.toLong must be(65536)
  }

  it must "create the number 16777215" in {
    val uInt32 = UInt32(ByteVector(0xff.toByte, 0xff.toByte, 0xff.toByte))
    uInt32.toLong must be(16777215)
  }

  it must "create the number 16777216" in {
    val uInt32 = UInt32(ByteVector(1.toByte, 0.toByte, 0.toByte, 0.toByte))
    uInt32.toLong must be(16777216)
  }

  it must "create the number 4294967295" in {
    //this is UInt32_t's max value
    val uInt32 =
      UInt32(ByteVector(0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
    uInt32.toLong must be(4294967295L)
    uInt32.hex must be("ffffffff")
  }

  it must "throw an exception if we try and create a UInt32 with a negative number" in {
    intercept[IllegalArgumentException] {
      UInt32(-1)
    }
  }

  it must "throw an exception if we try and create a UInt32 with more than 4 bytes" in {
    intercept[IllegalArgumentException] {
      UInt32(ByteVector(0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte))
    }
  }

  it must "have the correct representation for 0" in {
    UInt32.zero.toLong must be(0)
  }

  it must "have the correct representation for 1" in {
    UInt32.one.toLong must be(1)
  }

  it must "have the correct minimum number for a UInt32" in {
    UInt32.min.toLong must be(0)
  }

  it must "have the correct maximum number representation for UInt32" in {
    UInt32.max.toLong must be(4294967295L)
    UInt32.max.hex must be("ffffffff")
  }

  it must "throw an exception if we try to create a BigInt outside the range of UInt32" in {
    intercept[IllegalArgumentException] {
      UInt32(UInt32.max.toBigInt + 1)
    }
  }
} 
Example 96
Source File: Int32Test.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.number

import org.bitcoins.testkit.util.BitcoinSUnitTest
import scodec.bits.ByteVector


class Int32Test extends BitcoinSUnitTest {

  "Int32" must "create the number zero" in {
    val int32 = Int32(ByteVector.low(1))
    int32.toInt must be(0)
  }

  it must "represent the number -1" in {
    val int32 = Int32(ByteVector(0xff.toByte))
    int32.toInt must be(-1)
  }

  it must "represent the number -1 with 4 bytes" in {
    val int32 =
      Int32(ByteVector(0xff.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
    int32.toInt must be(-1)
  }

  it must "create the max number for a single byte" in {
    val int32 = Int32(ByteVector(0x7f.toByte))
    int32.toInt must be(127)
  }

  it must "create the min number for a single byte" in {
    val int32 = Int32(ByteVector(0x80.toByte))
    int32.toInt must be(-128)
  }

  it must "create the max number for an Int32" in {
    val int32 =
      Int32(ByteVector(0x7f.toByte, 0xff.toByte, 0xff.toByte, 0xff.toByte))
    int32.toInt must be(2147483647)
  }

  it must "create the minimum number for an Int32" in {
    val int32 = Int32(ByteVector(0x80.toByte, 0.toByte, 0.toByte, 0.toByte))
    int32.toInt must be(-2147483648)
  }

  it must "throw an exception if we try and create an Int32 with more than 4 bytes" in {
    intercept[IllegalArgumentException] {
      Int32(ByteVector(0.toByte, 0.toByte, 0.toByte, 0.toByte, 0.toByte))
    }
  }

  it must "have the correct representation for 0" in {
    Int32.zero.toInt must be(0)
  }

  it must "have the correct representation for 1" in {
    Int32.one.toInt must be(1)
  }

  it must "have the correct minimum number representation" in {
    Int32.min.toInt must be(-2147483648)
  }

  it must "have the correct maximum number representation" in {
    Int32.max.toInt must be(2147483647)
  }
} 
Example 97
Source File: UInt8Test.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.number

import org.bitcoins.testkit.util.BitcoinSUnitTest
import scodec.bits.ByteVector

class UInt8Test extends BitcoinSUnitTest {

  "UInt8" must "convert a byte to a UInt8 correctly" in {
    UInt8.toUInt8(0.toByte) must be(UInt8.zero)
    UInt8.toUInt8(1.toByte) must be(UInt8.one)
    UInt8.toUInt8(255.toByte) must be(UInt8(255.toShort))
  }

  it must "throw an exception if we try and create an UInt8 with more than 1 bytes" in {
    intercept[IllegalArgumentException] {
      UInt8(ByteVector(0.toByte, 0.toByte))
    }
  }

} 
Example 98
Source File: FilterTypeTest.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.gcs

import org.bitcoins.testkit.util.BitcoinSUnitTest
import scodec.bits.ByteVector

class FilterTypeTest extends BitcoinSUnitTest {
  behavior of "FilterType"

  it must "parse bytes" in {
    assert(FilterType.fromBytes(ByteVector(0)) == FilterType.Basic)
    assertThrows[IllegalArgumentException](FilterType.fromBytes(ByteVector(1)))
  }

  it must "know its code" in {
    assert(FilterType.getCode(FilterType.Basic) == 0)
    assert(FilterType.byCode(0) == FilterType.Basic)
    assertThrows[IllegalArgumentException](FilterType.byCode(1))
    assertThrows[IllegalArgumentException](
      FilterType.getCode(FilterType.fromHex("ffff")))
  }
} 
Example 99
Source File: NetworkHeaderTest.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.p2p

import org.bitcoins.core.config.TestNet3
import org.bitcoins.core.number.UInt32
import org.bitcoins.testkit.node.NodeTestUtil
import org.bitcoins.testkit.util.BitcoinSUnitTest
import org.bitcoins.core.config.MainNet
import org.bitcoins.core.util.BytesUtil
import org.bitcoins.crypto.CryptoUtil

import scala.util.Random
import scodec.bits.ByteVector

class NetworkHeaderTest extends BitcoinSUnitTest {

  "MessageHeader" must "must create a message header for a message" in {
    val messageHeader = NetworkHeader(TestNet3, NodeTestUtil.versionMessage)
    messageHeader.network must be(TestNet3)
    messageHeader.commandName must be(NodeTestUtil.versionMessage.commandName)
    messageHeader.payloadSize must be(
      UInt32(NodeTestUtil.versionMessage.bytes.size))
    messageHeader.checksum must be(
      CryptoUtil.doubleSHA256(NodeTestUtil.versionMessage.bytes).bytes.take(4))
  }

  it must "build the correct message header for a verack message" in {
    val messageHeader = NetworkHeader(TestNet3, VerAckMessage)
    messageHeader.network must be(TestNet3)
    messageHeader.commandName must be(VerAckMessage.commandName)
    messageHeader.payloadSize must be(UInt32.zero)
    BytesUtil.encodeHex(messageHeader.checksum) must be("5df6e0e2")
  }

  it must "throw on messages of bad length" in {
    intercept[IllegalArgumentException] {
      val commandName = Random.shuffle(NetworkPayload.commandNames).head
      NetworkHeader(MainNet,
                    commandName,
                    payloadSize = UInt32.one,
                    checksum = ByteVector.empty)
    }
  }

} 
Example 100
Source File: RawScriptPubKeyParserTest.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.script

import org.bitcoins.core.protocol.script.{EmptyScriptPubKey, ScriptPubKey}
import org.bitcoins.core.script.bitwise.OP_EQUALVERIFY
import org.bitcoins.core.script.constant._
import org.bitcoins.core.script.crypto.{OP_CHECKSIG, OP_HASH160}
import org.bitcoins.core.script.stack.OP_DUP
import org.bitcoins.core.util.BytesUtil
import org.bitcoins.testkit.util.{BitcoinSUnitTest, TestUtil}
import scodec.bits.ByteVector


class RawScriptPubKeyParserTest extends BitcoinSUnitTest {
  val encode = BytesUtil.encodeHex(_: ByteVector)
  "RawScriptPubKeyParser" must "read then write the scriptPubKey and get the original scriptPubKey" in {
    val scriptPubKey: ScriptPubKey =
      RawScriptPubKeyParser.read(TestUtil.rawScriptPubKey)
    encode(RawScriptPubKeyParser.write(scriptPubKey)) must be(
      TestUtil.rawScriptPubKey)
  }

  it must "read an EmptyScriptPubKey" in {
    assert(RawScriptPubKeyParser.read(ByteVector.empty) == EmptyScriptPubKey)
  }

  it must "read a raw scriptPubKey and give us the expected asm" in {
    val scriptPubKey = RawScriptPubKeyParser.read(TestUtil.rawP2PKHScriptPubKey)
    val expectedAsm: Seq[ScriptToken] =
      List(OP_DUP,
           OP_HASH160,
           BytesToPushOntoStack(20),
           ScriptConstant("31a420903c05a0a7de2de40c9f02ebedbacdc172"),
           OP_EQUALVERIFY,
           OP_CHECKSIG)
    scriptPubKey.asm must be(expectedAsm)

  }
  it must "read a raw scriptPubKey from an output" in {
    //from b30d3148927f620f5b1228ba941c211fdabdae75d0ba0b688a58accbf018f3cc
    //output is index 1
    val rawScriptPubKey = "17a914af575bd77c5ce7eba3bd9ce6f89774713ae62c7987"
    val scriptPubKey = RawScriptPubKeyParser.read(rawScriptPubKey)
    encode(RawScriptPubKeyParser.write(scriptPubKey)) must be(rawScriptPubKey)
  }

  it must "read and write the scriptPubKey that pushes using a PUSHDATA1 that is negative when read as signed" in {
    val rawScriptPubKey =
      "0x4c 0xae 0x606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e207460 DROP DUP HASH160 0x14 0xbfd7436b6265aa9de506f8a994f881ff08cc2872 EQUALVERIFY CHECKSIG"
    val asm = ScriptParser.fromString(rawScriptPubKey)
    val scriptPubKey = ScriptPubKey.fromAsm(asm)
    val actualRawScriptPubKey = RawScriptPubKeyParser.write(scriptPubKey)
    //the actual hex representation is from a bitcoin core test case inside of tx_valid.json
    encode(actualRawScriptPubKey) must be(
      "ca4cae606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e2074607576a914bfd7436b6265aa9de506f8a994f881ff08cc287288ac")

  }

} 
Example 101
Source File: RawTransactionOutputParserTest.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.transaction

import org.bitcoins.core.currency.Satoshis
import org.bitcoins.core.number.Int64
import org.bitcoins.core.protocol.transaction.{
  EmptyTransactionOutput,
  TransactionOutput
}
import org.bitcoins.core.script.bitwise.OP_EQUAL
import org.bitcoins.core.script.constant.{BytesToPushOntoStack, ScriptConstant}
import org.bitcoins.core.script.crypto.OP_HASH160
import org.bitcoins.core.util.BytesUtil
import org.bitcoins.testkit.util.BitcoinSUnitTest
import scodec.bits.ByteVector


class RawTransactionOutputParserTest extends BitcoinSUnitTest {

  //txid cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6
  val rawTxOutput =
    "204e00000000000017a914eda8ae08b5c9f973f49543e90a7c292367b3337c87"
  val encode = BytesUtil.encodeHex(_: ByteVector)
  "RawTransactionOutputTest" must "read a serialized tx output" in {

    val txOutput: TransactionOutput =
      RawTransactionOutputParser.read(rawTxOutput)
    txOutput.value must be(Satoshis(20000))
    txOutput.scriptPubKey.asm must be(
      Seq(OP_HASH160,
          BytesToPushOntoStack(20),
          ScriptConstant("eda8ae08b5c9f973f49543e90a7c292367b3337c"),
          OP_EQUAL))
  }

  it must "seralialize a transaction output" in {
    val txOutput = RawTransactionOutputParser.read(rawTxOutput)
    encode(RawTransactionOutputParser.write(txOutput)) must be(rawTxOutput)
  }

  it must "serialize a single transaction output not in a sequence" in {
    val txOutput = RawTransactionOutputParser.read(rawTxOutput)
    encode(RawTransactionOutputParser.write(txOutput)) must be(rawTxOutput)
  }

  it must "serialize an older raw transaction output" in {
    //from this question
    //https://bitcoin.stackexchange.com/questions/2859/how-are-transaction-hashes-calculated
    val txOutput =
      "00f2052a01000000434104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5fac"
    val output = RawTransactionOutputParser.read(txOutput)
    output.value must be(Satoshis(5000000000L))
  }

  it must "serialize the empty transaction output correctly" in {
    encode(RawTransactionOutputParser.write(EmptyTransactionOutput)) must be(
      "ffffffffffffffff00")

  }
} 
Example 102
Source File: RawTransactionOutPointParserTest.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.transaction

import org.bitcoins.core.number.UInt32
import org.bitcoins.core.util.BytesUtil
import org.bitcoins.testkit.util.BitcoinSUnitTest
import scodec.bits.ByteVector


class RawTransactionOutPointParserTest extends BitcoinSUnitTest {

  //txid cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6
  val rawOutPoint =
    "85d6b0da2edf96b282030d3f4f79d14cc8c882cfef1b3064170c850660317de100000000"

  val rawOutPointLargeVout =
    "df80e3e6eba7dcd4650281d3c13f140dafbb823a7227a78eb6ee9f6cedd0400134000000"
  val encode = BytesUtil.encodeHex(_: ByteVector)
  "RawTransactionOutPointParser" must "read a raw outpoint into a native scala TransactionOutPoint" in {
    val outPoint = RawTransactionOutPointParser.read(rawOutPoint)
    outPoint.txId.hex must be(
      BytesUtil.flipEndianness(
        "e17d316006850c1764301befcf82c8c84cd1794f3f0d0382b296df2edab0d685"))
    outPoint.vout must be(UInt32.zero)
  }

  it must "parse a large vout for an outpoint" in {
    val outPoint = RawTransactionOutPointParser.read(rawOutPointLargeVout)
    outPoint.vout must be(UInt32(52))
    outPoint.txId.hex must be(
      BytesUtil.flipEndianness(
        "0140d0ed6c9feeb68ea727723a82bbaf0d143fc1d3810265d4dca7ebe6e380df"))
  }
  it must "write a TransactionOutPoint to a serialized format" in {
    val outPoint = RawTransactionOutPointParser.read(rawOutPoint)
    val actualSerialization = RawTransactionOutPointParser.write(outPoint)
    encode(actualSerialization) must be(rawOutPoint)
  }

  it must "write a outpoint that has a large vout" in {
    val outPoint = RawTransactionOutPointParser.read(rawOutPointLargeVout)
    val serializedOutpoint = RawTransactionOutPointParser.write(outPoint)
    encode(serializedOutpoint) must be(rawOutPointLargeVout)
  }

  it must "write this outpoint with vout index 1" in {
    //from txid bdc221db675c06dbee2ae75d33e31cad4e2555efea10c337ff32c8cdf97f8e74
    val rawOutPoint =
      "fc37adbd036fb51b3f4f6f70474270939d6ff8c4ea697639f2b57dd6359e307001000000"

    val outPoint = RawTransactionOutPointParser.read(rawOutPoint)
    outPoint.txId.hex must be(
      BytesUtil.flipEndianness(
        "70309e35d67db5f2397669eac4f86f9d93704247706f4f3f1bb56f03bdad37fc"))
    val serializedOutPoint = RawTransactionOutPointParser.write(outPoint)
    encode(serializedOutPoint) must be(rawOutPoint)
  }

  it must "determine the correct size of a transaction outpoint" in {
    //cad1082e674a7bd3bc9ab1bc7804ba8a57523607c876b8eb2cbe645f2b1803d6
    val rawOutPoint =
      "85d6b0da2edf96b282030d3f4f79d14cc8c882cfef1b3064170c850660317de100000000"
    val outPoint = RawTransactionOutPointParser.read(rawOutPoint)
    outPoint.byteSize must be(36)
  }

  it must "parse a outpoint with extremely large vout" in {
    //vout should be 20183580
    val rawOutPoint =
      "4435c4ea162d51135c9b2bbb867a86f25001c246224b60e8ab2307edce7fc28a0ca13f13"
    val outPoint = RawTransactionOutPointParser.read(rawOutPoint)
    outPoint.vout must be(UInt32(322937100))
    outPoint.hex must be(rawOutPoint)
  }

} 
Example 103
Source File: RawBitcoinSerializerHelperTest.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers

import org.bitcoins.core.number.UInt64
import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.protocol.transaction.{
  EmptyTransactionOutput,
  TransactionInput,
  TransactionOutput
}
import org.bitcoins.core.serializers.transaction.{
  RawTransactionInputParser,
  RawTransactionOutputParser
}
import org.bitcoins.testkit.util.BitcoinSUnitTest
import scodec.bits.ByteVector

class RawSerializerHelperTest extends BitcoinSUnitTest {

  "RawBitcoinSerializerHelper" must "serialize an empty vector" in {
    val bytes = ByteVector(0.toByte)
    val construct: ByteVector => TransactionInput =
      RawTransactionInputParser.read(_)
    val (inputs, _) =
      RawSerializerHelper.parseCmpctSizeUIntSeq(bytes, construct)

    val serialize = RawTransactionInputParser.write(_)
    val write = RawSerializerHelper.writeCmpctSizeUInt(inputs, serialize)
    write must be(bytes)
  }

  it must "serialize one element in a vector correctly" in {
    val bytes =
      CompactSizeUInt(UInt64.one).bytes ++ EmptyTransactionOutput.bytes
    val constructor: ByteVector => TransactionOutput =
      RawTransactionOutputParser.read(_)

    val (outputs, _) =
      RawSerializerHelper.parseCmpctSizeUIntSeq(bytes, constructor)

    val serialize = RawTransactionOutputParser.write(_)
    val write = RawSerializerHelper.writeCmpctSizeUInt(outputs, serialize)
    write must be(bytes)
  }
} 
Example 104
Source File: RawSerializerHelperSpec.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers

import org.bitcoins.testkit.core.gen.TransactionGenerators
import org.bitcoins.core.protocol.transaction.TransactionOutput
import org.scalacheck.{Prop, Properties}
import scodec.bits.ByteVector

class RawSerializerHelperSpec extends Properties("RawSerializerHelperSpec") {

  property("serialization symmetry of txs") = {
    Prop.forAll(TransactionGenerators.smallOutputs) {
      txs: Seq[TransactionOutput] =>
        val serialized =
          RawSerializerHelper.writeCmpctSizeUInt(txs,
                                                 { tx: TransactionOutput =>
                                                   tx.bytes
                                                 })
        val (deserialized, remaining) = RawSerializerHelper
          .parseCmpctSizeUIntSeq(serialized, TransactionOutput(_: ByteVector))
        deserialized == txs && remaining == ByteVector.empty
    }
  }

} 
Example 105
Source File: ZMQSubscriberTest.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.zmq

import java.net.InetSocketAddress

import org.bitcoins.core.util.BytesUtil
import org.scalatest.flatspec.AsyncFlatSpec
import org.slf4j.LoggerFactory
import org.zeromq.{ZFrame, ZMQ, ZMsg}
import scodec.bits.ByteVector

import scala.concurrent.Promise

class ZMQSubscriberTest extends AsyncFlatSpec {
  private val logger = LoggerFactory.getLogger(this.getClass().toString)

  behavior of "ZMQSubscriber"

  it must "connect to a regtest instance of a daemon and stream txs/blocks from it" in {
    //note for this unit test to pass, you need to setup a bitcoind instance yourself
    //and set the bitcoin.conf file to allow for
    //zmq connections
    //see: https://github.com/bitcoin/bitcoin/blob/master/doc/zmq.md
    val socket = new InetSocketAddress("tcp://127.0.0.1", 29000)

    val zmqSub =
      new ZMQSubscriber(socket, None, None, rawTxListener, rawBlockListener)
    //stupid, doesn't test anything, for now. You need to look at log output to verify this is working
    // TODO: In the future this could use the testkit to verify the subscriber by calling generate(1)
    zmqSub.start()
    Thread.sleep(10000) // 10 seconds
    zmqSub.stop

    succeed
  }

  it must "be able to subscribe to a publisher and read a value" in {
    val port = Math.abs(scala.util.Random.nextInt % 14000) + 1000
    val socket = new InetSocketAddress("tcp://127.0.0.1", port)

    val context = ZMQ.context(1)
    val publisher = context.socket(ZMQ.PUB)

    val uri = socket.getHostString + ":" + socket.getPort
    publisher.bind(uri)

    val valuePromise = Promise[String]()
    val fakeBlockListener: Option[ByteVector => Unit] = Some { bytes =>
      val str = new String(bytes.toArray)
      valuePromise.success(str)
      ()
    }

    val sub = new ZMQSubscriber(socket, None, None, None, fakeBlockListener)
    sub.start()
    Thread.sleep(1000)

    val testValue = "sweet, sweet satoshis"

    val msg = new ZMsg()
    msg.add(new ZFrame(RawBlock.topic))
    msg.add(new ZFrame(testValue))

    val sent = msg.send(publisher)
    assert(sent)

    valuePromise.future.map { str =>
      sub.stop
      publisher.close()
      context.term()

      assert(str == testValue)
    }
  }

  val rawBlockListener: Option[ByteVector => Unit] = Some {
    { bytes: ByteVector =>
      val hex = BytesUtil.encodeHex(bytes)
      logger.debug(s"received raw block ${hex}")
    }
  }

  val hashBlockListener: Option[ByteVector => Unit] = Some {
    { bytes: ByteVector =>
      val hex = BytesUtil.encodeHex(bytes)
      logger.debug(s"received raw block hash ${hex}")

    }
  }

  val rawTxListener: Option[ByteVector => Unit] = Some {
    { bytes: ByteVector =>
      val hex = BytesUtil.encodeHex(bytes)
      logger.debug(s"received raw tx ${hex}")
    }
  }
} 
Example 106
Source File: InitOracleDialog.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.gui.dlc.dialog

import org.bitcoins.commons.jsonmodels.dlc.DLCMessage.ContractInfo
import org.bitcoins.core.currency.Satoshis
import org.bitcoins.crypto.CryptoUtil
import scalafx.Includes._
import scalafx.application.Platform
import scalafx.geometry.Insets
import scalafx.scene.control.{ButtonType, Dialog, Label, TextField}
import scalafx.scene.layout.GridPane
import scalafx.stage.Window
import scodec.bits.ByteVector

object InitOracleDialog {

  def showAndWait(
      parentWindow: Window,
      numOutcomes: Int): Option[(Vector[String], ContractInfo)] = {
    val dialog = new Dialog[Option[(Vector[String], ContractInfo)]]() {
      initOwner(parentWindow)
      title = "Initialize Demo Oracle"
      headerText = "Enter contract outcomes and their outcome values"
    }

    val fields =
      (0 until numOutcomes).map(_ =>
        (new TextField(),
         new TextField() {
           promptText = "Satoshis"
         }))

    dialog.dialogPane().buttonTypes = Seq(ButtonType.OK, ButtonType.Cancel)

    dialog.dialogPane().content = new GridPane {
      hgap = 10
      vgap = 10
      padding = Insets(20, 100, 10, 10)

      add(new Label("Outcomes"), 0, 0)
      add(new Label("Values"), 1, 0)

      var nextRow: Int = 1

      fields.foreach {
        case (str, value) =>
          add(str, 0, nextRow)
          add(value, 1, nextRow)
          nextRow += 1
      }
    }

    // Enable/Disable OK button depending on whether all data was entered.
    val okButton = dialog.dialogPane().lookupButton(ButtonType.OK)
    // Simple validation that sufficient data was entered
    okButton.disable <== fields
      .map { case (str, value) => str.text.isEmpty || value.text.isEmpty }
      .reduce(_ || _)

    // Request focus on the first field by default.
    Platform.runLater(fields.head._1.requestFocus())

    // When the OK button is clicked, convert the result to a CreateDLCOffer.
    dialog.resultConverter = dialogButton =>
      if (dialogButton == ButtonType.OK) {
        val inputs = fields.map {
          case (str, value) => (str.text(), value.text())
        }
        val contractMap = inputs.map {
          case (str, value) =>
            val hash = CryptoUtil.sha256(ByteVector(str.getBytes)).flip
            hash -> Satoshis(BigInt(value))
        }.toMap

        val outcomes = inputs.map(_._1).toVector

        Some((outcomes, ContractInfo(contractMap)))
      } else None

    val result = dialog.showAndWait()

    result match {
      case Some(Some((outcomes: Vector[_], contractInfo: ContractInfo))) =>
        Some((outcomes.map(_.toString), contractInfo))
      case Some(_) | None => None
    }
  }
} 
Example 107
Source File: DLCMessageTest.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.commons.dlc

import org.bitcoins.commons.jsonmodels.dlc.DLCMessage.{
  ContractInfo,
  DLCAccept,
  DLCOffer,
  OracleInfo
}
import org.bitcoins.commons.jsonmodels.dlc.{
  CETSignatures,
  DLCPublicKeys,
  DLCTimeouts
}
import org.bitcoins.core.currency.Satoshis
import org.bitcoins.core.number.UInt32
import org.bitcoins.core.protocol.BitcoinAddress
import org.bitcoins.core.protocol.BlockStamp.{BlockHeight, BlockTime}
import org.bitcoins.core.psbt.InputPSBTRecord.PartialSignature
import org.bitcoins.core.wallet.fee.SatoshisPerVirtualByte
import org.bitcoins.crypto.{
  DummyECDigitalSignature,
  ECPublicKey,
  Sha256DigestBE
}
import org.bitcoins.testkit.util.BitcoinSAsyncTest
import scodec.bits.ByteVector

class DLCMessageTest extends BitcoinSAsyncTest {
  behavior of "DLCMessage"

  it must "not allow a DLCTimeout where the contract times out before it matures" in {
    assertThrows[IllegalArgumentException](
      DLCTimeouts(UInt32(5), BlockHeight(4), BlockHeight(2)))
    assertThrows[IllegalArgumentException](
      DLCTimeouts(UInt32(5), BlockTime(UInt32(4)), BlockTime(UInt32(2))))
  }

  val dummyPubKey: ECPublicKey = ECPublicKey.freshPublicKey
  val dummyPubKey2: ECPublicKey = ECPublicKey.freshPublicKey

  val dummyAddress: BitcoinAddress = BitcoinAddress(
    "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa")

  val dummyHash: Sha256DigestBE = Sha256DigestBE(
    "00000000000000000008bba30d4d0fb53dcbffb601557de9f16d257d4f1985b7")

  val dummySig: PartialSignature =
    PartialSignature(dummyPubKey, DummyECDigitalSignature)

  it must "not allow a negative collateral for a DLCOffer" in {
    assertThrows[IllegalArgumentException](
      DLCOffer(
        ContractInfo.empty,
        OracleInfo.dummy,
        DLCPublicKeys(dummyPubKey, dummyPubKey2, dummyAddress),
        Satoshis(-1),
        Vector.empty,
        dummyAddress,
        SatoshisPerVirtualByte.one,
        DLCTimeouts(UInt32(5), BlockHeight(1), BlockHeight(2))
      ))
  }

  it must "not allow a negative collateral for a DLCAccept" in {
    assertThrows[IllegalArgumentException](
      DLCAccept(
        Satoshis(-1),
        DLCPublicKeys(dummyPubKey, dummyPubKey2, dummyAddress),
        Vector.empty,
        dummyAddress,
        CETSignatures(Map(dummyHash -> dummySig), dummySig),
        Sha256DigestBE(ByteVector.low(32))
      )
    )
  }

  it must "not allow duplicate keys in a DLCPublicKeys" in {
    assertThrows[IllegalArgumentException](
      DLCPublicKeys(dummyPubKey, dummyPubKey, dummyAddress)
    )
  }
} 
Example 108
Source File: SchnorrNonce.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.crypto

import scodec.bits.ByteVector

import scala.annotation.tailrec
import scala.util.Try

case class SchnorrNonce(bytes: ByteVector) extends NetworkElement {
  require(bytes.length == 32, s"Schnorr nonce must be 32 bytes, get $bytes")

  private val evenKey: ECPublicKey = ECPublicKey(s"02$hex")
  private val oddKey: ECPublicKey = ECPublicKey(s"03$hex")

  private val yCoordEven: Boolean = {
    evenKey.toPoint.getRawYCoord.sqrt() != null
  }

  
  def fromBipSchnorr(
      privKey: ECPrivateKey,
      message: ByteVector,
      auxRand: ByteVector): SchnorrNonce = {
    val k = kFromBipSchnorr(privKey, message, auxRand)
    k.publicKey.schnorrNonce
  }

  def apply(xCoor: FieldElement): SchnorrNonce = {
    SchnorrNonce(xCoor.bytes)
  }
} 
Example 109
Source File: PBKDF2.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.crypto

import javax.crypto.spec.PBEKeySpec
import javax.crypto.{SecretKey, SecretKeyFactory}
import scodec.bits.ByteVector


  def withSha512(
      bytes: ByteVector,
      salt: ByteVector,
      iterationCount: Int,
      derivedKeyLength: Int): SecretKey = {

    val keySpec = new PBEKeySpec(
      bytes.toArray.map(_.toChar),
      salt.toArray,
      iterationCount,
      derivedKeyLength
    )

    secretKeyFactory.generateSecret(keySpec)
  }
} 
Example 110
Source File: SchnorrDigitalSignature.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.crypto

import scodec.bits.ByteVector

case class SchnorrDigitalSignature(rx: SchnorrNonce, sig: FieldElement)
    extends NetworkElement {
  override def bytes: ByteVector = rx.bytes ++ sig.bytes
}

object SchnorrDigitalSignature extends Factory[SchnorrDigitalSignature] {

  override def fromBytes(bytes: ByteVector): SchnorrDigitalSignature = {
    require(bytes.length == 64,
            s"SchnorrDigitalSignature must be exactly 64 bytes, got $bytes")
    SchnorrDigitalSignature(SchnorrNonce(bytes.take(32)),
                            FieldElement(bytes.drop(32)))
  }
} 
Example 111
Source File: SchnorrPublicKey.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.crypto

import org.bitcoin.NativeSecp256k1
import scodec.bits.ByteVector

import scala.annotation.tailrec
import scala.util.Try

case class SchnorrPublicKey(bytes: ByteVector) extends NetworkElement {
  require(bytes.length == 32,
          s"Schnorr public keys must be 32 bytes, got $bytes")
  require(Try(publicKey).isSuccess,
          s"Schnorr public key must be a valid x coordinate, got $bytes")

  // TODO: match on CryptoContext once secp version is added
  def verify(data: ByteVector, signature: SchnorrDigitalSignature): Boolean = {
    verifyWithBouncyCastle(data, signature)
  }

  

  def computeSigPointWithBouncyCastle(
      data: ByteVector,
      nonce: SchnorrNonce,
      compressed: Boolean = true): ECPublicKey = {
    BouncyCastleUtil.schnorrComputeSigPoint(data, nonce, this, compressed)
  }

  def publicKey: ECPublicKey = {
    val pubKeyBytes = ByteVector.fromByte(2) ++ bytes

    val validPubKey = CryptoContext.default match {
      case CryptoContext.LibSecp256k1 =>
        NativeSecp256k1.isValidPubKey(pubKeyBytes.toArray)
      case CryptoContext.BouncyCastle =>
        BouncyCastleUtil.validatePublicKey(pubKeyBytes)
    }

    require(
      validPubKey,
      s"Cannot construct schnorr public key from invalid x coordinate: $bytes")

    ECPublicKey(pubKeyBytes)
  }

  def xCoord: FieldElement = FieldElement(bytes)
}

object SchnorrPublicKey extends Factory[SchnorrPublicKey] {

  @tailrec
  def fromBytes(bytes: ByteVector): SchnorrPublicKey = {
    require(bytes.length <= 33,
            s"XOnlyPublicKey must be less than 33 bytes, got $bytes")

    if (bytes.length == 32)
      new SchnorrPublicKey(bytes)
    else if (bytes.length < 32) {
      // means we need to pad the private key with 0 bytes so we have 32 bytes
      SchnorrPublicKey.fromBytes(bytes.padLeft(32))
    } else if (bytes.length == 33) {
      // this is for the case when java serialies a BigInteger to 33 bytes to hold the signed num representation
      SchnorrPublicKey.fromBytes(bytes.tail)
    } else {
      throw new IllegalArgumentException(
        "XOnlyPublicKey cannot be greater than 33 bytes in size, got: " +
          CryptoBytesUtil.encodeHex(bytes) + " which is of size: " + bytes.size)
    }
  }

  def apply(xCoor: FieldElement): SchnorrPublicKey = {
    SchnorrPublicKey(xCoor.bytes)
  }
} 
Example 112
Source File: CompactFilterDb.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.chain.models

import org.bitcoins.core.gcs.{BlockFilter, FilterType, GolombFilter}
import org.bitcoins.crypto.{CryptoUtil, DoubleSha256DigestBE}
import scodec.bits.ByteVector

case class CompactFilterDb(
    hashBE: DoubleSha256DigestBE,
    filterType: FilterType,
    bytes: ByteVector,
    height: Int,
    blockHashBE: DoubleSha256DigestBE) {
  require(
    CryptoUtil.doubleSHA256(bytes).flip == hashBE,
    s"Bytes must hash to hashBE! It looks like you didn't construct CompactFilterDb correctly")

  def golombFilter: GolombFilter =
    filterType match {
      case FilterType.Basic => BlockFilter.fromBytes(bytes, blockHashBE.flip)
    }

  override def toString: String = {
    s"CompactFilterDb(hashBE=$hashBE,filterType=$filterType,height=$height,blockHashBE=$blockHashBE,bytes=${bytes})"
  }
}

object CompactFilterDbHelper {

  def fromGolombFilter(
      golombFilter: GolombFilter,
      blockHash: DoubleSha256DigestBE,
      height: Int): CompactFilterDb =
    fromFilterBytes(golombFilter.bytes, blockHash, height)

  def fromFilterBytes(
      filterBytes: ByteVector,
      blockHash: DoubleSha256DigestBE,
      height: Int): CompactFilterDb =
    CompactFilterDb(CryptoUtil.doubleSHA256(filterBytes).flip,
                    FilterType.Basic,
                    filterBytes,
                    height,
                    blockHash)
} 
Example 113
Source File: CompactFilterDAO.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.chain.models

import org.bitcoins.chain.config.ChainAppConfig
import org.bitcoins.core.gcs.FilterType
import org.bitcoins.crypto.DoubleSha256DigestBE
import org.bitcoins.db.{CRUD, SlickUtil}
import scodec.bits.ByteVector

import scala.concurrent.{ExecutionContext, Future}

case class CompactFilterDAO()(implicit
    ec: ExecutionContext,
    override val appConfig: ChainAppConfig)
    extends CRUD[CompactFilterDb, DoubleSha256DigestBE]
    with SlickUtil[CompactFilterDb, DoubleSha256DigestBE] {
  val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile)
  import mappers.{
    byteVectorMapper,
    doubleSha256DigestBEMapper,
    filterTypeMapper
  }
  import profile.api._

  implicit private val bigIntMapper: BaseColumnType[BigInt] =
    if (appConfig.driverName == "postgresql") {
      mappers.bigIntPostgresMapper
    } else {
      mappers.bigIntMapper
    }

  class CompactFilterTable(tag: Tag)
      extends Table[CompactFilterDb](tag, "cfilters") {

    def hash = column[DoubleSha256DigestBE]("hash")

    def filterType = column[FilterType]("filter_type")

    def bytes = column[ByteVector]("bytes")

    def height = column[Int]("height")

    def blockHash = column[DoubleSha256DigestBE]("block_hash", O.PrimaryKey)

    def heightIndex = index("cfilters_height_index", height)

    def hashIndex = index("cfilters_hash_index", hash)

    override def * = {
      (hash,
       filterType,
       bytes,
       height,
       blockHash) <> (CompactFilterDb.tupled, CompactFilterDb.unapply)
    }
  }

  override val table: profile.api.TableQuery[CompactFilterTable] = {
    TableQuery[CompactFilterTable]
  }

  private lazy val blockHeaderTable: profile.api.TableQuery[
    BlockHeaderDAO#BlockHeaderTable] = {
    BlockHeaderDAO().table
  }

  override def createAll(
      filters: Vector[CompactFilterDb]): Future[Vector[CompactFilterDb]] = {
    createAllNoAutoInc(ts = filters, database = safeDatabase)
  }

  
  def getBestFilter: Future[Option[CompactFilterDb]] = {
    val join = (table
      .join(blockHeaderTable))
      .on(_.blockHash === _.hash)
    val query = join.groupBy(_._1).map {
      case (filter, headers) =>
        filter -> headers.map(_._2.chainWork).max
    }
    val filtersWithWorkF: Future[Vector[(CompactFilterDb, Option[BigInt])]] = {
      safeDatabase.runVec(query.result)
    }

    filtersWithWorkF.map { filtersWithWork =>
      if (filtersWithWork.isEmpty) {
        None
      } else {
        val highest = filtersWithWork.maxBy(_._2.getOrElse(BigInt(0)))._1
        Some(highest)
      }
    }
  }
} 
Example 114
Source File: DLCTimeouts.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.commons.jsonmodels.dlc

import org.bitcoins.core.number.UInt32
import org.bitcoins.core.protocol.BlockStamp.{BlockHeight, BlockTime}
import org.bitcoins.core.protocol.BlockTimeStamp
import org.bitcoins.crypto.{Factory, NetworkElement}
import scodec.bits.ByteVector


  final val DEFAULT_PENALTY_TIMEOUT: UInt32 = UInt32(5)

  override def fromBytes(bytes: ByteVector): DLCTimeouts = {
    require(bytes.size == 12, s"A DLCTimeouts is exactly 12 bytes, got $bytes")

    val penalty = UInt32(bytes.take(4))
    val contractMaturity =
      BlockTimeStamp.fromUInt32(UInt32(bytes.slice(4, 8)))
    val contractTimeout =
      BlockTimeStamp.fromUInt32(UInt32(bytes.takeRight(4)))
    DLCTimeouts(penalty, contractMaturity, contractTimeout)
  }
} 
Example 115
Source File: EncryptedMnemonic.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.keymanager

import java.time.Instant

import org.bitcoins.core.compat.CompatEither
import org.bitcoins.core.crypto._
import org.bitcoins.crypto.{AesCrypt, AesEncryptedData, AesPassword, AesSalt}
import scodec.bits.ByteVector

import scala.util.{Failure, Success, Try}

case class DecryptedMnemonic(
    mnemonicCode: MnemonicCode,
    creationTime: Instant) {

  def encrypt(password: AesPassword): EncryptedMnemonic =
    EncryptedMnemonicHelper.encrypt(this, password)
}

case class EncryptedMnemonic(
    value: AesEncryptedData,
    salt: AesSalt,
    creationTime: Instant) {

  def toMnemonic(password: AesPassword): Try[MnemonicCode] = {
    val key = password.toKey(salt)
    val either = AesCrypt.decrypt(value, key)
    CompatEither(either).toTry.flatMap { decrypted =>
      decrypted.decodeUtf8 match {
        case Left(_) =>
          // when failing to decode this to a UTF-8 string
          // we assume it's because of a bad password
          Failure(ReadMnemonicError.DecryptionError)

        case Right(wordsStr) =>
          val wordsVec = wordsStr.split(" ").toVector
          Success(MnemonicCode.fromWords(wordsVec))
      }
    }
  }
}

object EncryptedMnemonicHelper {

  def encrypt(
      mnemonic: DecryptedMnemonic,
      password: AesPassword): EncryptedMnemonic = {
    val wordsStr = mnemonic.mnemonicCode.words.mkString(" ")
    val Right(clearText) = ByteVector.encodeUtf8(wordsStr)

    val (key, salt) = password.toKey

    val encryted = AesCrypt
      .encrypt(clearText, key)

    EncryptedMnemonic(encryted, salt, mnemonic.creationTime)
  }
} 
Example 116
Source File: BroadcastAbleTransactionDAO.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.node.models

import org.bitcoins.db.CRUDAutoInc
import org.bitcoins.node.config.NodeAppConfig

import scala.concurrent.ExecutionContext
import slick.lifted.ProvenShape

import scala.concurrent.Future
import org.bitcoins.core.protocol.transaction.Transaction
import org.bitcoins.crypto.{DoubleSha256Digest, DoubleSha256DigestBE}
import scodec.bits.ByteVector

final case class BroadcastAbleTransactionDAO()(implicit
    override val appConfig: NodeAppConfig,
    val ec: ExecutionContext)
    extends CRUDAutoInc[BroadcastAbleTransaction] {

  import profile.api._
  val mappers = new org.bitcoins.db.DbCommonsColumnMappers(profile)
  import mappers._

  override val table: profile.api.TableQuery[BroadcastAbleTransactionTable] =
    profile.api.TableQuery[BroadcastAbleTransactionTable]

  
  class BroadcastAbleTransactionTable(tag: Tag)
      extends TableAutoInc[BroadcastAbleTransaction](tag,
                                                     "broadcast_elements") {
    private type Tuple = (DoubleSha256DigestBE, ByteVector, Option[Long])

    private val fromTuple: (Tuple => BroadcastAbleTransaction) = {
      case (txid, bytes, id) =>
        val tx = Transaction.fromBytes(bytes)
        require(tx.txId == txid.flip)
        BroadcastAbleTransaction(tx, id)
    }

    private val toTuple: BroadcastAbleTransaction => Option[Tuple] = tx =>
      Some(tx.transaction.txId.flip, tx.transaction.bytes, tx.id)

    def txid: Rep[DoubleSha256DigestBE] = column("txid", O.Unique)
    def bytes: Rep[ByteVector] = column("tx_bytes")

    def * : ProvenShape[BroadcastAbleTransaction] =
      (txid, bytes, id.?) <>
        (fromTuple, toTuple)
  }

} 
Example 117
Source File: ScriptOperationFactory.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.script

import org.bitcoins.core.script.arithmetic.ArithmeticOperation
import org.bitcoins.core.script.bitwise.BitwiseOperation
import org.bitcoins.core.script.constant._
import org.bitcoins.core.script.control.ControlOperations
import org.bitcoins.core.script.crypto.CryptoOperation
import org.bitcoins.core.script.locktime.LocktimeOperation
import org.bitcoins.core.script.reserved.ReservedOperation
import org.bitcoins.core.script.splice.SpliceOperation
import org.bitcoins.core.script.stack.StackOperation
import org.bitcoins.core.util.{BitcoinSLogger, BytesUtil}
import scodec.bits.ByteVector


  final override val operations: Vector[ScriptOperation] = {
    StackPushOperationFactory.pushDataOperations ++
      StackOperation.operations ++
      LocktimeOperation.operations ++
      CryptoOperation.operations ++
      ControlOperations.operations ++
      BitwiseOperation.operations ++
      ArithmeticOperation.operations ++
      BytesToPushOntoStack.operations ++
      SpliceOperation.operations ++
      ReservedOperation.operations ++
      ScriptNumberOperation.operations
  }

} 
Example 118
Source File: PaymentSecret.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.protocol.ln

import org.bitcoins.crypto.{
  CryptoUtil,
  ECPrivateKey,
  Factory,
  NetworkElement,
  Sha256Digest
}
import scodec.bits.ByteVector

final case class PaymentSecret(bytes: ByteVector) extends NetworkElement {
  require(bytes.size == 32,
          s"Payment secret must be 32 bytes in size, got: " + bytes.length)

  lazy val hash: Sha256Digest = CryptoUtil.sha256(bytes)
}

object PaymentSecret extends Factory[PaymentSecret] {

  override def fromBytes(bytes: ByteVector): PaymentSecret = {
    new PaymentSecret(bytes)
  }

  def random: PaymentSecret = fromBytes(ECPrivateKey.freshPrivateKey.bytes)

} 
Example 119
Source File: ShortChannelId.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.protocol.ln

import org.bitcoins.core.number.UInt64
import org.bitcoins.crypto.{Factory, NetworkElement}
import scodec.bits.ByteVector

case class ShortChannelId(u64: UInt64) extends NetworkElement {
  override def bytes: ByteVector = u64.bytes

  
  def toHumanReadableString: String = {
    val blockHeight = (u64 >> 40) & UInt64(0xffffff)
    val txIndex = (u64 >> 16) & UInt64(0xffffff)
    val outputIndex = u64 & UInt64(0xffff)
    s"${blockHeight.toInt}x${txIndex.toInt}x${outputIndex.toInt}"
  }

}

object ShortChannelId extends Factory[ShortChannelId] {

  override def fromBytes(byteVector: ByteVector): ShortChannelId = {
    new ShortChannelId(UInt64.fromBytes(byteVector))
  }

  def fromHumanReadableString(str: String): ShortChannelId =
    str.split("x") match {
      case Array(_blockHeight, _txIndex, _outputIndex) =>
        val blockHeight = BigInt(_blockHeight)
        require(blockHeight >= 0 && blockHeight <= 0xffffff,
                "ShortChannelId: invalid block height")

        val txIndex = _txIndex.toInt
        require(txIndex >= 0 && txIndex <= 0xffffff,
                "ShortChannelId:invalid tx index")

        val outputIndex = _outputIndex.toInt
        require(outputIndex >= 0 && outputIndex <= 0xffff,
                "ShortChannelId: invalid output index")

        val u64 = UInt64(
          ((blockHeight & 0xffffffL) << 40) | ((txIndex & 0xffffffL) << 16) | (outputIndex & 0xffffL))
        ShortChannelId(u64)
      case _: Array[String] => fromHex(str)
    }
} 
Example 120
Source File: LnRoute.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.protocol.ln.routing

import java.math.BigInteger

import org.bitcoins.core.number.UInt32
import org.bitcoins.core.protocol.ln.ShortChannelId
import org.bitcoins.core.protocol.ln.currency.MilliSatoshis
import org.bitcoins.core.protocol.ln.fee.{
  FeeBaseMSat,
  FeeProportionalMillionths
}
import org.bitcoins.core.util.BytesUtil
import org.bitcoins.crypto.{ECPublicKey, NetworkElement}
import scodec.bits.ByteVector


case class LnRoute(
    pubkey: ECPublicKey,
    shortChannelID: ShortChannelId,
    feeBaseMsat: FeeBaseMSat,
    feePropMilli: FeeProportionalMillionths,
    cltvExpiryDelta: Short)
    extends NetworkElement {

  require(pubkey.isCompressed,
          s"Can only use a compressed public key in routing")

  override def bytes: ByteVector = {

    val cltvExpiryDeltaHex = BytesUtil.encodeHex(cltvExpiryDelta)

    pubkey.bytes ++
      shortChannelID.bytes ++
      feeBaseMsat.bytes ++
      feePropMilli.bytes ++
      ByteVector.fromValidHex(cltvExpiryDeltaHex)
  }
}

object LnRoute {

  def fromBytes(bytes: ByteVector): LnRoute = {
    val PUBKEY_LEN = 33
    val SHORT_CHANNEL_ID_LEN = 8
    val FEE_BASE_U32_LEN = 4
    val FEE_PROPORTIONAL_LEN = 4
    val CLTV_EXPIRTY_DELTA_LEN = 2

    val TOTAL_LEN = PUBKEY_LEN +
      SHORT_CHANNEL_ID_LEN +
      FEE_BASE_U32_LEN +
      FEE_PROPORTIONAL_LEN +
      CLTV_EXPIRTY_DELTA_LEN

    require(
      bytes.length >= TOTAL_LEN,
      s"ByteVector must at least of length $TOTAL_LEN, got ${bytes.length}")

    val (pubKeyBytes, rest0) = bytes.splitAt(PUBKEY_LEN)
    val pubKey = ECPublicKey.fromBytes(pubKeyBytes)

    val (shortChannelIdBytes, rest1) = rest0.splitAt(SHORT_CHANNEL_ID_LEN)

    val shortChannelId = ShortChannelId.fromBytes(shortChannelIdBytes)

    val (feeBaseU32Bytes, rest2) = rest1.splitAt(FEE_BASE_U32_LEN)

    val feeBaseU32 = UInt32.fromBytes(feeBaseU32Bytes)
    val feeBase = feeBaseU32.toLong
    val feeBaseMSat = FeeBaseMSat(MilliSatoshis(feeBase))

    val (u32Bytes, rest3) = rest2.splitAt(FEE_PROPORTIONAL_LEN)

    val u32 = UInt32.fromBytes(u32Bytes)
    val feeProportionalMillionths = FeeProportionalMillionths(u32)

    val (cltvExpiryDeltaBytes, _) = rest3.splitAt(CLTV_EXPIRTY_DELTA_LEN)

    val cltvExpiryDelta = new BigInteger(
      cltvExpiryDeltaBytes.toArray).shortValueExact

    LnRoute(pubKey,
            shortChannelId,
            feeBaseMSat,
            feeProportionalMillionths,
            cltvExpiryDelta)
  }
} 
Example 121
Source File: LnInvoiceSignature.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.protocol.ln

import java.math.BigInteger

import org.bitcoins.core.number.{UInt5, UInt8}
import org.bitcoins.core.util.Bech32
import org.bitcoins.crypto.{ECDigitalSignature, Factory, NetworkElement}
import scodec.bits.ByteVector


sealed abstract class LnInvoiceSignature extends NetworkElement {
  require(recoverId.toInt >= 0 && recoverId.toInt <= 3,
          s"signature recovery byte must be 0,1,2,3, got ${recoverId.toInt}")

  require(
    bytes.length == 65,
    s"LnInvoiceSignatures MUST be 65 bytes in length, got ${bytes.length}")
  def signature: ECDigitalSignature

  def recoverId: UInt8

  def data: Vector[UInt5] = {
    val bytes = signature.toRawRS ++ recoverId.bytes
    Bech32.from8bitTo5bit(bytes)
  }

  override def bytes: ByteVector = {
    signature.toRawRS ++ recoverId.bytes
  }
}

object LnInvoiceSignature extends Factory[LnInvoiceSignature] {

  private case class LnInvoiceSignatureImpl(
      recoverId: UInt8,
      signature: ECDigitalSignature)
      extends LnInvoiceSignature

  def apply(
      recoverId: UInt8,
      signature: ECDigitalSignature): LnInvoiceSignature = {
    LnInvoiceSignatureImpl(recoverId, signature)
  }

  def fromBytes(bytes: ByteVector): LnInvoiceSignature = {
    val sigBytes = bytes.take(64)
    val recoverId = UInt8(bytes(64))

    val signature = ECDigitalSignature.fromRS(sigBytes)

    LnInvoiceSignature.apply(recoverId = recoverId, signature = signature)
  }

  def fromRS(
      r: BigInteger,
      s: BigInteger,
      recovId: UInt8): LnInvoiceSignature = {
    val sig = ECDigitalSignature.fromRS(r, s)
    LnInvoiceSignature(recovId, sig)
  }

  def fromU5s(u5s: Vector[UInt5]): LnInvoiceSignature = {
    val u8s = Bech32.from5bitTo8bit(u5s)
    val bytes = UInt8.toBytes(u8s)
    fromBytes(bytes)
  }
} 
Example 122
Source File: TransactionOutput.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.protocol.transaction

import org.bitcoins.core.currency.{CurrencyUnit, CurrencyUnits}
import org.bitcoins.core.protocol.script.ScriptPubKey
import org.bitcoins.core.serializers.transaction.RawTransactionOutputParser
import org.bitcoins.crypto.{Factory, NetworkElement}
import scodec.bits.ByteVector

case class TransactionOutput(value: CurrencyUnit, scriptPubKey: ScriptPubKey)
    extends NetworkElement {

  //https://bitcoin.org/en/developer-reference#txout
  override lazy val byteSize = scriptPubKey.byteSize + 8

  override def bytes = RawTransactionOutputParser.write(this)
}

final object EmptyTransactionOutput
    extends TransactionOutput(CurrencyUnits.negativeSatoshi,
                              ScriptPubKey.empty) {
  override def toString(): String = "EmptyTransactionOutput"
}

object TransactionOutput extends Factory[TransactionOutput] {

  def fromBytes(bytes: ByteVector): TransactionOutput =
    RawTransactionOutputParser.read(bytes)

} 
Example 123
Source File: OutputReference.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.protocol.transaction

import org.bitcoins.crypto.{Factory, NetworkElement}
import scodec.bits.ByteVector


case class OutputReference(
    outPoint: TransactionOutPoint,
    output: TransactionOutput)
    extends NetworkElement {

  override def bytes: ByteVector = {
    outPoint.bytes ++ output.bytes
  }
}

object EmptyOutputReference
    extends OutputReference(EmptyTransactionOutPoint, EmptyTransactionOutput) {
  override def toString: String = "EmptyOutputReference"
}

object OutputReference extends Factory[OutputReference] {

  override def fromBytes(bytes: ByteVector): OutputReference = {
    val (outPointBytes, outputBytes) = bytes.splitAt(36)
    val outPoint = TransactionOutPoint(outPointBytes)
    val output = TransactionOutput(outputBytes)

    OutputReference(outPoint, output)
  }
} 
Example 124
Source File: Block.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.protocol.blockchain

import org.bitcoins.core.number.UInt64
import org.bitcoins.core.protocol.transaction.Transaction
import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.serializers.blockchain.RawBlockSerializer
import org.bitcoins.crypto.{Factory, NetworkElement}
import scodec.bits.ByteVector


object Block extends Factory[Block] {

  sealed private case class BlockImpl(
      blockHeader: BlockHeader,
      txCount: CompactSizeUInt,
      transactions: Seq[Transaction])
      extends Block

  def apply(
      blockHeader: BlockHeader,
      txCount: CompactSizeUInt,
      transactions: Seq[Transaction]): Block = {
    BlockImpl(blockHeader, txCount, transactions)
  }

  def apply(blockHeader: BlockHeader, transactions: Seq[Transaction]): Block = {
    val txCount = CompactSizeUInt(UInt64(transactions.size))
    Block(blockHeader, txCount, transactions)
  }

  def fromBytes(bytes: ByteVector): Block = RawBlockSerializer.read(bytes)

} 
Example 125
Source File: BlockFilter.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.gcs

import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.protocol.blockchain.Block
import org.bitcoins.core.protocol.script.{EmptyScriptPubKey, ScriptPubKey}
import org.bitcoins.core.protocol.transaction.{Transaction, TransactionOutput}
import org.bitcoins.core.script.control.OP_RETURN
import org.bitcoins.core.util.BytesUtil
import org.bitcoins.crypto.DoubleSha256Digest
import scodec.bits.ByteVector

object BlockFilter {

  
  def apply(
      block: Block,
      prevOutputScripts: Vector[ScriptPubKey]): GolombFilter = {
    val keyBytes: ByteVector = block.blockHeader.hash.bytes.take(16)

    val key: SipHashKey = SipHashKey(keyBytes)

    val newScriptPubKeys: Vector[ByteVector] =
      getOutputScriptPubKeysFromBlock(block).map(_.asmBytes)

    val prevOutputScriptBytes: Vector[ByteVector] =
      prevOutputScripts
        .filterNot(_ == EmptyScriptPubKey)
        .map(_.asmBytes)

    val allOutputs = (prevOutputScriptBytes ++ newScriptPubKeys).distinct

    GCS.buildBasicBlockFilter(allOutputs, key)
  }

  def fromBytes(
      bytes: ByteVector,
      blockHash: DoubleSha256Digest): GolombFilter = {
    val n = CompactSizeUInt.fromBytes(bytes)
    val filterBytes = bytes.drop(n.bytes.length)
    val keyBytes: ByteVector = blockHash.bytes.take(16)
    val key: SipHashKey = SipHashKey(keyBytes)

    GolombFilter(key,
                 FilterType.Basic.M,
                 FilterType.Basic.P,
                 n,
                 filterBytes.toBitVector)
  }

  def fromHex(hex: String, blockHash: DoubleSha256Digest): GolombFilter = {
    fromBytes(BytesUtil.decodeHex(hex), blockHash)
  }
} 
Example 126
Source File: GolombFilter.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.gcs

import org.bitcoins.core.number.{UInt64, UInt8}
import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.crypto.{
  CryptoUtil,
  DoubleSha256Digest,
  DoubleSha256DigestBE,
  NetworkElement
}
import scodec.bits.{BitVector, ByteVector}


  def getHeader(prevHeaderHash: DoubleSha256Digest): FilterHeader = {
    FilterHeader(filterHash = this.hash, prevHeaderHash = prevHeaderHash)
  }

  override def bytes: ByteVector = {
    n.bytes ++ encodedData.bytes
  }

  def hashToRange(item: ByteVector): UInt64 = GCS.hashToRange(item, f, key)

} 
Example 127
Source File: BloomFlag.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.bloom

import org.bitcoins.crypto.Factory
import scodec.bits.ByteVector


case object BloomUpdateP2PKOnly extends BloomFlag {
  def byte = 2.toByte
}

object BloomFlag extends Factory[BloomFlag] {
  private def flags = Seq(BloomUpdateNone, BloomUpdateAll, BloomUpdateP2PKOnly)

  def apply(byte: Byte): BloomFlag = {
    val flagOpt = flags.find(_.byte == byte)
    if (flagOpt.isDefined) flagOpt.get
    else
      throw new IllegalArgumentException(
        "The given byte was not defined for BloomFlag, got: " + byte)
  }

  def fromBytes(bytes: ByteVector): BloomFlag = BloomFlag(bytes.head)
} 
Example 128
Source File: NetworkHeader.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.p2p

import org.bitcoins.core.config.NetworkParameters
import org.bitcoins.core.number.UInt32
import org.bitcoins.core.serializers.p2p.headers.RawNetworkHeaderSerializer
import org.bitcoins.crypto.{CryptoUtil, Factory, NetworkElement}
import scodec.bits.ByteVector


  def apply(
      network: NetworkParameters,
      payload: NetworkPayload): NetworkHeader = {
    val checksum = CryptoUtil.doubleSHA256(payload.bytes)
    NetworkHeader(network,
                  payload.commandName,
                  UInt32(payload.bytes.size),
                  checksum.bytes.take(4))
  }
} 
Example 129
Source File: TypeIdentifier.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.p2p

import org.bitcoins.core.number.UInt32
import org.bitcoins.core.serializers.p2p.messages.RawTypeIdentifierSerializer
import org.bitcoins.crypto.{Factory, NetworkElement}
import scodec.bits.ByteVector


  private val MsgWitnessFlag = UInt32(1 << 30)

  private case class MsgUnassignedImpl(num: UInt32) extends MsgUnassigned

  override def fromBytes(bytes: ByteVector): TypeIdentifier =
    RawTypeIdentifierSerializer.read(bytes)

  def apply(num: Long): TypeIdentifier = TypeIdentifier(UInt32(num))

  def apply(uInt32: UInt32): TypeIdentifier =
    uInt32 match {
      case UInt32.one               => MsgTx
      case _ if uInt32 == UInt32(2) => MsgBlock
      case _ if uInt32 == UInt32(3) => MsgFilteredBlock
      case x: UInt32                => MsgUnassignedImpl(x)
    }
} 
Example 130
Source File: BytesUtil.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.util

import org.bitcoins.core.number.UInt64
import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.crypto.{CryptoBytesUtil, Factory, NetworkElement}
import scodec.bits.ByteVector

import scala.annotation.tailrec

trait BytesUtil extends CryptoBytesUtil {

  def writeCmpctSizeUInt[T <: NetworkElement](ts: Seq[T]): ByteVector = {
    val serialized = ts.map(_.bytes).foldLeft(ByteVector.empty)(_ ++ _)
    val cmpct = CompactSizeUInt(UInt64(ts.size))
    cmpct.bytes ++ serialized
  }

  
  def parseCmpctSizeUIntSeq[T <: NetworkElement](
      bytes: ByteVector,
      factory: Factory[T]): (Vector[T], ByteVector) = {
    val count = CompactSizeUInt.parse(bytes)
    val payload = bytes.drop(count.byteSize.toInt)
    val builder = Vector.newBuilder[T]

    @tailrec
    def loop(remaining: ByteVector, counter: Int = 0): ByteVector = {
      if (counter == count.num.toInt) {
        remaining
      } else {
        val parsed = factory.fromBytes(remaining)
        val newRemaining = remaining.drop(parsed.byteSize)

        builder.+=(parsed)

        loop(newRemaining, counter + 1)
      }
    }

    val remaining = loop(payload)
    val result = builder.result()
    require(
      result.size == count.num.toInt,
      s"Could not parse the amount of required elements, got: ${result.size} required: ${count}")

    (result, remaining)
  }
}

object BytesUtil extends BytesUtil 
Example 131
Source File: RawScriptSignatureParser.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.script

import org.bitcoins.core.protocol.script._
import org.bitcoins.core.serializers.RawBitcoinSerializer
import org.bitcoins.core.util.BitcoinScriptUtil
import scodec.bits.ByteVector


sealed abstract class RawScriptSignatureParser
    extends RawBitcoinSerializer[ScriptSignature] {

  def read(bytes: ByteVector): ScriptSignature = {
    if (bytes.isEmpty) EmptyScriptSignature
    else {
      BitcoinScriptUtil.parseScript(bytes = bytes, f = ScriptSignature.fromAsm)
    }
  }

  def write(scriptSig: ScriptSignature): ByteVector = scriptSig.bytes
}

object RawScriptSignatureParser extends RawScriptSignatureParser 
Example 132
Source File: RawScriptWitnessParser.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.script

import org.bitcoins.core.number.UInt64
import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.protocol.script.ScriptWitness
import org.bitcoins.core.serializers.RawBitcoinSerializer
import scodec.bits.ByteVector

import scala.annotation.tailrec


sealed abstract class RawScriptWitnessParser
    extends RawBitcoinSerializer[ScriptWitness] {

  def read(bytes: ByteVector): ScriptWitness = {
    //first byte is the number of stack items
    val stackSize = CompactSizeUInt.parseCompactSizeUInt(bytes)
    val (_, stackBytes) = bytes.splitAt(stackSize.byteSize.toInt)
    @tailrec
    def loop(
        remainingBytes: ByteVector,
        accum: Seq[ByteVector],
        remainingStackItems: UInt64): Seq[ByteVector] = {
      if (remainingStackItems <= UInt64.zero) accum
      else {
        val elementSize = CompactSizeUInt.parseCompactSizeUInt(remainingBytes)
        val (_, stackElementBytes) =
          remainingBytes.splitAt(elementSize.byteSize.toInt)
        val stackElement = stackElementBytes.take(elementSize.num.toInt)
        val (_, newRemainingBytes) =
          stackElementBytes.splitAt(stackElement.size)
        loop(newRemainingBytes,
             stackElement +: accum,
             remainingStackItems - UInt64.one)
      }
    }
    //note there is no 'reversing' the accum, in bitcoin-s we assume the top of the stack is the 'head' element in the sequence
    val stack = loop(stackBytes, Nil, stackSize.num)
    val witness = ScriptWitness(stack)
    witness
  }

  def write(scriptWitness: ScriptWitness): ByteVector = {
    @tailrec
    def loop(
        remainingStack: Seq[ByteVector],
        accum: Vector[ByteVector]): Vector[ByteVector] = {
      if (remainingStack.isEmpty) accum.reverse
      else {
        val compactSizeUInt: CompactSizeUInt =
          CompactSizeUInt.calc(remainingStack.head)
        val serialization: ByteVector =
          compactSizeUInt.bytes ++ remainingStack.head
        loop(remainingStack.tail, serialization +: accum)
      }
    }
    val stackItems: Vector[ByteVector] =
      loop(scriptWitness.stack.reverse, Vector.empty)
    val size = CompactSizeUInt(UInt64(stackItems.size))
    (size.bytes +: stackItems).fold(ByteVector.empty)(_ ++ _)
  }
}

object RawScriptWitnessParser extends RawScriptWitnessParser 
Example 133
Source File: RawScriptPubKeyParser.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.script

import org.bitcoins.core.protocol.script.{EmptyScriptPubKey, ScriptPubKey}
import org.bitcoins.core.serializers.RawBitcoinSerializer
import org.bitcoins.core.util.BitcoinScriptUtil
import scodec.bits.ByteVector


trait RawScriptPubKeyParser extends RawBitcoinSerializer[ScriptPubKey] {

  override def read(bytes: ByteVector): ScriptPubKey = {
    if (bytes.isEmpty) EmptyScriptPubKey
    else {
      BitcoinScriptUtil.parseScript(bytes = bytes, f = ScriptPubKey.fromAsm)
    }
  }

  override def write(scriptPubKey: ScriptPubKey): ByteVector =
    scriptPubKey.bytes
}

object RawScriptPubKeyParser extends RawScriptPubKeyParser 
Example 134
Source File: RawTransactionOutputParser.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.transaction

import org.bitcoins.core.currency.{CurrencyUnits, Satoshis}
import org.bitcoins.core.protocol.transaction.TransactionOutput
import org.bitcoins.core.serializers.script.RawScriptPubKeyParser
import org.bitcoins.core.serializers.{
  RawBitcoinSerializer,
  RawSatoshisSerializer
}
import scodec.bits.ByteVector


  override def read(bytes: ByteVector): TransactionOutput = {
    val satoshisBytes = bytes.take(8)
    val satoshis = RawSatoshisSerializer.read(satoshisBytes)
    //it doesn't include itself towards the size, thats why it is incremented by one
    val scriptPubKeyBytes = bytes.slice(8, bytes.size)
    val scriptPubKey = RawScriptPubKeyParser.read(scriptPubKeyBytes)
    val parsedOutput = TransactionOutput(satoshis, scriptPubKey)
    parsedOutput
  }

}

object RawTransactionOutputParser extends RawTransactionOutputParser 
Example 135
Source File: RawTransactionOutPointParser.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.transaction

import org.bitcoins.core.number.UInt32
import org.bitcoins.core.protocol.transaction.{
  EmptyTransactionOutPoint,
  TransactionOutPoint
}
import org.bitcoins.core.serializers.RawBitcoinSerializer
import org.bitcoins.crypto.DoubleSha256Digest
import scodec.bits.ByteVector


sealed abstract class RawTransactionOutPointParser
    extends RawBitcoinSerializer[TransactionOutPoint] {

  override def read(bytes: ByteVector): TransactionOutPoint = {
    val txId: ByteVector = bytes.take(32)
    val indexBytes = bytes.slice(32, 36)
    val index = UInt32(indexBytes.reverse)
    TransactionOutPoint(DoubleSha256Digest(txId), index)
  }

  def write(outPoint: TransactionOutPoint): ByteVector = {
    //UInt32s cannot hold negative numbers, but sometimes the Bitcoin Protocol requires the vout to be -1, which is serialized
    //as "0xFFFFFFFF".
    //https://github.com/bitcoin/bitcoin/blob/d612837814020ae832499d18e6ee5eb919a87907/src/primitives/transaction.h
    //http://stackoverflow.com/questions/2711522/what-happens-if-i-assign-a-negative-value-to-an-unsigned-variable
    val idxBytes = outPoint match {
      case EmptyTransactionOutPoint      => UInt32.max.bytes
      case outPoint: TransactionOutPoint => outPoint.vout.bytes
    }
    val txIdHex = outPoint.txId.bytes
    txIdHex ++ idxBytes.reverse
  }

}

object RawTransactionOutPointParser extends RawTransactionOutPointParser 
Example 136
Source File: RawTransactionWitnessParser.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.transaction

import org.bitcoins.core.protocol.script.ScriptWitness
import org.bitcoins.core.protocol.transaction.TransactionWitness
import org.bitcoins.core.serializers.script.RawScriptWitnessParser
import scodec.bits.ByteVector

import scala.annotation.tailrec


  def read(bytes: ByteVector, numInputs: Int): TransactionWitness = {
    @tailrec
    def loop(
        remainingBytes: ByteVector,
        remainingInputs: Int,
        accum: Vector[ScriptWitness]): Vector[ScriptWitness] = {
      if (remainingInputs != 0) {
        val w = RawScriptWitnessParser.read(remainingBytes)
        val (_, newRemainingBytes) = remainingBytes.splitAt(w.bytes.size)
        loop(newRemainingBytes, remainingInputs - 1, w +: accum)
      } else accum.reverse
    }
    val witnesses = loop(bytes, numInputs, Vector.empty)
    require(witnesses.size == numInputs)
    TransactionWitness(witnesses)
  }

  def write(witness: TransactionWitness): ByteVector = {
    witness.foldLeft(ByteVector.empty)(_ ++ _.bytes)
  }
}

object RawTransactionWitnessParser extends RawTransactionWitnessParser 
Example 137
Source File: RawBitcoinSerializerHelper.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers

import org.bitcoins.core.number.UInt64
import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.crypto.NetworkElement
import scodec.bits.ByteVector

import scala.annotation.tailrec


  final def writeNetworkElements[T <: NetworkElement](
      ts: Seq[T]): ByteVector = {
    val f = { t: T =>
      t.bytes
    }
    write(ts, f)
  }

  final def write[T](ts: Seq[T], serializer: T => ByteVector): ByteVector = {
    ts.foldLeft(ByteVector.empty) {
      case (accum, t) =>
        accum ++ serializer(t)
    }
  }
}

object RawSerializerHelper extends RawSerializerHelper 
Example 138
Source File: RawBloomFilterSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.bloom

import org.bitcoins.core.bloom.{BloomFilter, BloomFlag}
import org.bitcoins.core.number.UInt32
import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.serializers.RawBitcoinSerializer
import scodec.bits.ByteVector


sealed abstract class RawBloomFilterSerializer
    extends RawBitcoinSerializer[BloomFilter] {

  override def read(bytes: ByteVector): BloomFilter = {
    val filterSize = CompactSizeUInt.parseCompactSizeUInt(bytes)
    val filter = bytes.slice(filterSize.byteSize.toInt,
                             filterSize.byteSize.toInt + filterSize.num.toInt)
    val hashFuncsIndex = (filterSize.byteSize + filterSize.num.toInt).toInt
    val hashFuncs = UInt32(
      bytes.slice(hashFuncsIndex, hashFuncsIndex + 4).reverse)
    val tweakIndex = hashFuncsIndex + 4
    val tweak = UInt32(bytes.slice(tweakIndex, tweakIndex + 4).reverse)
    val flags = BloomFlag(bytes(tweakIndex + 4))
    BloomFilter(filterSize, filter, hashFuncs, tweak, flags)

  }

  override def write(bloomFilter: BloomFilter): ByteVector = {
    bloomFilter.filterSize.bytes ++ bloomFilter.data ++
      bloomFilter.hashFuncs.bytes.reverse ++ bloomFilter.tweak.bytes.reverse ++
      ByteVector.fromByte(bloomFilter.flags.byte)
  }
}

object RawBloomFilterSerializer extends RawBloomFilterSerializer 
Example 139
Source File: RawNetworkMessageSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p

import org.bitcoins.core.p2p._
import org.bitcoins.core.serializers.RawBitcoinSerializer
import scodec.bits.ByteVector

trait RawNetworkMessageSerializer extends RawBitcoinSerializer[NetworkMessage] {

  def read(bytes: ByteVector): NetworkMessage = {
    //first 24 bytes are the header
    val (headerBytes, payloadBytes) = bytes.splitAt(24)
    val header = NetworkHeader.fromBytes(headerBytes)
    if (header.payloadSize.toInt > payloadBytes.length) {
      throw new RuntimeException(
        s"We do not have enough bytes for payload! Expected=${header.payloadSize.toInt} got=${payloadBytes.length}")
    } else {
      val payload = NetworkPayload(header, payloadBytes)
      val n = NetworkMessage(header, payload)
      n
    }
  }

  def write(networkMessage: NetworkMessage): ByteVector = {
    networkMessage.header.bytes ++ networkMessage.payload.bytes
  }
}

object RawNetworkMessageSerializer extends RawNetworkMessageSerializer 
Example 140
Source File: RawGetCompactFiltersMessageSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p.messages

import org.bitcoins.core.gcs.FilterType
import org.bitcoins.core.number.UInt32
import org.bitcoins.core.p2p.GetCompactFiltersMessage
import org.bitcoins.core.serializers.RawBitcoinSerializer
import org.bitcoins.crypto.DoubleSha256Digest
import scodec.bits.ByteVector


object RawGetCompactFiltersMessageSerializer
    extends RawBitcoinSerializer[GetCompactFiltersMessage] {

  def read(bytes: ByteVector): GetCompactFiltersMessage = {
    val filterType = FilterType.fromBytes(bytes.take(1))
    val (startHeightBytes, rest) = bytes.drop(1).splitAt(4)
    val startHeight = UInt32.fromBytes(startHeightBytes.reverse)
    val stopHash = DoubleSha256Digest.fromBytes(rest.take(32))
    GetCompactFiltersMessage(filterType, startHeight, stopHash)
  }

  def write(message: GetCompactFiltersMessage): ByteVector = {
    val filterType = message.filterType.bytes
    val startHeight = message.startHeight.bytes.reverse
    val stopHash = message.stopHash.bytes
    val bytes = filterType ++ startHeight ++ stopHash
    bytes
  }

} 
Example 141
Source File: RawFilterLoadMessageSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p.messages

import org.bitcoins.core.serializers.RawBitcoinSerializer
import org.bitcoins.core.serializers.bloom.RawBloomFilterSerializer
import org.bitcoins.core.p2p.FilterLoadMessage
import scodec.bits.ByteVector


trait RawFilterLoadMessageSerializer
    extends RawBitcoinSerializer[FilterLoadMessage] {

  override def read(bytes: ByteVector): FilterLoadMessage = {
    val filter = RawBloomFilterSerializer.read(bytes)
    FilterLoadMessage(filter)
  }

  override def write(filterLoadMessage: FilterLoadMessage): ByteVector = {
    RawBloomFilterSerializer.write(filterLoadMessage.bloomFilter)
  }
}

object RawFilterLoadMessageSerializer extends RawFilterLoadMessageSerializer 
Example 142
Source File: RawGetBlocksMessageSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p.messages

import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.serializers.{RawBitcoinSerializer, RawSerializerHelper}
import org.bitcoins.core.p2p._
import org.bitcoins.crypto.DoubleSha256Digest
import scodec.bits.ByteVector

import scala.annotation.tailrec


  private def parseBlockHeaders(
      bytes: ByteVector,
      compactSizeUInt: CompactSizeUInt): (
      List[DoubleSha256Digest],
      ByteVector) = {
    @tailrec
    def loop(
        remainingHeaders: Long,
        accum: List[DoubleSha256Digest],
        remainingBytes: ByteVector): (List[DoubleSha256Digest], ByteVector) = {
      if (remainingHeaders <= 0) (accum.reverse, remainingBytes)
      else {
        val dsha256 = DoubleSha256Digest(remainingBytes.slice(0, 32))
        val rem = remainingBytes.slice(32, remainingBytes.size)
        loop(remainingHeaders = remainingHeaders - 1,
             accum = dsha256 :: accum,
             remainingBytes = rem)
      }
    }
    loop(compactSizeUInt.num.toInt, List.empty, bytes)
  }
}

object RawGetBlocksMessageSerializer extends RawGetBlocksMessageSerializer 
Example 143
Source File: RawCompactFilterCheckpointMessageSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p.messages

import org.bitcoins.core.gcs.FilterType
import org.bitcoins.core.p2p.CompactFilterCheckPointMessage
import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.serializers.{RawBitcoinSerializer, RawSerializerHelper}
import org.bitcoins.crypto.DoubleSha256Digest
import scodec.bits.ByteVector


object RawCompactFilterCheckpointMessageSerializer
    extends RawBitcoinSerializer[CompactFilterCheckPointMessage] {

  def read(bytes: ByteVector): CompactFilterCheckPointMessage = {
    val filterType = FilterType.fromBytes(bytes.take(1))

    val (stopHashBytes, afterStopHash) = bytes.drop(1).splitAt(32)
    val stopHash = DoubleSha256Digest.fromBytes(stopHashBytes)

    val filterHeadersLength = CompactSizeUInt.parse(afterStopHash)

    val (headers, _) =
      RawSerializerHelper.parseCmpctSizeUIntSeq(
        afterStopHash,
        { bytes =>
          DoubleSha256Digest.fromBytes(bytes.take(32))
        })

    require(
      headers.length == filterHeadersLength.toInt,
      s"Invalid compact filter checkpoint message: expected number of headers ${filterHeadersLength.toInt}, but got ${headers.length}"
    )

    CompactFilterCheckPointMessage(filterType, stopHash, headers.toVector)
  }

  def write(message: CompactFilterCheckPointMessage): ByteVector = {
    val filterType = message.filterType.bytes
    val stopHash = message.stopHash.bytes
    val filterHeaders =
      RawSerializerHelper.writeCmpctSizeUInt(message.filterHeaders,
                                             { fh: DoubleSha256Digest =>
                                               fh.bytes
                                             })
    filterType ++ stopHash ++ filterHeaders
  }
} 
Example 144
Source File: RawGetDataMessageSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p.messages

import org.bitcoins.core.serializers.RawBitcoinSerializer
import org.bitcoins.core.p2p.{GetDataMessage, InventoryMessage}
import scodec.bits.ByteVector


trait RawGetDataMessageSerializer extends RawBitcoinSerializer[GetDataMessage] {
  //InventoryMessages & GetDataMessages have the same structure and are serialized the same
  //so we can piggy back off of the serialilzers for InventoryMessages

  def read(bytes: ByteVector): GetDataMessage = {
    val inv = InventoryMessage(bytes)
    GetDataMessage(inv.inventoryCount, inv.inventories)
  }

  def write(getDataMessage: GetDataMessage): ByteVector = {
    val inv = InventoryMessage(getDataMessage.inventoryCount,
                               getDataMessage.inventories)
    inv.bytes
  }
}

object RawGetDataMessageSerializer extends RawGetDataMessageSerializer 
Example 145
Source File: RawNotFoundMessageSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p.messages

import org.bitcoins.core.serializers.RawBitcoinSerializer
import org.bitcoins.core.p2p.{InventoryMessage, NotFoundMessage}
import scodec.bits.ByteVector


trait RawNotFoundMessageSerializer
    extends RawBitcoinSerializer[NotFoundMessage] {

  override def read(bytes: ByteVector): NotFoundMessage = {
    //this seems funky, but according to the documentation inventory messages
    //and NotFoundMessages have the same structure, therefore we can piggy back
    //off of the serializer used by InventoryMessage
    val inventoryMessage = InventoryMessage(bytes)
    NotFoundMessage(inventoryMessage.inventoryCount,
                    inventoryMessage.inventories)

  }

  override def write(notFoundMessage: NotFoundMessage): ByteVector = {
    //Since InventoryMessages and NotFoundMessages have the same format
    //we can just create an inventory message then piggy back off of the
    //serializer used by inventory message
    val inventoryMessage = InventoryMessage(notFoundMessage.inventoryCount,
                                            notFoundMessage.inventories)
    inventoryMessage.bytes
  }

}

object RawNotFoundMessageSerializer extends RawNotFoundMessageSerializer 
Example 146
Source File: RawCompactFilterMessageSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p.messages

import org.bitcoins.core.gcs.FilterType
import org.bitcoins.core.number.UInt64
import org.bitcoins.core.serializers.RawBitcoinSerializer
import org.bitcoins.core.p2p.CompactFilterMessage
import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.crypto.DoubleSha256Digest
import scodec.bits.ByteVector


object RawCompactFilterMessageSerializer
    extends RawBitcoinSerializer[CompactFilterMessage] {

  def read(bytes: ByteVector): CompactFilterMessage = {
    val filterType = FilterType.fromBytes(bytes.take(1))

    val (blockHashBytes, afterBlockHash) = bytes.drop(1).splitAt(32)
    val blockHash = DoubleSha256Digest.fromBytes(blockHashBytes)

    val mumFilterBytes = CompactSizeUInt.parse(afterBlockHash)

    val filterBytes = afterBlockHash
      .drop(mumFilterBytes.bytes.length)
      .take(mumFilterBytes.toInt)

    CompactFilterMessage(filterType, blockHash, filterBytes)
  }

  def write(message: CompactFilterMessage): ByteVector = {
    val filterType = message.filterType.bytes
    val blockHash = message.blockHash.bytes
    val numFilterBytes = CompactSizeUInt(UInt64(message.filterBytes.size)).bytes
    val filterBytes = message.filterBytes
    filterType ++ blockHash ++ numFilterBytes ++ filterBytes
  }
} 
Example 147
Source File: RawGetCompactFilterHeadersMessageSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p.messages

import org.bitcoins.core.gcs.FilterType
import org.bitcoins.core.number.UInt32
import org.bitcoins.core.p2p.GetCompactFilterHeadersMessage
import org.bitcoins.core.serializers.RawBitcoinSerializer
import org.bitcoins.crypto.DoubleSha256Digest
import scodec.bits.ByteVector


object RawGetCompactFilterHeadersMessageSerializer
    extends RawBitcoinSerializer[GetCompactFilterHeadersMessage] {

  def read(bytes: ByteVector): GetCompactFilterHeadersMessage = {
    val filterType = FilterType.fromBytes(bytes.take(1))
    val startHeight = UInt32.fromBytes(bytes.drop(1).take(4).reverse)
    val stopHash = bytes.drop(5).take(32)
    GetCompactFilterHeadersMessage(
      filterType = filterType,
      startHeight = startHeight,
      stopHash = DoubleSha256Digest.fromBytes(stopHash)
    )
  }

  def write(message: GetCompactFilterHeadersMessage): ByteVector = {
    val filterType = message.filterType.bytes
    val startHeight = message.startHeight.bytes.reverse
    val stopHash = message.stopHash.bytes
    val bytes = filterType ++ startHeight ++ stopHash
    bytes
  }
} 
Example 148
Source File: RawGetHeadersMessageSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p.messages

import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.serializers.{RawBitcoinSerializer, RawSerializerHelper}
import org.bitcoins.core.p2p._
import org.bitcoins.crypto.DoubleSha256Digest
import scodec.bits.ByteVector

import scala.annotation.tailrec

trait RawGetHeadersMessageSerializer
    extends RawBitcoinSerializer[GetHeadersMessage] {

  override def read(bytes: ByteVector): GetHeadersMessage = {
    val version = ProtocolVersion(bytes.take(4))
    val hashCount =
      CompactSizeUInt.parseCompactSizeUInt(bytes.slice(4, bytes.length))
    val hashesStartIndex = (hashCount.byteSize + 4).toInt
    val (hashes, remainingBytes) =
      parseHashes(bytes.slice(hashesStartIndex, bytes.length), hashCount)
    val hashStop = DoubleSha256Digest(remainingBytes.take(32))
    GetHeadersMessage(version, hashCount, hashes, hashStop)
  }

  override def write(getHeadersMessage: GetHeadersMessage): ByteVector = {
    getHeadersMessage.version.bytes ++
      getHeadersMessage.hashCount.bytes ++
      RawSerializerHelper.writeNetworkElements(getHeadersMessage.hashes) ++
      getHeadersMessage.hashStop.bytes
  }

  
  private def parseHashes(
      bytes: ByteVector,
      numHashes: CompactSizeUInt): (List[DoubleSha256Digest], ByteVector) = {
    @tailrec
    def loop(
        remainingBytes: ByteVector,
        remainingHashes: Long,
        accum: List[DoubleSha256Digest]): (
        List[DoubleSha256Digest],
        ByteVector) = {
      if (remainingHashes <= 0) (accum.reverse, remainingBytes)
      else {
        val hash = DoubleSha256Digest(remainingBytes.take(32))
        loop(remainingBytes.slice(32, remainingBytes.length),
             remainingHashes - 1,
             hash :: accum)
      }
    }

    loop(bytes, numHashes.num.toInt, List.empty)
  }
}

object RawGetHeadersMessageSerializer extends RawGetHeadersMessageSerializer 
Example 149
Source File: RawCompactFilterHeadersMessageSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p.messages

import org.bitcoins.core.gcs.FilterType
import org.bitcoins.core.p2p.CompactFilterHeadersMessage
import org.bitcoins.core.serializers.{RawBitcoinSerializer, RawSerializerHelper}
import org.bitcoins.crypto.DoubleSha256Digest
import scodec.bits.ByteVector


object RawCompactFilterHeadersMessageSerializer
    extends RawBitcoinSerializer[CompactFilterHeadersMessage] {

  def read(bytes: ByteVector): CompactFilterHeadersMessage = {
    val filterType = FilterType.fromBytes(bytes.take(1))

    val (stopHashBytes, afterStopHash) = bytes.drop(1).splitAt(32)
    val stopHash = DoubleSha256Digest.fromBytes(stopHashBytes)

    val (previousFilterHeaderBytes, afterPreviousFilterHeader) =
      afterStopHash.splitAt(32)
    val previousFilterHeaderHash =
      DoubleSha256Digest.fromBytes(previousFilterHeaderBytes)

    val (hashes, _) =
      RawSerializerHelper.parseCmpctSizeUIntSeq(
        afterPreviousFilterHeader,
        { bytes =>
          DoubleSha256Digest.fromBytes(bytes.take(32))
        })

    val message = CompactFilterHeadersMessage(filterType,
                                              stopHash,
                                              previousFilterHeaderHash,
                                              hashes.toVector)

    message
  }

  def write(message: CompactFilterHeadersMessage): ByteVector = {
    val filterType = message.filterType.bytes
    val stopHash = message.stopHash.bytes
    val previousFilterHeader = message.previousFilterHeader.bytes
    val filterHashes =
      RawSerializerHelper.writeCmpctSizeUInt(message.filterHashes,
                                             { fh: DoubleSha256Digest =>
                                               fh.bytes
                                             })

    filterType ++ stopHash ++ previousFilterHeader ++ filterHashes
  }

} 
Example 150
Source File: RawVersionMessageSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p.messages

import java.net.InetAddress

import org.bitcoins.core.number.{Int32, Int64, UInt32, UInt64}
import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.serializers.RawBitcoinSerializer
import org.bitcoins.core.util.BitcoinSLogger
import org.bitcoins.core.p2p._
import scodec.bits.ByteVector


trait RawVersionMessageSerializer
    extends RawBitcoinSerializer[VersionMessage]
    with BitcoinSLogger {

  def read(bytes: ByteVector): VersionMessage = {
    val version = ProtocolVersion(bytes.take(4))

    val services = ServiceIdentifier(bytes.slice(4, 12))

    val timestamp = Int64(bytes.slice(12, 20).reverse)

    val addressReceiveServices = ServiceIdentifier(bytes.slice(20, 28))

    val addressReceiveIpAddress =
      InetAddress.getByAddress(bytes.slice(28, 44).toArray)

    val addressReceivePort = UInt32(bytes.slice(44, 46)).toInt

    val addressTransServices = ServiceIdentifier(bytes.slice(46, 54))

    val addressTransIpAddress =
      InetAddress.getByAddress(bytes.slice(54, 70).toArray)

    val addressTransPort = UInt32(bytes.slice(70, 72)).toInt

    val nonce = UInt64(bytes.slice(72, 80))

    val userAgentSize =
      CompactSizeUInt.parseCompactSizeUInt(bytes.slice(80, bytes.size))

    val userAgentBytesStartIndex = 80 + userAgentSize.byteSize.toInt

    val userAgentBytes = bytes.slice(
      userAgentBytesStartIndex,
      userAgentBytesStartIndex + userAgentSize.num.toInt)

    val userAgent = userAgentBytes.toArray.map(_.toChar).mkString

    val startHeightStartIndex =
      userAgentBytesStartIndex + userAgentSize.num.toInt

    val startHeight = Int32(
      bytes.slice(startHeightStartIndex, startHeightStartIndex + 4).reverse)

    val relay = bytes(startHeightStartIndex + 4) != 0

    VersionMessage(
      version = version,
      services = services,
      timestamp = timestamp,
      addressReceiveServices = addressReceiveServices,
      addressReceiveIpAddress = addressReceiveIpAddress,
      addressReceivePort = addressReceivePort,
      addressTransServices = addressTransServices,
      addressTransIpAddress = addressTransIpAddress,
      addressTransPort = addressTransPort,
      nonce = nonce,
      userAgent = userAgent,
      startHeight = startHeight,
      relay = relay
    )
  }

  def write(versionMessage: VersionMessage): ByteVector = {
    versionMessage.version.bytes ++
      versionMessage.services.bytes ++
      versionMessage.timestamp.bytes.reverse ++
      versionMessage.addressReceiveServices.bytes ++
      NetworkIpAddress.writeAddress(versionMessage.addressReceiveIpAddress) ++
      //encode hex returns 8 characters, but we only need the last 4 since port number is a uint16
      //check for precision loss here?
      ByteVector.fromShort(versionMessage.addressReceivePort.toShort) ++
      versionMessage.addressTransServices.bytes ++
      NetworkIpAddress.writeAddress(versionMessage.addressTransIpAddress) ++
      //encode hex returns 8 characters, but we only need the last 4 since port number is a uint16
      //check for precision loss here?
      ByteVector.fromShort(versionMessage.addressTransPort.toShort) ++
      versionMessage.nonce.bytes ++
      versionMessage.userAgentSize.bytes ++
      ByteVector(versionMessage.userAgent.getBytes) ++
      versionMessage.startHeight.bytes.reverse ++
      (if (versionMessage.relay) ByteVector.fromByte(1.toByte)
       else ByteVector.fromByte(0.toByte))
  }

}

object RawVersionMessageSerializer extends RawVersionMessageSerializer 
Example 151
Source File: RawHeadersMessageSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p.messages

import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.protocol.blockchain.BlockHeader
import org.bitcoins.core.serializers.RawBitcoinSerializer
import org.bitcoins.core.p2p.HeadersMessage
import scodec.bits.ByteVector

import scala.annotation.tailrec

trait RawHeadersMessageSerializer extends RawBitcoinSerializer[HeadersMessage] {

  def read(bytes: ByteVector): HeadersMessage = {
    val compactSizeUInt = CompactSizeUInt.parseCompactSizeUInt(bytes)
    val headerStartIndex = compactSizeUInt.byteSize.toInt
    val headerBytes = bytes.slice(headerStartIndex, bytes.length)
    val headers = parseBlockHeaders(headerBytes, compactSizeUInt)
    HeadersMessage(compactSizeUInt, headers)
  }

  def write(headersMessage: HeadersMessage): ByteVector = {
    val z = ByteVector.fromByte(0.toByte)
    val headerBytes = headersMessage.headers.foldLeft(ByteVector.empty) {
      case (accum, msg) =>
        accum ++ msg.bytes ++ z
    }
    headersMessage.count.bytes ++ headerBytes
  }

  private def parseBlockHeaders(
      bytes: ByteVector,
      compactSizeUInt: CompactSizeUInt): Vector[BlockHeader] = {
    @tailrec
    def loop(
        remainingBytes: ByteVector,
        remainingHeaders: Long,
        accum: List[BlockHeader]): List[BlockHeader] = {
      if (remainingHeaders <= 0) accum
      //81 is because HeadersMessage appends 0x00 at the end of every block header for some reason
      //read https://bitcoin.org/en/developer-reference#headers
      else {
        require(
          remainingBytes.size >= 80,
          "We do not have enough bytes for another block header, this probably means a tcp frame was not aligned")
        loop(remainingBytes = remainingBytes.slice(81, remainingBytes.length),
             remainingHeaders = remainingHeaders - 1,
             accum = BlockHeader(remainingBytes.take(80)) :: accum)
      }
    }
    loop(bytes, compactSizeUInt.num.toInt, List.empty).reverse.toVector
  }
}

object RawHeadersMessageSerializer extends RawHeadersMessageSerializer 
Example 152
Source File: RawFeeFilterMessageSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p.messages

import org.bitcoins.core.currency.Satoshis
import org.bitcoins.core.serializers.RawBitcoinSerializer
import org.bitcoins.core.wallet.fee.SatoshisPerKiloByte
import org.bitcoins.core.p2p._
import scodec.bits.ByteVector

sealed abstract class RawFeeFilterMessageSerializer
    extends RawBitcoinSerializer[FeeFilterMessage] {

  override def read(bytes: ByteVector): FeeFilterMessage = {
    val satBytes = bytes.take(8).reverse
    val sat = Satoshis(satBytes)
    val satPerKb = SatoshisPerKiloByte(sat)
    FeeFilterMessage(satPerKb)
  }

  override def write(feeFilterMessage: FeeFilterMessage): ByteVector = {
    feeFilterMessage.feeRate.currencyUnit.satoshis.bytes.reverse
  }
}

object RawFeeFilterMessageSerializer extends RawFeeFilterMessageSerializer 
Example 153
Source File: RawRejectMessageSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p.messages

import org.bitcoins.core.p2p.RejectMessage
import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.serializers.RawBitcoinSerializer
import scodec.bits.ByteVector

trait RawRejectMessageSerializer extends RawBitcoinSerializer[RejectMessage] {

  def read(bytes: ByteVector): RejectMessage = {
    val messageSize = CompactSizeUInt.parseCompactSizeUInt(bytes)
    val message: String = bytes
      .slice(messageSize.byteSize.toInt,
             messageSize.byteSize.toInt +
               messageSize.num.toInt)
      .toArray
      .map(_.toChar)
      .mkString
    val code: Char = bytes(
      messageSize.byteSize.toInt + messageSize.num.toInt).toChar
    val reasonSizeStartIndex =
      messageSize.byteSize.toInt + messageSize.num.toInt + 1
    val reasonSize = CompactSizeUInt.parseCompactSizeUInt(
      bytes.slice(reasonSizeStartIndex.toInt, bytes.size))
    val reason = bytes
      .slice(
        (reasonSizeStartIndex + reasonSize.byteSize).toInt,
        (reasonSizeStartIndex + reasonSize.byteSize.toInt + reasonSize.num.toInt))
      .toArray
      .map(_.toChar)
      .mkString
    val extraStartIndex =
      reasonSizeStartIndex + reasonSize.byteSize.toInt + reasonSize.num.toInt
    val extra = bytes.slice(extraStartIndex, bytes.size)
    RejectMessage(messageSize, message, code, reasonSize, reason, extra)
  }

  def write(rejectMessage: RejectMessage): ByteVector = {
    rejectMessage.messageSize.bytes ++
      ByteVector(rejectMessage.message.map(_.toByte)) ++
      ByteVector.fromByte(rejectMessage.code.toByte) ++
      rejectMessage.reasonSize.bytes ++
      ByteVector(rejectMessage.reason.map(_.toByte)) ++
      rejectMessage.extra
  }
}

object RawRejectMessageSerializer extends RawRejectMessageSerializer 
Example 154
Source File: RawFilterAddMessageSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p.messages

import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.serializers.RawBitcoinSerializer
import org.bitcoins.core.p2p._
import scodec.bits.ByteVector


trait RawFilterAddMessageSerializer
    extends RawBitcoinSerializer[FilterAddMessage] {

  override def read(bytes: ByteVector): FilterAddMessage = {
    val elementSize = CompactSizeUInt.parseCompactSizeUInt(bytes)
    val element = bytes.slice(elementSize.byteSize.toInt, bytes.size)
    FilterAddMessage(elementSize, element)
  }

  override def write(filterAddMessage: FilterAddMessage): ByteVector = {
    filterAddMessage.elementSize.bytes ++ filterAddMessage.element
  }
}

object RawFilterAddMessageSerializer extends RawFilterAddMessageSerializer 
Example 155
Source File: RawGetCompactFilterCheckpointMessageSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p.messages

import org.bitcoins.core.gcs.FilterType
import org.bitcoins.core.p2p.GetCompactFilterCheckPointMessage
import org.bitcoins.core.serializers.RawBitcoinSerializer
import org.bitcoins.crypto.DoubleSha256Digest
import scodec.bits.ByteVector


object RawGetCompactFilterCheckpointMessageSerializer
    extends RawBitcoinSerializer[GetCompactFilterCheckPointMessage] {

  def read(bytes: ByteVector): GetCompactFilterCheckPointMessage = {
    val filterType = FilterType.fromBytes(bytes.take(1))
    val stopHash = bytes.drop(1).take(32)
    GetCompactFilterCheckPointMessage(
      filterType = filterType,
      stopHash = DoubleSha256Digest.fromBytes(stopHash)
    )
  }

  def write(message: GetCompactFilterCheckPointMessage): ByteVector = {
    val filterType = message.filterType.bytes
    val stopHash = message.stopHash.bytes
    val bytes = filterType ++ stopHash
    bytes
  }
} 
Example 156
Source File: RawInventoryMessageSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p.messages

import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.serializers.{RawBitcoinSerializer, RawSerializerHelper}
import org.bitcoins.core.p2p.{Inventory, InventoryMessage}
import scodec.bits.ByteVector

import scala.annotation.tailrec


  private def parseInventories(
      bytes: ByteVector,
      requiredInventories: CompactSizeUInt): (List[Inventory], ByteVector) = {
    @tailrec
    def loop(
        remainingInventories: Long,
        remainingBytes: ByteVector,
        accum: List[Inventory]): (List[Inventory], ByteVector) = {
      if (remainingInventories <= 0) (accum.reverse, remainingBytes)
      else {
        val inventory = RawInventorySerializer.read(remainingBytes.slice(0, 36))
        loop(remainingInventories - 1,
             remainingBytes.slice(36, remainingBytes.size),
             inventory :: accum)
      }
    }
    loop(requiredInventories.num.toInt, bytes, List.empty)
  }
}

object RawInventoryMessageSerializer extends RawInventoryMessageSerializer 
Example 157
Source File: RawAddrMessageSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p.messages

import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.serializers.{RawBitcoinSerializer, RawSerializerHelper}
import org.bitcoins.core.serializers.p2p._
import org.bitcoins.core.p2p._
import scodec.bits.ByteVector

import scala.annotation.tailrec


  private def parseNetworkIpAddresses(
      ipCount: CompactSizeUInt,
      bytes: ByteVector): (Seq[NetworkIpAddress], ByteVector) = {
    @tailrec
    def loop(
        remainingAddresses: BigInt,
        remainingBytes: ByteVector,
        accum: List[NetworkIpAddress]): (Seq[NetworkIpAddress], ByteVector) = {
      if (remainingAddresses <= 0) (accum.reverse, remainingBytes)
      else {
        val networkIpAddress =
          RawNetworkIpAddressSerializer.read(remainingBytes)
        val newRemainingBytes =
          remainingBytes.slice(networkIpAddress.byteSize, remainingBytes.size)
        loop(remainingAddresses - 1,
             newRemainingBytes,
             networkIpAddress :: accum)
      }
    }
    loop(ipCount.num.toInt, bytes, List())
  }
}

object RawAddrMessageSerializer extends RawAddrMessageSerializer 
Example 158
Source File: RawTransactionMessageSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p.messages

import org.bitcoins.core.protocol.transaction.Transaction
import org.bitcoins.core.serializers.RawBitcoinSerializer
import org.bitcoins.core.p2p.TransactionMessage
import scodec.bits.ByteVector


trait RawTransactionMessageSerializer
    extends RawBitcoinSerializer[TransactionMessage] {

  def read(bytes: ByteVector): TransactionMessage = {
    val transaction = Transaction(bytes)
    TransactionMessage(transaction)
  }

  def write(transactionMessage: TransactionMessage): ByteVector = {
    transactionMessage.transaction.bytes
  }
}

object RawTransactionMessageSerializer extends RawTransactionMessageSerializer 
Example 159
Source File: RawInventorySerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p.messages

import org.bitcoins.core.serializers.RawBitcoinSerializer
import org.bitcoins.core.p2p.TypeIdentifier
import org.bitcoins.core.p2p.Inventory
import org.bitcoins.crypto.DoubleSha256Digest
import scodec.bits.ByteVector


trait RawInventorySerializer extends RawBitcoinSerializer[Inventory] {

  override def read(bytes: ByteVector): Inventory = {
    val typeIdentifier = TypeIdentifier(bytes.take(4))
    val hash = DoubleSha256Digest(bytes.slice(4, bytes.size))
    Inventory(typeIdentifier, hash)
  }

  override def write(inventory: Inventory): ByteVector = {
    inventory.typeIdentifier.bytes ++ inventory.hash.bytes
  }
}

object RawInventorySerializer extends RawInventorySerializer 
Example 160
Source File: RawNetworkHeaderSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p.headers

import org.bitcoins.core.number.UInt32
import org.bitcoins.core.config._
import org.bitcoins.core.p2p.NetworkHeader
import org.bitcoins.core.serializers.RawBitcoinSerializer
import org.bitcoins.core.util.BitcoinSLogger
import scodec.bits.ByteVector


  def write(messageHeader: NetworkHeader): ByteVector = {
    val network = messageHeader.network
    val commandNameNoPadding = messageHeader.commandName.map(_.toByte)
    //command name needs to be 12 bytes in size, or 24 chars in hex
    val commandName = ByteVector(commandNameNoPadding).padRight(12)
    val checksum = messageHeader.checksum
    network.magicBytes ++
      commandName ++
      messageHeader.payloadSize.bytes.reverse ++
      checksum
  }

}

object RawNetworkHeaderSerializer extends RawNetworkHeaderSerializer 
Example 161
Source File: RawNetworkIpAddressSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.p2p

import java.net.InetAddress

import org.bitcoins.core.number.UInt32
import org.bitcoins.core.p2p._
import org.bitcoins.core.serializers.RawBitcoinSerializer
import org.bitcoins.core.util.BitcoinSLogger
import scodec.bits.ByteVector


trait RawNetworkIpAddressSerializer
    extends RawBitcoinSerializer[NetworkIpAddress]
    with BitcoinSLogger {

  def read(bytes: ByteVector): NetworkIpAddress = {
    val time = UInt32(bytes.take(4).reverse)
    val services = ServiceIdentifier(bytes.slice(4, 12))
    val ipBytes = bytes.slice(12, 28)
    val ipAddress = InetAddress.getByAddress(ipBytes.toArray)
    val port = bytes.slice(28, 30).toInt(signed = false)
    NetworkIpAddress(time, services, ipAddress, port)
  }

  def write(networkIpAddress: NetworkIpAddress): ByteVector = {
    val time = networkIpAddress.time.bytes.reverse
    val services = networkIpAddress.services.bytes
    val ipAddress = NetworkIpAddress.writeAddress(networkIpAddress.address)
    // uint16s are only 4 hex characters
    // cannot do fromShort,
    val port = ByteVector.fromInt(networkIpAddress.port, size = 2)
    time ++ services ++ ipAddress ++ port
  }

}

object RawNetworkIpAddressSerializer extends RawNetworkIpAddressSerializer 
Example 162
Source File: RawMerkleBlockSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.blockchain

import org.bitcoins.core.number.{UInt32, UInt64}
import org.bitcoins.core.protocol.CompactSizeUInt
import org.bitcoins.core.protocol.blockchain.MerkleBlock
import org.bitcoins.core.serializers.RawBitcoinSerializer
import org.bitcoins.core.util.BytesUtil
import org.bitcoins.crypto.DoubleSha256Digest
import scodec.bits.{BitVector, ByteVector}

import scala.annotation.tailrec


  private def parseTransactionHashes(
      bytes: ByteVector,
      hashCount: CompactSizeUInt): (Seq[DoubleSha256Digest], ByteVector) = {
    @tailrec
    def loop(
        remainingHashes: Long,
        remainingBytes: ByteVector,
        accum: List[DoubleSha256Digest]): (
        Seq[DoubleSha256Digest],
        ByteVector) = {
      if (remainingHashes <= 0) (accum.reverse, remainingBytes)
      else {
        val (hashBytes, newRemainingBytes) = remainingBytes.splitAt(32)
        loop(remainingHashes - 1,
             newRemainingBytes,
             DoubleSha256Digest(hashBytes) :: accum)
      }
    }
    loop(hashCount.num.toInt, bytes, Nil)
  }
}

object RawMerkleBlockSerializer extends RawMerkleBlockSerializer 
Example 163
Source File: RawBlockSerializer.scala    From bitcoin-s   with MIT License 5 votes vote down vote up
package org.bitcoins.core.serializers.blockchain

import org.bitcoins.core.protocol.blockchain.{Block, BlockHeader}
import org.bitcoins.core.protocol.transaction.Transaction
import org.bitcoins.core.serializers.{RawBitcoinSerializer, RawSerializerHelper}
import scodec.bits.ByteVector


  def write(block: Block): ByteVector = {
    val writtenHeader = block.blockHeader.bytes
    val txBytes = RawSerializerHelper.writeCmpctSizeUInt(block.transactions,
                                                         { tx: Transaction =>
                                                           tx.bytes
                                                         })
    writtenHeader ++ txBytes
  }

}

object RawBlockSerializer extends RawBlockSerializer 
Example 164
Source File: TopicConsumer.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal.replicator


import cats.Monad
import cats.data.{NonEmptyList => Nel}
import cats.implicits._
import com.evolutiongaming.kafka.journal.{ConsRecord, KafkaConsumer}
import com.evolutiongaming.skafka._
import com.evolutiongaming.skafka.consumer._
import com.evolutiongaming.sstream.Stream
import scodec.bits.ByteVector

import scala.concurrent.duration._


trait TopicConsumer[F[_]] {

  def subscribe(listener: RebalanceListener[F]): F[Unit]

  def poll: Stream[F, Map[Partition, Nel[ConsRecord]]]

  def commit: TopicCommit[F]
}

object TopicConsumer {

  def apply[F[_] : Monad](
    topic: Topic,
    pollTimeout: FiniteDuration,
    commit: TopicCommit[F],
    consumer: KafkaConsumer[F, String, ByteVector],
  ): TopicConsumer[F] = {

    val commit1 = commit

    new TopicConsumer[F] {

      def subscribe(listener: RebalanceListener[F]) = {
        consumer.subscribe(topic, listener.some)
      }

      val poll = {
        val records = for {
          records <- consumer.poll(pollTimeout)
        } yield for {
          (partition, records) <- records.values
        } yield {
          (partition.partition, records)
        }
        Stream.repeat(records)
      }

      def commit = commit1
    }
  }
} 
Example 165
Source File: Events.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal

import cats.data.{NonEmptyList => Nel}
import java.lang.{Byte => ByteJ}

import com.evolutiongaming.kafka.journal.util.ScodecHelper._
import scodec.bits.ByteVector
import scodec.{Codec, codecs}

import scala.util.Try

final case class Events[A](events: Nel[Event[A]], metadata: PayloadMetadata)

object Events {

  implicit def codecEvents[A](implicit
    eventCodec: Codec[Event[A]],
    metadataCodec: Codec[PayloadMetadata]
  ): Codec[Events[A]] = {
    val eventsCodec = nelCodec(codecs.listOfN(codecs.int32, codecs.variableSizeBytes(codecs.int32, eventCodec)))

    val default = (codecs.ignore(ByteJ.SIZE) ~> eventsCodec)
      .xmap[Events[A]](a => Events(a, PayloadMetadata.empty), _.events)

    val version0 = (codecs.constant(ByteVector.fromByte(0)) ~> eventsCodec)
      .xmap[Events[A]](a => Events(a, PayloadMetadata.empty), _.events)

    val version1 = (codecs.constant(ByteVector.fromByte(1)) ~> (eventsCodec :: metadataCodec))
      .as[Events[A]]

    codecs.choice(version1, version0, default)
  }

  implicit def eventsToBytes[F[_] : FromAttempt, A](implicit
    eventCodec: Codec[Event[A]],
    metadataCodec: Codec[PayloadMetadata]
  ): ToBytes[F, Events[A]] = ToBytes.fromEncoder

  implicit def eventsFromBytes[F[_] : FromAttempt, A](implicit
    eventCodec: Codec[Event[A]],
    metadataCodec: Codec[PayloadMetadata]
  ): FromBytes[F, Events[A]] = FromBytes.fromDecoder
} 
Example 166
Source File: ConsRecord.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal

import com.evolutiongaming.skafka.consumer.{ConsumerRecord, WithSize}
import com.evolutiongaming.skafka.{Header, Offset, TimestampAndType, TopicPartition}
import scodec.bits.ByteVector

object ConsRecord {

  def apply(
    topicPartition: TopicPartition,
    offset: Offset,
    timestampAndType: Option[TimestampAndType],
    key: Option[WithSize[String]] = None,
    value: Option[WithSize[ByteVector]] = None,
    headers: List[Header] = Nil
  ): ConsRecord = {

    ConsumerRecord(
      topicPartition = topicPartition,
      offset = offset,
      timestampAndType = timestampAndType,
      key = key,
      value = value,
      headers = headers)
  }
} 
Example 167
Source File: EventualPayloadAndType.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal.eventual

import cats.Applicative
import cats.implicits._
import com.evolutiongaming.kafka.journal.PayloadType
import com.evolutiongaming.kafka.journal.util.Fail
import com.evolutiongaming.kafka.journal.util.Fail.implicits._
import scodec.bits.ByteVector

final case class EventualPayloadAndType(
  payload: Either[String, ByteVector],
  payloadType: PayloadType
)

object EventualPayloadAndType {

  implicit class EventualPayloadAndTypeOps(val self: EventualPayloadAndType) extends AnyVal {

    def payloadStr[F[_] : Applicative : Fail]: F[String] = self.payload.fold(
      _.pure[F],
      _ => "String expected, but got bytes".fail
    )

    def payloadBytes[F[_] : Applicative : Fail]: F[ByteVector] = self.payload.fold(
      _ => "Bytes expected, but got string".fail,
      _.pure[F]
    )

  }
} 
Example 168
Source File: ScodecHelper.scala    From kafka-journal   with MIT License 5 votes vote down vote up
package com.evolutiongaming.kafka.journal.util

import cats.MonadError
import cats.data.{NonEmptyList => Nel}
import cats.implicits._
import com.evolutiongaming.kafka.journal.JsonCodec
import play.api.libs.json.Format
import scodec.bits.ByteVector
import scodec.{Attempt, Codec, Err, codecs}

import scala.annotation.tailrec
import scala.util.Try

object ScodecHelper {

  implicit val attemptMonadError: MonadError[Attempt, Attempt.Failure] = {

    import Attempt._

    new MonadError[Attempt, Failure] {

      def raiseError[A](a: Failure) = a

      def handleErrorWith[A](fa: Attempt[A])(f: Failure => Attempt[A]) = {
        fa match {
          case fa: Successful[A] => fa
          case fa: Failure       => f(fa)
        }
      }

      def pure[A](a: A) = Successful(a)

      def flatMap[A, B](fa: Attempt[A])(f: A => Attempt[B]) = fa.flatMap(f)

      @tailrec
      def tailRecM[A, B](a: A)(f: A => Attempt[Either[A, B]]): Attempt[B] = {
        f(a) match {
          case b: Failure                  => b
          case b: Successful[Either[A, B]] => b.value match {
            case Left(b1) => tailRecM(b1)(f)
            case Right(a) => Successful(a)
          }
        }
      }
    }
  }


  def nelCodec[A](codec: Codec[List[A]]): Codec[Nel[A]] = {
    val to = (a: List[A]) => {
      Attempt.fromOption(a.toNel, Err("list is empty"))
    }
    val from = (a: Nel[A]) => Attempt.successful(a.toList)
    codec.exmap(to, from)
  }


  def formatCodec[A](implicit format: Format[A], jsonCodec: JsonCodec[Try]): Codec[A] = {
    val fromBytes = (bytes: ByteVector) => {
      val jsValue = jsonCodec.decode.fromBytes(bytes)
      for {
        a <- Attempt.fromTry(jsValue)
        a <- format.reads(a).fold(a => Attempt.failure(Err(a.toString())), Attempt.successful)
      } yield a
    }
    val toBytes = (a: A) => {
      val jsValue = format.writes(a)
      val bytes = jsonCodec.encode.toBytes(jsValue)
      Attempt.fromTry(bytes)
    }
    codecs.bytes.exmap(fromBytes, toBytes)
  }
}