公鏈開發特點優缺點分析及前端實現

电报nft119發表於2024-03-13

本文正式介紹區塊鏈2.0時代,以太坊為代表的智慧合約時代。


以太坊(Ethereum)是一個支援智慧合約的區塊鏈平臺,它與Bitcoin最大的不同是,以太坊透過一個虛擬機器(EVM)可以執行智慧合約。以太坊是Vitalik Buterin(在2013年提出的概念,從2015年正式啟動並執行,基於PoW,目前每個區塊獎勵是2 Ether,約13~15秒左右出一個塊。


特點:


以太坊的賬戶模型就是餘額模型,不是UTXO。

以太坊支援智慧合約(圖蘭完備的指令碼語言solidity,執行在Ethereum Virtual Machine,以太坊虛擬機器上)

1 賬戶

以太坊賬戶分為外部賬戶和合約賬戶兩類:


外部賬戶:即普通使用者用私鑰控制的賬戶;

合約賬戶:一種擁有合約程式碼的賬戶,它不屬於任何人,也沒有私鑰與之對應。

本節僅討論外部賬戶。一個以太坊賬戶就是一個公鑰雜湊後得到的地址,同樣由一個私鑰推匯出對應的公鑰,然後再計算出地址。私鑰與公鑰演算法與比特幣完全相同,均為secp256k1橢圓曲線,但和比特幣不同的是,以太坊採用非壓縮公鑰,然後直接對公鑰做keccak256雜湊,得到32位元組的雜湊值,取後20位元組加上0x字首即為地址:



const

randomBytes = require('randombytes'),

ethUtil = require('ethereumjs-util');

// 生成256bit的隨機數作為私鑰:

let priKey = randomBytes(32).toString('hex');

// 計算公鑰(非壓縮格式):

let pubKey = ethUtil.privateToPublic(new Buffer(priKey, 'hex')).toString('hex');

// 計算地址:

let addr = ethUtil.pubToAddress(new Buffer(pubKey, 'hex')).toString('hex');

1

2

3

4

5

6

7

8

9

以太坊對私鑰和地址均採用十六進位制編碼,因此沒有校驗,如果某一位寫錯了,仍然是一個有效的私鑰或地址。keccak256雜湊演算法在以太坊中也被稱為SHA3演算法,但是要注意,keccak演算法原本是SHA3的候選演算法,然而在SHA3最後的標準化時,對 keccak 做了改進,因此,標準的SHA3演算法和keccak是不同的,只是以太坊在開發時就選擇了尚未成為SHA3標準的keccak演算法。後續我們在討論以太坊的雜湊演算法時,一律使用keccak256而不是SHA3-256。


帶校驗的地址

以太坊透過EIP-55實現了一個帶校驗的地址格式:對地址做一個keccak256雜湊,然後按位對齊,將雜湊值>=8的字母變成大寫:


以太坊地址就是依靠部分變成大寫的字母進行校驗,它的好處是帶校驗的地址和不帶校驗的地址對錢包軟體都是一樣的格式,缺點是有很小的機率無法校驗全部小寫的地址。

下面這個程式可以自動搜尋指定字首地址的私鑰:


const randomBytes = require('randombytes');

const ethUtil = require('ethereumjs-util');


let prefix = '0xAA';

if (/^0x[a-fA-F0-9]{1,2}$/.test(prefix)) {

let

max = parseInt(Math.pow(32, prefix.length-2)),

qPrefix = prefix.toLowerCase().substring(2),

prettyPriKey = null,

prettyAddress = null,

priKey, pubKey, addr, cAddr, i;


for (i=0; i<max; i++) {

priKey = randomBytes(32).toString('hex');

pubKey = ethUtil.privateToPublic(new Buffer(priKey, 'hex')).toString('hex');

addr = ethUtil.pubToAddress(new Buffer(pubKey, 'hex')).toString('hex');

if (addr.startsWith(qPrefix)) {

cAddr = ethUtil.toChecksumAddress('0x' + addr);

if(cAddr.startsWith(prefix)) {

prettyPriKey = priKey;

prettyAddress = cAddr;

break;

}

}

}


if (prettyPriKey === null) {

console.error('Not found.');

} else {

console.log('Private key: 0x' + prettyPriKey);

console.log('Address: ' + prettyAddress);

}

} else {

console.error('Invalid prefix.');

}


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

HD錢包

因為以太坊和比特幣的非對稱加密演算法是完全相同的,不同的僅僅是公鑰和地址的表示格式,因此,比特幣的HD錢包體系也完全適用於以太坊。使用者透過一套助記詞,既可以管理比特幣錢包,也可以管理以太坊錢包。


以太坊錢包的派生路徑是m/44’/60’/0’/0/0,用程式碼實現如下:


const

bitcoin = require('bitcoinjs-lib'),

bip39 = require('bip39'),

ethUtil = require('ethereumjs-util');


// 助記詞和口令:

let

words = 'bleak version runway tell hour unfold donkey defy digital abuse glide please omit much cement sea sweet tenant demise taste emerge inject cause link',

password = 'bitcoin';


// 計算seed:

let seedHex = bip39.mnemonicToSeedHex(words, password);

console.log('seed: ' + seedHex); // b59a8078...c9ebfaaa


// 生成root:

let root = bitcoin.HDNode.fromSeedHex(seedHex);

console.log('xprv: ' + root.toBase58()); // xprv9s21ZrQH...uLgyr9kF

console.log('xpub: ' + root.neutered().toBase58()); // xpub661MyMwA...oy32fcRG


// 生成派生key:

let child0 = root.derivePath("m/44'/60'/0'/0/0");

let prvKey = child0.keyPair.d.toString(16);

let pubKey = ethUtil.privateToPublic(new Buffer(prvKey, 'hex')).toString('hex');

let address = '0x' + ethUtil.pubToAddress(new Buffer(pubKey, 'hex')).toString('hex');

let checksumAddr = ethUtil.toChecksumAddress(address);


console.log(" prv m/44'/60'/0'/0/0: 0x" + prvKey); // 0x6c03e50ae20af44b9608109fc978bdc8f081e7b0aa3b9d0295297eb20d72c1c2

console.log(" pub m/44'/60'/0'/0/0: 0x" + pubKey); // 0xff10c2376a9ff0974b28d97bc70daa42cf85826ba83e985c91269e8c975f75f7d56b9f5071911fb106e48b2dbb2b30e0558faa2fc687a813113632c87c3b051c

console.log(" addr m/44'/60'/0'/0/0: " + address); // 0x9759be9e1f8994432820739d7217d889918f2f07

console.log("check-addr m/44'/60'/0'/0/0: " + checksumAddr); // 0x9759bE9e1f8994432820739D7217D889918f2f07


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

2 區塊結構

以太坊採用的是賬戶模型,如果小明的賬戶在某個區塊的資產是1 ETH,當小明給小紅轉賬0.2 ETH後,刨除手續費,他的賬戶還剩下約0.8 ETH。由於小明的賬戶地址不變,所以,以太坊的區塊結構必須能在每個區塊持續地跟蹤並記錄小明的賬戶餘額變動。

以太坊儲存賬戶資料的資料結構是MPT:Merkle Patricia Tree

當MPT的每個葉子結點的值確定後,計算出的Root Hash就是完全確定的。



每一個區塊透過Root Hash將完全確定所有賬戶的狀態,所以,從全域性看,以太坊就是一個狀態機,每個區塊透過記錄一個 stateRoot 來表示一個新狀態。如果給定某個區塊的 stateRoot,我們肯定能完全確定所有賬戶的所有餘額等資訊。因此,stateRoot 就被稱為當前的世界狀態。


如果第一個區塊只有幾個賬戶,隨著賬戶的增加,如果有數百萬個賬戶,到後面豈不是區塊儲存的資料量會越來越大?

實際上,每個區塊的stateRoot表示的是一個完全狀態的邏輯樹,但每個區塊記錄的資料只包括修改的部分,如果我們觀察第二個區塊的樹,它實際上只記錄修改的兩個賬戶,以及兩個賬戶因修改後導致的上層路徑的Hash發生的變化:


想要將一個有幾百萬節點的樹完整地放入記憶體需要消耗大量的記憶體,而以太坊全節點也並不會將整顆邏輯樹放入記憶體。實際上,每個節點的資料被存放到LevelDB中,節點僅在記憶體中儲存當前活動的一些賬戶資訊。如果需要操作某個不在記憶體的賬戶,則會將其從LevelDB載入到記憶體。如果記憶體不夠,也會將長期不活動的節點從記憶體中移除,因為將來可以透過節點的路徑再次從LevelDB載入。

————————————————


請明確標註出處

原文連結:https://blog.csdn.net/qq_33583069/article/details/122807100

版權宣告 :本文作者由 西安鏈酷科技 原創文章,著作權歸作者所有,轉載請告知作者並註明出處

來自 “ ITPUB部落格 ” ,連結:https://blog.itpub.net/70035240/viewspace-3008884/,如需轉載,請註明出處,否則將追究法律責任。

相關文章