Skip to content

Commit

Permalink
Constructing reorg w/ dbl-spend blkchain test
Browse files Browse the repository at this point in the history
  • Loading branch information
etotheipi committed Oct 11, 2011
1 parent 78bccfd commit 81cffdc
Show file tree
Hide file tree
Showing 5 changed files with 246 additions and 10 deletions.
15 changes: 14 additions & 1 deletion cppForSwig/BlockUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1217,6 +1217,7 @@ pair<bool,bool> BlockDataManager_FullRAM::addNewBlockData(BinaryData rawBlock,
// TODO: It might also be necessary to look at the specific
// block headers that were invalidated, to make sure
// we aren't using stale data somewhere that copied it
cout << "Done reassessing tx validity " << endl;
}

// Write this block to file if is on the main chain and we requested it
Expand Down Expand Up @@ -1277,18 +1278,28 @@ void BlockDataManager_FullRAM::reassessTxValidityOnReorg(
BlockHeaderRef* newTopPtr,
BlockHeaderRef* branchPtr)
{
PDEBUG("Reassessing Tx validity after (after reorg?)");
cout << "Reassessing Tx validity after (after reorg?)" << endl;
cout << " Old top block: " << endl;
oldTopPtr->pprint(cout, 2);
cout << " New top block: " << endl;
newTopPtr->pprint(cout, 2);
cout << " Branch point: " << endl;
branchPtr->pprint(cout, 2);
cout << endl << endl;

// Walk down invalidated chain first, until we get to the branch point
// Mark transactions as invalid
txJustInvalidated_.clear();
txJustAffected_.clear();
BlockHeaderRef* thisHeaderPtr = oldTopPtr;
cout << "Invalidating old-chain transactions..." << endl;
while(oldTopPtr != branchPtr)
{

for(uint32_t i=0; i<thisHeaderPtr->getTxRefPtrList().size(); i++)
{
TxRef * txptr = thisHeaderPtr->getTxRefPtrList()[i];
cout << " Tx: " << txptr->getThisHash().getSliceCopy(0,8).toHexStr() << endl;
txptr->setHeaderPtr(NULL);
txptr->setMainBranch(false);
txJustInvalidated_.insert(txptr->getThisHash());
Expand All @@ -1300,11 +1311,13 @@ void BlockDataManager_FullRAM::reassessTxValidityOnReorg(
// Walk down the newly-valid chain and mark transactions as valid. If
// a tx is in both chains, it will still be valid after this process
thisHeaderPtr = newTopPtr;
cout << "Marking new-chain transactions valid..." << endl;
while(newTopPtr != branchPtr)
{
for(uint32_t i=0; i<thisHeaderPtr->getTxRefPtrList().size(); i++)
{
TxRef * txptr = thisHeaderPtr->getTxRefPtrList()[i];
cout << " Tx: " << txptr->getThisHash().getSliceCopy(0,8).toHexStr() << endl;
txptr->setHeaderPtr(thisHeaderPtr);
txptr->setMainBranch(true);
txJustInvalidated_.erase(txptr->getThisHash());
Expand Down
4 changes: 2 additions & 2 deletions cppForSwig/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
COMPILER = g++
#COMPILER_OPTS = -c -g -Wall -D_DEBUG
COMPILER_OPTS = -c -march=native -O2 -pipe
COMPILER_OPTS = -c -g -Wall -D_DEBUG
#COMPILER_OPTS = -c -march=native -O2 -pipe


LINKER = g++
Expand Down
136 changes: 136 additions & 0 deletions createTestChain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#! /usr/bin/python
from pybtcengine import *


blkfile = open('/home/alan/.bitcoin/blk0001.dat','r')
blkfile.seek(8,0)
genBlock = PyBlockHeader().unserialize(blkfile.read(80))
numTx = blkfile.read(1)
genTx = PyTx().unserialize(blkfile.read(285))

print 'Genesis block header:'
genBlock.pprint()
print 'Genesis block tx:'
genTx.pprint()


################################################################################
def findDiff1Nonce(blkHeader):
for n in range(2**33):
h.nonce = n
theHash = hash256(h.serialize())
if theHash[-4:] == '\x00\x00\x00\x00':
return h
print 'No nonce found!'

################################################################################
# We will reference src TxOuts by the blkNum and TxIndex
# Src TxOut ~ {tx, txoutIndex, BtcAddr} / COINBASE = -1
# Dst TxOut ~ {BtcAddr, value}
def createTx(srcTxOuts, dstAddrVal):
tx = PyTx()
tx.numInputs = len(srcTxOuts)
tx.numOutputs = len(dstAddrs)
tx.inputs = []
tx.outputs = []

coinbaseTx = False
if tx.numInputs==1 and srcTxOuts[0] == -1:
coinbaseTx = True


####################
for i in range(tx.numOutputs):
txout = PyTxOut()
txout.value = dstAddrVal[i][1]
dstAddr160 = dstAddr[i][0].getAddr160()
if(coinbaseTx):
txout.binPKScript = ''.join(['\x41', \
dstAddr160,
opCodeLookup['OP_CHECKSIG']])
else:
txout.binPKScript = ''.join([opCodeLookup['OP_DUP'], \
opCodeLookup['OP_HASH160'], \
'\x14', \
dstAddr160,
opCodeLookup['OP_EQUALVERIFY'], \
opCodeLookup['OP_CHECKSIG']])
tx.outputs.append(txout)


####################
for i in range(tx.inputs):
txin = PyTxIn()
txin.outpoint = PyOutPoint()
if(coinbaseTx):
txin.outpoint.txOutHash = '\x00'*32
txin.outpoint.index = '\xff'*4
else:
txin.outpoint.txOutHash = hash256(srcTxOuts[0][0].serialize())
txin.outpoint.index = srcTxOuts[0][1]
txin.binScript = ''.join(['\xaa\xbb\xcc\xdd'])
txin.intSeq = 2**32-1
tx.inputs.append(txin)



####################
# Now we apply the ultra-complicated signature procedure
# We need a copy of the Tx with all the txin scripts blanked out
txCopySerialized = tx.serialize()
for i in range(tx.inputs):
if coinbaseTx:
pass # no sig on coinbase txs
else:
txCopy = PyTx().unserialize(txCopySerialized)
thisTxIn = txCopy.inputs[i]
txoutIdx = srcTxOuts[i][1]
prevTxOut = srcTxOuts[i][0].outputs[txoutIdx]
btcAddr = srcTxOuts[i][2]
hashCode = int_to_binary(hashtype, widthBytes=4)
binToSign = ''

# Copy the script of the TxOut we're spending, into the txIn script
thisTxIn.binScript = prevTxOut.binPKScript
binToSign = hash256(txCopy.serialize() + hashCode)
signature = addrPrivKey.generateDERSignature(binToSign) + '\x01'
if len(prevTxOut.binPKScript) > 26:
#Spend-CB: only Sig needed
tx.inputs[i].binScript = signature
else
tx.inputs[i].binScript = signature + '\x41' + addrPrivKey

return tx


txlist = []


AddrA = PyBtcAddress().createFromPublicKey(hex_to_binary('04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f'))
AddrB = PyBtcAddress().generateNew()
AddrC = PyBtcAddress().generateNew()
AddrD = PyBtcAddress().generateNew()

def btcValue(btc):
return btc*(10**8)

Blk0_Tx0 = createTx( [-1], [[AddrA, btcValue(50)]] )
Blk1_Tx0 = createTx( [-1], [[AddrB, btcValue(50)]] )
Blk2_Tx0 = createTx( [-1], [[AddrB, btcValue(50)]] )
Blk2_Tx1 = createTx( [[Blk1_Tx0, 0, AddrB]], [[ AddrC, btcValue(10)],
[ AddrB, btcValue(40)]] )
Blk3_Tx0 = createTx( [-1], [[AddrC, btcValue(50)]] )
Blk3_Tx1 = createTx( [[Blk2_Tx1, 1, AddrB]] [[AddrD, btcValue(40)]] )
Blk3_Tx2 = createTx( [[Blk2_Tx1, 0, AddrC]] [[AddrD, btcValue(10)]] )












99 changes: 92 additions & 7 deletions pybtcengine.py
Original file line number Diff line number Diff line change
Expand Up @@ -884,12 +884,9 @@ def createFromAddrStr(self, addrStr):

def calculateAddrStr(self, netbyte=ADDRBYTE):
assert( self.hasPubKey )
xBinBE = int_to_binary(self.pubKeyXInt, widthBytes=32, endOut=BIGENDIAN)
yBinBE = int_to_binary(self.pubKeyYInt, widthBytes=32, endOut=BIGENDIAN)
binPubKey = '\x04' + xBinBE + yBinBE
keyHash = hash160(binPubKey)
chkSum = hash256(netbyte + keyHash)[:4]
return binary_to_addrStr(netbyte + keyHash + chkSum)
keyHash = self.getAddr160()
chkSum = hash256(netbyte + keyHash)[:4]
return binary_to_addrStr(netbyte + keyHash + chkSum)

def getAddrStr(self):
if self.addrStr==UNINITIALIZED:
Expand Down Expand Up @@ -958,6 +955,11 @@ def checkPubPrivKeyPairMatch(self):
yMatches = privToPubPoint.y() == self.pubKeyYInt
return (xMatches and yMatches)

def getAddr160(self):
xBinBE = int_to_binary(self.pubKeyXInt, widthBytes=32, endOut=BIGENDIAN)
yBinBE = int_to_binary(self.pubKeyYInt, widthBytes=32, endOut=BIGENDIAN)
binPubKey = '\x04' + xBinBE + yBinBE
return hash160(binPubKey)

def addrStr_serialize(self):
# Address string has a maximum length of 34 bytes... so let's left-pad
Expand Down Expand Up @@ -1702,7 +1704,90 @@ def makeScriptBinary(binSig, binPubKey):
opnames[173] = 'OP_CHECKSIGVERIFY'
opnames[174] = 'OP_CHECKMULTISIG'
opnames[175] = 'OP_CHECKMULTISIGVERIFY'
# = words are used internally for assisting with transaction matching. They are invalid if used in actual scripts.


opCodeLookup = {}
opCodeLookup['OP_FALSE'] = 0
opCodeLookup['OP_PUSHDATA1'] = 76
opCodeLookup['OP_PUSHDATA2'] = 77
opCodeLookup['OP_PUSHDATA4'] = 78
opCodeLookup['OP_1NEGATE'] = 79
opCodeLookup['OP_1'] = 81
opCodeLookup['OP_TRUE'] = 81
opCodeLookup['OP_NOP'] = 97
opCodeLookup['OP_IF'] = 99
opCodeLookup['OP_NOTIF'] = 100
opCodeLookup['OP_ELSE'] = 103
opCodeLookup['OP_ENDIF'] = 104
opCodeLookup['OP_VERIFY'] = 105
opCodeLookup['OP_RETURN'] = 106
opCodeLookup['OP_TOALTSTACK'] = 107
opCodeLookup['OP_FROMALTSTACK'] = 108
opCodeLookup['OP_IFDUP'] = 115
opCodeLookup['OP_DEPTH'] = 116
opCodeLookup['OP_DROP'] = 117
opCodeLookup['OP_DUP'] = 118
opCodeLookup['OP_NIP'] = 119
opCodeLookup['OP_OVER'] = 120
opCodeLookup['OP_PICK'] = 121
opCodeLookup['OP_ROLL'] = 122
opCodeLookup['OP_ROT'] = 123
opCodeLookup['OP_SWAP'] = 124
opCodeLookup['OP_TUCK'] = 125
opCodeLookup['OP_2DROP'] = 109
opCodeLookup['OP_2DUP'] = 110
opCodeLookup['OP_3DUP'] = 111
opCodeLookup['OP_2OVER'] = 112
opCodeLookup['OP_2ROT'] = 113
opCodeLookup['OP_2SWAP'] = 114
opCodeLookup['OP_CAT'] = 126
opCodeLookup['OP_SUBSTR'] = 127
opCodeLookup['OP_LEFT'] = 128
opCodeLookup['OP_RIGHT'] = 129
opCodeLookup['OP_SIZE'] = 130
opCodeLookup['OP_INVERT'] = 131
opCodeLookup['OP_AND'] = 132
opCodeLookup['OP_OR'] = 133
opCodeLookup['OP_XOR'] = 134
opCodeLookup['OP_EQUAL'] = 135
opCodeLookup['OP_EQUALVERIFY'] = 136
opCodeLookup['OP_1ADD'] = 139
opCodeLookup['OP_1SUB'] = 140
opCodeLookup['OP_2MUL'] = 141
opCodeLookup['OP_2DIV'] = 142
opCodeLookup['OP_NEGATE'] = 143
opCodeLookup['OP_ABS'] = 144
opCodeLookup['OP_NOT'] = 145
opCodeLookup['OP_0NOTEQUAL'] = 146
opCodeLookup['OP_ADD'] = 147
opCodeLookup['OP_SUB'] = 148
opCodeLookup['OP_MUL'] = 149
opCodeLookup['OP_DIV'] = 150
opCodeLookup['OP_MOD'] = 151
opCodeLookup['OP_LSHIFT'] = 152
opCodeLookup['OP_RSHIFT'] = 153
opCodeLookup['OP_BOOLAND'] = 154
opCodeLookup['OP_BOOLOR'] = 155
opCodeLookup['OP_NUMEQUAL'] = 156
opCodeLookup['OP_NUMEQUALVERIFY'] = 157
opCodeLookup['OP_NUMNOTEQUAL'] = 158
opCodeLookup['OP_LESSTHAN'] = 159
opCodeLookup['OP_GREATERTHAN'] = 160
opCodeLookup['OP_LESSTHANOREQUAL'] = 161
opCodeLookup['OP_GREATERTHANOREQUAL'] = 162
opCodeLookup['OP_MIN'] = 163
opCodeLookup['OP_MAX'] = 164
opCodeLookup['OP_WITHIN'] = 165
opCodeLookup['OP_RIPEMD160'] = 166
opCodeLookup['OP_SHA1'] = 167
opCodeLookup['OP_SHA256'] = 168
opCodeLookup['OP_HASH160'] = 169
opCodeLookup['OP_HASH256'] = 170
opCodeLookup['OP_CODESEPARATOR'] = 171
opCodeLookup['OP_CHECKSIG'] = 172
opCodeLookup['OP_CHECKSIGVERIFY'] = 173
opCodeLookup['OP_CHECKMULTISIG'] = 174
opCodeLookup['OP_CHECKMULTISIGVERIFY'] = 175
#Word Opcode Description
#OP_PUBKEYHASH = 253 Represents a public key hashed with OP_HASH160.
#OP_PUBKEY = 254 Represents a public key compatible with OP_CHECKSIG.
Expand Down
2 changes: 2 additions & 0 deletions pyqt/pbemodels.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,8 @@ def data(self, index, role=Qt.DisplayRole):
elif role==Qt.TextAlignmentRole:
if col in (TXOUT_STYPE,):
return QVariant(int(Qt.AlignHCenter | Qt.AlignVCenter))
elif col in (TXOUT_BTC,):
return QVariant(int(Qt.AlignRight | Qt.AlignVCenter))
else:
return QVariant(int(Qt.AlignLeft | Qt.AlignVCenter))
elif role==Qt.BackgroundColorRole:
Expand Down

0 comments on commit 81cffdc

Please sign in to comment.