Go ブロックチェーンのブロックとトランザクションをどのように設計したか

最終的に単なるデータベースではなくブロックチェーンを完成させるには、プロジェクトに 3 つの重要な要素を追加する必要があります。

  • ブロックのデータ構造とメソッドの説明
  • データ構造とトランザクションメソッドの説明
  • データベースにブロックを保存し、ハッシュまたは高さ (またはその他) によってブロックを検索するブロックチェーン機能。

Go ブロックチェーンのブロックとトランザクションをどのように設計したか

これは産業向けブロックチェーンに関する XNUMX 回目の記事です。 ここで.

このシリーズの前回の記事に関して読者から寄せられた質問を思い出してください。この場合、ブロックチェーン データを保存するために LevelDB データベースが使用されていますが、他のデータベース、たとえば MySQL の使用を妨げるものはありません。 次に、このデータの構造を見てみましょう。

トランザクションから始めましょう: github.com/Rusldv/bcstartup/blob/master/transaction/builder.go

そのデータ構造は次のとおりです。

type TX struct {
	DataType byte		
	TxHash string 
	TxType byte	
	Timestamp int64		
	INs []TxIn
	OUTs []TxOut
}

type TxIn struct {
	ThatTxHash string
	TxOutN int
	ByteCode string
}

type TxOut struct {
	Value int
	ByteCode string
}

TX は、データ タイプ (トランザクション 2 の場合)、そのトランザクションのハッシュ、トランザクション自体のタイプ、タイムスタンプ、および入力と出力を保存します。 TxIn 入力には、出力が参照されるトランザクションのハッシュ、この出力の番号とバイトコードが格納され、TxOut 出力には値とバイトコードも格納されます。

次に、トランザクションがそのデータに対してどのようなアクションを実行できるかを見てみましょう。 方法を見てみましょう。

トランザクションを作成するには、transaction.NewTransaction(txtype byte) *TX 関数を使用します。

AddTxIn(thattxhash []byte, txoutn int, code []byte) (*TxIn, error) メソッドは、トランザクションに入力を追加します。

AddTxOut(value int, data []byte) (*TxOut, error) メソッドは、トランザクションに出力を追加します。

ToBytes() []byte メソッドは、トランザクションをバイト スライスに変換します。

内部関数 preByteHash(bytes []byte) string は、生成されたトランザクション ハッシュを JavaScript アプリケーションから生成されたトランザクション ハッシュと互換性を持たせるために、Build() および Check() で使用されます。

Build() メソッドは、トランザクション ハッシュを次のように設定します: tx.TxHash = preByteHash(tx.ToBytes())。

ToJSON() 文字列メソッドは、トランザクションを JSON 文字列に変換します。

FromJSON(data []byte) エラー メソッドは、バイト スライスとして渡された JSON 形式からトランザクションを読み込みます。

Check() bool メソッドは、トランザクション ハッシュ フィールドから得られたハッシュと、このトランザクションのハッシュ (ハッシュ フィールドを無視した) の結果として取得されたハッシュを比較します。

トランザクションがブロックに追加されます。 github.com/Rusldv/bcstartup/blob/master/block/builder.go

ブロック データ構造はさらに大容量になります。

type Block struct {
	DataType byte				
	BlockHeight int					
        Timestamp int64				 
        HeaderSize int					
        PrevBlockHash string				 
        SelfBlockHash string			
	TxsHash string			
	MerkleRoot string
	CreatorPublicKey string			
	CreatorSig string
	Version int
	TxsN int
	Txs []transaction.TX
}

DataType はデータ型を格納し、ノードはそれを使用して、ブロックをトランザクションまたは他のデータから区別します。 ブロックの場合、この値は 1 です。

BlockHeight にはブロックの高さが格納されます。
タイムスタンプ タイムスタンプ。
HeaderSize はブロック サイズ (バイト単位) です。
PrevBlockHash は前のブロックのハッシュであり、SelfBlockHash は現在のブロックのハッシュです。
TxsHash はトランザクションの一般的なハッシュです。
MerkleRoot はマークル ツリーのルートです。

さらにフィールドには、ブロックの作成者の公開キー、作成者の署名、ブロックのバージョン、ブロック内のトランザクションの数、およびこれらのトランザクション自体があります。

そのメソッドを見てみましょう。
ブロックを作成するには、block.NewBlock() 関数を使用します。 NewBlock(prevBlockHash string, height int) *Block。これは、前のブロックのハッシュと、ブロックチェーン内で作成されたブロックに設定された高さを取得します。 ブロック タイプも、types パッケージ定数から設定されます。

b.DataType = types.BLOCK_TYPE.

AddTx(tx *transaction.TX) メソッドは、ブロックにトランザクションを追加します。

Build() メソッドは、ブロックのフィールドに値をロードし、現在のハッシュを生成して設定します。

ToBytesHeader() []byte メソッドは、ブロック ヘッダー (トランザクションなし) をバイト スライスに変換します。

ToJSON() 文字列メソッドは、ブロックをデータの文字列表現の JSON 形式に変換します。

FromJSON(data []byte) エラー メソッドは、JSON からブロック構造にデータを読み込みます。

Check() bool メソッドはブロック ハッシュを生成し、それをブロック ハッシュ フィールドで指定されたものと比較します。

GetTxsHash() 文字列メソッドは、ブロック内のすべてのトランザクションの合計ハッシュを返します。

GetMerkleRoot() メソッドは、ブロック内のトランザクションのマークル ツリーのルートを指定します。

Sign(privk string) メソッドは、ブロック作成者の秘密キーを使用してブロックに署名します。

SetHeight(height int) メソッドは、ブロックの高さをブロック構造フィールドに書き込みます。

GetHeight() int メソッドは、ブロック構造の対応するフィールドで指定されたブロックの高さを返します。

ToGOBBytes() []byte メソッドは、ブロックを GOB 形式でエンコードし、バイト スライスとして返します。

FromGOBBytes(data []byte) エラー メソッドは、渡されたバイト スライスからブロック データを GOB 形式でブロック構造に書き込みます。

GetHash() 文字列メソッドは、指定されたブロックのハッシュを返します。

GetPrevHash() 文字列メソッドは、前のブロックのハッシュを返します。

SetPublicKey(pubk string) メソッドは、ブロック作成者の公開キーをブロックに書き込みます。

したがって、Block オブジェクトのメソッドを使用すると、ネットワーク経由で送信したり、LevelDB データベースに保存したりできる形式に簡単に変換できます。

ブロックチェーン パッケージの関数は、ブロックチェーンへの保存を担当します。 github.com/Rusldv/bcstartup/tree/master/blockchain

これを行うには、ブロックは IBlock インターフェイスを実装する必要があります。

type IGOBBytes interface {
	ToGOBBytes() []byte
	FromGOBBytes(data []byte) error
}

type IBlock interface {
	IGOBBytes
	GetHash() string
	GetPrevHash() string
	GetHeight() int
	Check() bool

}

データベース接続は、パッケージが init() 関数で初期化されるときに一度作成されます。

db, err = leveldb.OpenFile(BLOCKCHAIN_DB_DEBUG, nil).

CloseDB() は db.Cloce() のラッパーであり、パッケージ関数を操作してデータベースへの接続を閉じた後に呼び出されます。

SetTargetBlockHash(ハッシュ文字列) エラー関数は、BLOCK_HASH 定数で指定されたキーを持つ現在のブロックのハッシュをデータベースに書き込みます。

GetTargetBlockHash() (文字列、エラー) 関数は、データベースに保存されている現在のブロックのハッシュを返します。

SetTargetBlockHeight(height int) エラー関数は、BLOCK_HEIGHT 定数で指定されたキーを持つノードのブロックチェーンの高さの値をデータベースに書き込みます。

GetTargetBlockHeight() (int, error) 関数は、データベースに保存されている特定のノードのブロックチェーンの高さを返します。

CheckBlock(block IBlock) ブール関数は、ブロックをブロックチェーンに追加する前に、ブロックが正しいかどうかをチェックします。

AddBlock(block IBlock) エラー関数は、ブロックをブロックチェーンに追加します。

ブロックを取得および表示するための関数は、ブロックチェーン パッケージのexplore.go ファイルにあります。

GetBlockByHash(ハッシュ文字列) (*block.Block, error) 関数は、空のブロック オブジェクトを作成し、ハッシュが渡されたデータベースからブロックをロードし、そのブロックへのポインタを返します。

Genesis ブロックの作成は、ブロックチェーン パッケージの Genesis.go ファイルの Genesis() エラー関数によって実行されます。

次の記事では、WebSocket メカニズムを使用してクライアントをノードに接続する方法について説明します。

出所: habr.com

コメントを追加します