implementing first parts of serializing a transaction to be signed by an ECKey

This commit is contained in:
Chris Stewart 2016-02-21 16:16:41 -06:00
parent bf813287d4
commit 0f9a87f971
2 changed files with 52 additions and 27 deletions

View File

@ -26,7 +26,7 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper {
* @param script
* @return
*/
def serializeScriptCode(script : Seq[ScriptToken]) : String = removeOpCodeSeparators(script)
def serializeScriptCode(script : Seq[ScriptToken]) : List[Byte] = removeOpCodeSeparators(script)
def serializeInput(input : TransactionInput, nType : Int, nVersion : Int) : String = ???
@ -56,11 +56,32 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper {
}
def serialize(inputIndex : Int, nType : Int, script : ScriptPubKey, hashType : HashType) : String = {
//remove signatures from all inputs because we cannot sign existing signatures
// Clear input scripts in preparation for signing. If we're signing a fresh
// transaction that step isn't very helpful, but it doesn't add much cost relative to the actual
// EC math so we'll do it anyway.
val txWithInputSigsRemoved = for {
input <- spendingTransaction.inputs
} yield input.factory(ScriptSignatureFactory.empty)
???
// This step has no purpose beyond being synchronized with Bitcoin Core's bugs. OP_CODESEPARATOR
// is a legacy holdover from a previous, broken design of executing scripts that shipped in Bitcoin 0.1.
// It was seriously flawed and would have let anyone take anyone elses money. Later versions switched to
// the design we use today where scripts are executed independently but share a stack. This left the
// OP_CODESEPARATOR instruction having no purpose as it was only meant to be used internally, not actually
// ever put into scripts. Deleting OP_CODESEPARATOR is a step that should never be required but if we don't
// do it, we could split off the main chain.
val scriptWithOpCodeSeparatorsRemoved : List[Byte] = serializeScriptCode(script.asm)
val inputToSign = spendingTransaction.inputs(inputIndex)
// Set the input to the script of its output. Bitcoin Core does this but the step has no obvious purpose as
// the signature covers the hash of the prevout transaction which obviously includes the output script
// already. Perhaps it felt safer to him in some way, or is another leftover from how the code was written.
val inputWithConnectedScript = inputToSign.factory(script)
//check the hash type of
}
/**
@ -68,12 +89,12 @@ trait TransactionSignatureSerializer extends RawBitcoinSerializerHelper {
* format
* @return
*/
def removeOpCodeSeparators(script : Seq[ScriptToken]) : String = {
def removeOpCodeSeparators(script : Seq[ScriptToken]) : List[Byte] = {
val scriptWithoutOpCodeSeparators : String = script.filterNot(_ == OP_CODESEPARATOR).map(_.hex).mkString
val scriptWithoutOpCodeSeparatorSize = addPrecedingZero((scriptWithoutOpCodeSeparators.size / 2).toHexString)
val expectedScript : ScriptPubKey = ScriptPubKeyFactory.factory(
scriptWithoutOpCodeSeparatorSize + scriptWithoutOpCodeSeparators)
expectedScript.hex
expectedScript.bytes
}
}

View File

@ -32,13 +32,13 @@ trait BinaryTree[+T] {
* @return
*/
def toSeqLeafValues : Seq[T] = {
//TODO: Optimize this into a tailrec function
def loop(tree : BinaryTree[T],accum : List[T]) : Seq[T] = tree match {
case Leaf(x) => x :: accum
case Empty => accum
case Node(_,l,r) => loop(l,List()) ++ loop(r,List())
@tailrec
def loop(tree : BinaryTree[T],accum : List[T], remainder : List[BinaryTree[T]]) : Seq[T] = tree match {
case Leaf(x) => if (remainder.isEmpty) x :: accum else loop(remainder.head, x :: accum, remainder.tail)
case Empty => if (remainder.isEmpty) accum else loop(remainder.head, accum, remainder.tail)
case Node(_,l,r) => loop(l,accum,r :: remainder)
}
loop(this,List())
loop(this,List(),List()).reverse
}
@ -80,7 +80,6 @@ trait BinaryTree[+T] {
* Inserts a element into one of the two branches in a binary tree
* if it cannot insert it because the branches are not empty
* it throws a runtime exception
* @param subTree
* @param tree
* @tparam T
* @return
@ -94,7 +93,7 @@ trait BinaryTree[+T] {
* if it cannot insert it because the branches are not empty
* it throws a runtime exception
* @param subTree
* @param tree
* @param parentTree
* @tparam T
* @return
*/
@ -105,43 +104,48 @@ trait BinaryTree[+T] {
else throw new RuntimeException("There was no empty branch to insert the new t: " + subTree + "inside of tree: " + parentTree)
case l : Leaf[T] => Node(l.v, subTree,Empty)
case Empty => subTree
}
/**
* Removes the subTree from the parentTree
* @param subTree - the tree to be removed
* @param parentTree - the tree of which the @subTree is being removed from
* @tparam T
* @return
*/
def remove[T](subTree : BinaryTree[T])(parentTree : BinaryTree[T] = this) : BinaryTree[T] = {
//TODO: Optimize into a tail recursive function
parentTree match {
case Empty => Empty
case l : Leaf[T] => if (l == subTree) Empty else l
case n : Node[T] => if (n == subTree) Empty
else Node[T](n.value.get,remove(subTree)(n.left.getOrElse(Empty)),
remove(subTree)(n.right.getOrElse(Empty)))
case n : Node[T] =>
if (n == subTree) Empty
else Node[T](n.v,remove(subTree)(n.l), remove(subTree)(n.r))
}
}
/**
* Replaces all instances of the original tree with the replacement tree
* @param originalTree - the tree that needs to be replaced
* @param replacement - the tree that is being put into the original tree
* @param replacementTree - the tree that is being put into the original tree
* @param parentTree - the tree that is being searched for instances to replace
* @tparam T
* @return
*/
def replace[T](originalTree : BinaryTree[T], replacement : BinaryTree[T])(implicit parentTree : BinaryTree[T] = this) : BinaryTree[T] = {
def replace[T](originalTree : BinaryTree[T], replacementTree : BinaryTree[T])(implicit parentTree : BinaryTree[T] = this) : BinaryTree[T] = {
//TODO: Optimize this into a tail recursive function
parentTree match {
case Empty => Empty
case l : Leaf[T] => if (l == originalTree) replacement else l
case n : Node[T] => if (n == originalTree) replacement else
case Empty => if (originalTree == Empty) replacementTree else Empty
case l : Leaf[T] => if (l == originalTree) replacementTree else l
case n : Node[T] => if (n == originalTree) replacementTree else
Node(n.v,
replace(originalTree,replacement)(n.l),
replace(originalTree,replacement)(n.r))
replace(originalTree,replacementTree)(n.l),
replace(originalTree,replacementTree)(n.r))
}
}
def toSeq : Seq[T] = {
//TODO: Optimize this into a tailrec function
//@tailrec