區塊由交易組成。區塊體中包含若干項交易數據。java
交易主要包含兩類數據:交易輸入和交易輸出。
- 交易輸入用來指明錢的來源
- 交易輸出用來指明錢的去向數組
除了交易輸入和交易輸出外,交易中還包含版本號和鎖定時間。交易數據的存儲結構以下:數據結構
交易對象中的各個字段含義以下:ide
字段 | 大小 | 描述 |
---|---|---|
version | 4個字節 | 明確該筆交易參考的版本規則 |
numInputs | 1-9個字節 | 交易中包含的輸入數量 |
inputs | 不定長 | 交易中包含的輸入數據 |
numOutputs | 1-9個字節 | 交易中包含的輸出數量 |
outputs | 不定長 | 交易中包含的輸出數據 |
lockTime | 4個字節 | 交易鎖定時間 |
注:若是鎖定時間爲0,表明當即執行,無需鎖定。若是該值小於5億,則表明區塊鏈到達該高度前,交易不會被執行,若是該值大於5億,則該值表明Unix紀元時間戳,交易在該時間以後執行。區塊鏈
// These are bitcoin serialized. private long version; //交易遵循的版本號 private ArrayList<TransactionInput> inputs; //交易的金錢來源 private ArrayList<TransactionOutput> outputs; //交易的金錢去向 private long lockTime; //交易的鎖定時間
//解析區塊原始字節數據,構造交易對象 @Override protected void parse() throws ProtocolException { cursor = offset; version = readUint32(); //讀取版本號 optimalEncodingMessageSize = 4; // First come the inputs. long numInputs = readVarInt(); //讀取輸入交易量 optimalEncodingMessageSize += VarInt.sizeOf(numInputs); inputs = new ArrayList<>((int) numInputs); //逐一解析輸入交易對象 for (long i = 0; i < numInputs; i++) { //構造輸入交易對象 TransactionInput input = new TransactionInput(params, this, payload, cursor, serializer); inputs.add(input); long scriptLen = readVarInt(TransactionOutPoint.MESSAGE_LENGTH); optimalEncodingMessageSize += TransactionOutPoint.MESSAGE_LENGTH + VarInt.sizeOf(scriptLen) + scriptLen + 4; cursor += scriptLen + 4; } // Now the outputs long numOutputs = readVarInt(); //讀取輸出交易量 optimalEncodingMessageSize += VarInt.sizeOf(numOutputs); outputs = new ArrayList<>((int) numOutputs); //逐一解析輸出交易對象 for (long i = 0; i < numOutputs; i++) { //構造輸出交易對象 TransactionOutput output = new TransactionOutput(params, this, payload, cursor, serializer); outputs.add(output); long scriptLen = readVarInt(8); optimalEncodingMessageSize += 8 + VarInt.sizeOf(scriptLen) + scriptLen; cursor += scriptLen; } lockTime = readUint32(); optimalEncodingMessageSize += 4; length = cursor - offset; }
交易輸入指明瞭交易的金錢來源。在比特幣系統中,交易的金錢來源,並不來自於某一特定帳戶,而來自於其餘人的輸出。
好比A和B分別轉給C一筆金錢,則當C向D支付時,須要用A和B的輸出做爲輸入。this
交易輸入中,存儲了其關聯的交易輸出指針,同時還存儲了該輸出的解鎖腳本。加密
交易輸入結構以下:idea
交易輸入中,各個字段的含義以下:spa
字段 | 大小 | 描述 |
---|---|---|
hash | 32個字節 | 關聯輸出所在的交易Hash地址 |
index | 4個字節 | 關聯輸出在其交易輸出集合中的索引 |
scriptLen | 1-9個字節 | 解鎖腳本長度 |
scriptBytes | 不定長 | 解鎖腳本數據 |
sequence | 4個字節 | 序列號,暫未使用 |
注:只有解鎖腳本正確,才能對輸出進行消費。解鎖腳本須要使用當前用戶的祕鑰進行簽名,所以只有當前用戶,能使用別人來的輸出。指針
// Allows for altering transactions after they were broadcast. Values below NO_SEQUENCE-1 mean it can be altered. private long sequence; // Data needed to connect to the output of the transaction we're gathering coins from. //關聯的交易輸出 private TransactionOutPoint outpoint; // The "script bytes" might not actually be a script. In coinbase transactions where new coins are minted there // is no input transaction, so instead the scriptBytes contains some extra stuff (like a rollover nonce) that we // don't care about much. The bytes are turned into a Script object (cached below) on demand via a getter. // 腳本字節數組可能並非實際的腳本,在創世區塊中,沒有輸入交易,該字段可能存儲其餘數據。正常狀況下,該數據會轉換成腳本對象 private byte[] scriptBytes;
//經過區塊的原始字節數據,構造輸入交易對象 @Override protected void parse() throws ProtocolException { //構造該輸入交易對應的輸出(接收地址) //解析數據時,會解析出對應輸出所在交易的Hash地址以及交易輸出對應的索引值 outpoint = new TransactionOutPoint(params, payload, cursor, this, serializer); cursor += outpoint.getMessageSize(); int scriptLen = (int) readVarInt(); //讀取腳本長度 length = cursor - offset + scriptLen + 4; scriptBytes = readBytes(scriptLen); //讀取解鎖腳本數據 sequence = readUint32(); //序列號,目前未使用 }
交易輸出指明瞭錢的去向,擁有該輸出,並用私鑰解密後,方可做爲其餘交易的輸入,進行消費。
交易輸出中,存儲了支付的金額以及鎖定腳本。交易輸出的存儲結構以下:
交易輸出中,各個字段含義以下:
字段 | 大小 | 描述 |
---|---|---|
value | 8個字節 | 支付金額(單位爲聰) |
scriptLen | 1-9個字節 | 鎖定腳本長度 |
scriptBytes | 1-9個字節 | 鎖定腳本數據 |
注:只有接收者,經過祕鑰加密生成解鎖腳本後,方可繼續使用該輸出做爲輸入,繼續消費。
// The output's value is kept as a native type in order to save class instances. //支付金額 private long value; // A transaction output has a script used for authenticating that the redeemer is allowed to spend // this output. //鎖定腳本 private byte[] scriptBytes;
//解析交易輸出數據,包含輸出金額和鎖定腳本(接收者能夠解鎖該腳本) @Override protected void parse() throws ProtocolException { value = readInt64(); //獲取交易輸出的金額 scriptLen = (int) readVarInt(); //鎖定腳本的長度 length = cursor - offset + scriptLen; scriptBytes = readBytes(scriptLen); //鎖定腳本的內容 }
上一篇:(二) 區塊鏈數據結構-區塊
下一篇:(四) 區塊鏈數據結構 – 腳本