-
Notifications
You must be signed in to change notification settings - Fork 268
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
21 changed files
with
486 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
dependencies { | ||
compile project(':classpy-common') | ||
} |
47 changes: 47 additions & 0 deletions
47
classpy-bitcoin/src/main/java/com/github/zxh/classpy/bitcoin/Block.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package com.github.zxh.classpy.bitcoin; | ||
|
||
public class Block extends BlockComponent { | ||
|
||
{ | ||
uint32("Version"); | ||
hash ("HashPrevBlock"); | ||
hash ("HashMerkleRoot"); | ||
uint32("Time"); | ||
uint32("Bits"); | ||
uint32("Nonce"); | ||
table ("Transactions", Transaction::new); | ||
} | ||
|
||
// https://en.bitcoin.it/wiki/Transaction | ||
private class Transaction extends BlockComponent { | ||
|
||
{ | ||
uint32("Version"); | ||
table ("Txins", TxIn::new); | ||
table ("Txouts", TxOut::new); | ||
uint32("LockTime"); | ||
} | ||
|
||
} | ||
|
||
private static class TxIn extends BlockComponent { | ||
|
||
{ | ||
hash ("PreviousTransactionHash"); | ||
uint32("PreviousTxoutIndex"); | ||
script("TxinScript"); | ||
bytes ("SequenceNo", 4); | ||
} | ||
|
||
} | ||
|
||
private static class TxOut extends BlockComponent { | ||
|
||
{ | ||
uint64("value"); | ||
script("TxoutScript"); | ||
} | ||
|
||
} | ||
|
||
} |
61 changes: 61 additions & 0 deletions
61
classpy-bitcoin/src/main/java/com/github/zxh/classpy/bitcoin/BlockComponent.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package com.github.zxh.classpy.bitcoin; | ||
|
||
import com.github.zxh.classpy.bitcoin.types.*; | ||
import com.github.zxh.classpy.common.FileComponent; | ||
|
||
import java.util.function.Supplier; | ||
|
||
public class BlockComponent extends FileComponent { | ||
|
||
public final void read(BlockReader reader) { | ||
try { | ||
int offset = reader.getPosition(); | ||
readContent(reader); | ||
int length = reader.getPosition() - offset; | ||
super.setOffset(offset); | ||
super.setLength(length); | ||
} catch (Exception e) { | ||
System.out.println("error parsing: " + getClass()); | ||
throw e; | ||
} | ||
} | ||
|
||
protected void readContent(BlockReader reader) { | ||
for (FileComponent fc : getComponents()) { | ||
((BlockComponent) fc).read(reader); | ||
} | ||
} | ||
|
||
protected long readVarInt(BlockReader reader, String name) { | ||
VarInt varInt = new VarInt(); | ||
add(name, varInt); | ||
varInt.read(reader); | ||
return varInt.getValue(); | ||
} | ||
|
||
protected void uint32(String name) { | ||
add(name, new UInt32()); | ||
} | ||
|
||
protected void uint64(String name) { | ||
add(name, new UInt64()); | ||
} | ||
|
||
protected void hash(String name) { | ||
add(name, new Hash()); | ||
} | ||
|
||
protected void bytes(String name, int n) { | ||
add(name, new Bytes(n)); | ||
} | ||
|
||
protected void script(String name) { | ||
add(name, new Script()); | ||
} | ||
|
||
protected void table(String name, | ||
Supplier<? extends BlockComponent> supplier) { | ||
add(name, new Table(supplier)); | ||
} | ||
|
||
} |
18 changes: 18 additions & 0 deletions
18
classpy-bitcoin/src/main/java/com/github/zxh/classpy/bitcoin/BlockParser.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package com.github.zxh.classpy.bitcoin; | ||
|
||
import com.github.zxh.classpy.common.FileParser; | ||
|
||
public class BlockParser implements FileParser { | ||
|
||
@Override | ||
public Block parse(byte[] data) { | ||
Block block = new Block(); | ||
try { | ||
block.read(new BlockReader(data)); | ||
} catch (Exception e) { | ||
e.printStackTrace(System.err); | ||
} | ||
return block; | ||
} | ||
|
||
} |
27 changes: 27 additions & 0 deletions
27
classpy-bitcoin/src/main/java/com/github/zxh/classpy/bitcoin/BlockReader.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package com.github.zxh.classpy.bitcoin; | ||
|
||
import com.github.zxh.classpy.common.BytesReader; | ||
|
||
import java.nio.ByteOrder; | ||
|
||
// https://en.wikipedia.org/wiki/LEB128 | ||
public class BlockReader extends BytesReader { | ||
|
||
public BlockReader(byte[] data) { | ||
super(data, ByteOrder.LITTLE_ENDIAN); // ? | ||
} | ||
|
||
public long readVarInt() { | ||
int b = readByte() & 0xFF; | ||
if (b < 0xFD) { | ||
return b; | ||
} if (b == 0xFD) { | ||
return readUnsignedShort(); | ||
} if (b == 0xFE) { | ||
return readUnsignedInt(); | ||
} else { | ||
return readLong(); | ||
} | ||
} | ||
|
||
} |
24 changes: 24 additions & 0 deletions
24
classpy-bitcoin/src/main/java/com/github/zxh/classpy/bitcoin/types/Bytes.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package com.github.zxh.classpy.bitcoin.types; | ||
|
||
import com.github.zxh.classpy.bitcoin.BlockComponent; | ||
import com.github.zxh.classpy.bitcoin.BlockReader; | ||
|
||
public class Bytes extends BlockComponent { | ||
|
||
private final int n; | ||
private byte[] bytes; | ||
|
||
public Bytes(int n) { | ||
this.n = n; | ||
} | ||
|
||
public byte[] getBytes() { | ||
return bytes; | ||
} | ||
|
||
@Override | ||
protected void readContent(BlockReader reader) { | ||
bytes = reader.readBytes(n); | ||
} | ||
|
||
} |
19 changes: 19 additions & 0 deletions
19
classpy-bitcoin/src/main/java/com/github/zxh/classpy/bitcoin/types/Hash.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.github.zxh.classpy.bitcoin.types; | ||
|
||
import com.github.zxh.classpy.bitcoin.BlockComponent; | ||
import com.github.zxh.classpy.bitcoin.BlockReader; | ||
|
||
public class Hash extends BlockComponent { | ||
|
||
@Override | ||
protected void readContent(BlockReader reader) { | ||
byte[] bytes = reader.readBytes(32); | ||
|
||
StringBuilder sb = new StringBuilder(); | ||
for (int i = 31; i >= 0; i--) { | ||
sb.append(Integer.toHexString(bytes[i] & 0xFF)); | ||
} | ||
setDesc(sb.toString()); | ||
} | ||
|
||
} |
145 changes: 145 additions & 0 deletions
145
classpy-bitcoin/src/main/java/com/github/zxh/classpy/bitcoin/types/Script.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
package com.github.zxh.classpy.bitcoin.types; | ||
|
||
import com.github.zxh.classpy.bitcoin.BlockComponent; | ||
import com.github.zxh.classpy.bitcoin.BlockReader; | ||
import com.github.zxh.classpy.common.ParseException; | ||
|
||
// https://en.bitcoin.it/wiki/Script | ||
public class Script extends BlockComponent { | ||
|
||
@Override | ||
protected void readContent(BlockReader reader) { | ||
long n = readVarInt(reader, "Length"); | ||
|
||
Bytes bytes = new Bytes((int) n); | ||
bytes.read(reader); | ||
byte[] code = bytes.getBytes(); | ||
try { | ||
decodeScript(new BlockReader(code) { | ||
int basePos = reader.getPosition() - code.length; | ||
@Override | ||
public int getPosition() { | ||
return basePos + super.getPosition(); | ||
} | ||
}); | ||
} catch (Exception e) { | ||
e.printStackTrace(System.err); | ||
//add("Script", bytes); | ||
} | ||
} | ||
|
||
private void decodeScript(BlockReader reader) { | ||
while (reader.remaining() > 0) { | ||
Instr instr = new Instr(); | ||
add("Instr", instr); | ||
instr.read(reader); | ||
} | ||
} | ||
|
||
|
||
private static class Instr extends BlockComponent { | ||
|
||
@Override | ||
protected void readContent(BlockReader reader) { | ||
int opcode = reader.readByte() & 0xFF; | ||
if (opcode == 0) { | ||
setName("OP_0"); // OP_FALSE | ||
} else if (opcode <= 0x4B) { | ||
setName("OP_PUSH<" + opcode + ">"); | ||
reader.readBytes(opcode); | ||
} else if (opcode == 0x4C) { | ||
setName("OP_PUSHDATA1"); | ||
int n = reader.readUnsignedByte(); | ||
reader.readBytes(n); | ||
} else if (opcode == 0x4D) { | ||
setName("OP_PUSHDATA2"); | ||
int n = reader.readUnsignedShort(); | ||
reader.readBytes(n); | ||
} else if (opcode == 0x4E) { | ||
setName("OP_PUSHDATA4"); | ||
int n = (int) reader.readUnsignedInt(); | ||
reader.readBytes(n); | ||
} else { | ||
setOpcodeName(opcode); | ||
} | ||
} | ||
|
||
private void setOpcodeName(int opcode) { | ||
switch (opcode) { | ||
// 0x4F ~ 0x60 Constants | ||
case 0x4F: setName("OP_1NEGATE"); break; | ||
case 0x51: setName("OP_1"); break; // OP_TRUE | ||
case 0x52: setName("OP_2"); break; | ||
case 0x53: setName("OP_3"); break; | ||
case 0x54: setName("OP_4"); break; | ||
case 0x55: setName("OP_5"); break; | ||
case 0x56: setName("OP_6"); break; | ||
case 0x57: setName("OP_7"); break; | ||
case 0x58: setName("OP_8"); break; | ||
case 0x59: setName("OP_9"); break; | ||
case 0x5A: setName("OP_10"); break; | ||
case 0x5B: setName("OP_11"); break; | ||
case 0x5C: setName("OP_12"); break; | ||
case 0x5D: setName("OP_13"); break; | ||
case 0x5E: setName("OP_14"); break; | ||
case 0x5F: setName("OP_15"); break; | ||
case 0x60: setName("OP_16"); break; | ||
// 0x61 ~ 0x6A Flow control | ||
case 0x61: setName("OP_NOP"); break; | ||
case 0x63: setName("OP_IF"); break; | ||
case 0x64: setName("OP_NOTIF"); break; | ||
case 0x66: setName("OP_ELSE"); break; | ||
case 0x68: setName("OP_ENDIF"); break; | ||
case 0x69: setName("OP_VERIFY"); break; | ||
case 0x6A: setName("OP_RETURN"); break; | ||
// 0x6B ~ 0x7D Stack | ||
case 0x6b: setName("OP_TOALTSTACK"); break; | ||
case 0x6c: setName("OP_FROMALTSTACK"); break; | ||
case 0x73: setName("OP_IFDUP"); break; | ||
case 0x74: setName("OP_DEPTH"); break; | ||
case 0x75: setName("OP_DROP"); break; | ||
case 0x76: setName("OP_DUP"); break; | ||
case 0x77: setName("OP_NIP"); break; | ||
case 0x78: setName("OP_OVER"); break; | ||
case 0x79: setName("OP_PICK"); break; | ||
case 0x7a: setName("OP_ROLL"); break; | ||
case 0x7b: setName("OP_ROT"); break; | ||
case 0x7c: setName("OP_SWAP"); break; | ||
case 0x7d: setName("OP_TUCK"); break; | ||
case 0x6d: setName("OP_2DROP"); break; | ||
case 0x6e: setName("OP_2DUP"); break; | ||
case 0x6f: setName("OP_3DUP"); break; | ||
case 0x70: setName("OP_2OVER"); break; | ||
case 0x71: setName("OP_2ROT"); break; | ||
case 0x72: setName("OP_2SWAP"); break; | ||
// 0x7E ~ 0x82 Splice | ||
case 0x7E: setName("OP_CAT!"); break; | ||
case 0x7F: setName("OP_SUBSTR!"); break; | ||
case 0x80: setName("OP_LEFT!"); break; | ||
case 0x81: setName("OP_RIGHT!"); break; | ||
case 0x82: setName("OP_SIZE"); break; | ||
// 0x83 ~ 0x88 Bitwise logic | ||
case 0x83: setName("OP_INVERT!"); break; | ||
case 0x84: setName("OP_AND!"); break; | ||
case 0x85: setName("OP_OR!"); break; | ||
case 0x86: setName("OP_XOR!"); break; | ||
case 0x87: setName("OP_EQUAL"); break; | ||
case 0x88: setName("OP_EQUALVERIFY"); break; | ||
// 0xA6 ~ 0xAF Crypto | ||
case 0xA6: setName("OP_RIPEMD160"); break; | ||
case 0xA7: setName("OP_SHA1"); break; | ||
case 0xA8: setName("OP_SHA256"); break; | ||
case 0xA9: setName("OP_HASH160"); break; | ||
case 0xAA: setName("OP_HASH256"); break; | ||
case 0xAB: setName("OP_CODESEPARATOR"); break; | ||
case 0xAC: setName("OP_CHECKSIG"); break; | ||
case 0xAD: setName("OP_CHECKSIGVERIFY"); break; | ||
case 0xAE: setName("OP_CHECKMULTISIG"); break; | ||
case 0xAF: setName("OP_CHECKMULTISIGVERIFY"); break; | ||
default: throw new ParseException( | ||
String.format("Invalid opcode: 0x%02X", opcode)); | ||
} | ||
} | ||
} | ||
|
||
} |
29 changes: 29 additions & 0 deletions
29
classpy-bitcoin/src/main/java/com/github/zxh/classpy/bitcoin/types/Table.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package com.github.zxh.classpy.bitcoin.types; | ||
|
||
import com.github.zxh.classpy.bitcoin.BlockComponent; | ||
import com.github.zxh.classpy.bitcoin.BlockReader; | ||
|
||
import java.util.function.Supplier; | ||
|
||
public class Table extends BlockComponent { | ||
|
||
private Supplier<? extends BlockComponent> supplier; | ||
private String componentName; | ||
|
||
public Table(Supplier<? extends BlockComponent> supplier) { | ||
this.supplier = supplier; | ||
componentName = supplier.get().getClass().getSimpleName(); | ||
} | ||
|
||
@Override | ||
protected void readContent(BlockReader reader) { | ||
long count = readVarInt(reader, "Count"); | ||
for (long i = 0; i < count; i++) { | ||
BlockComponent element = supplier.get(); | ||
add(componentName + "#" + i, element); | ||
element.read(reader); | ||
} | ||
setDesc(Long.toString(count)); | ||
} | ||
|
||
} |
14 changes: 14 additions & 0 deletions
14
classpy-bitcoin/src/main/java/com/github/zxh/classpy/bitcoin/types/UInt32.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package com.github.zxh.classpy.bitcoin.types; | ||
|
||
import com.github.zxh.classpy.bitcoin.BlockComponent; | ||
import com.github.zxh.classpy.bitcoin.BlockReader; | ||
|
||
public class UInt32 extends BlockComponent { | ||
|
||
@Override | ||
protected void readContent(BlockReader reader) { | ||
long value = reader.readUnsignedInt(); | ||
setDesc(Long.toString(value)); | ||
} | ||
|
||
} |
Oops, something went wrong.