區(qū)塊鏈:第一部分:數(shù)字賬戶喳魏、簽名和驗(yàn)證

原文鏈接:https://www.ardanlabs.com/blog/2022/02/blockchain-01-digital-accounts-signatures-verification.html

介紹

這是探索 Ardan 區(qū)塊鏈項(xiàng)目的語義和實(shí)現(xiàn)細(xì)節(jié)的系列文章中的第一篇。該代碼是區(qū)塊鏈的參考實(shí)現(xiàn)崇决,并非是當(dāng)今使用的任何特定區(qū)塊鏈。雖然代碼是按照生產(chǎn)級編碼標(biāo)準(zhǔn)設(shè)計(jì)的互亮,但是我不會將這個項(xiàng)目用于學(xué)習(xí)之外的任何事情慢宗。

我使用以太坊項(xiàng)目作為參考坪蚁,并從該代碼中獲得靈感。我希望理解 Ardan 區(qū)塊鏈中的代碼能給你提供足夠的知識來幫助你理解以太坊的代碼镜沽。

本系列將通過 Ardan 區(qū)塊鏈項(xiàng)目提供的支持實(shí)現(xiàn)來探索區(qū)塊鏈的五個方面敏晤。

  • 帶有電子簽名和驗(yàn)證的數(shù)字賬戶
  • 計(jì)算機(jī)之間的事務(wù)分發(fā)/同步/通信
  • 賬目在不同計(jì)算機(jī)上冗余存儲
  • 不同計(jì)算機(jī)達(dá)成共識以處理和存儲新交易
  • 檢測過去交易的任何偽造

這篇文章將關(guān)注第一個方面,即 Ardan 區(qū)塊鏈如何為數(shù)字賬戶缅茉、簽名和驗(yàn)證提供支持嘴脾。

源代碼

Ardan 區(qū)塊鏈項(xiàng)目的源代碼可以在下面的鏈接中找到。

https://github.com/ardanlabs/blockchain

初始化

每個區(qū)塊鏈都有一個初始文件宾舅,提供區(qū)塊鏈的全局設(shè)置和初始狀態(tài)统阿。對于 Ardan 區(qū)塊鏈,我也創(chuàng)建了一個初始文件筹我。

** 片段1:初始文件**

{
    "date": "2021-12-17T00:00:00.000000000Z",
    "chain_id": "the-ardan-blockchain",
    "difficulty": 6,
    "transactions_per_block": 2,
    "mining_reward": 700,
    "gas_price": 15,
    "balance_sheet": {
        "0xF01813E4B85e178A83e29B8E7bF26BD830a25f32": 1000000,
        "0xdd6B972ffcc631a62CAE1BB9d80b7ff429c8ebA4": 1000000
    }
}

我找到了描述以太坊初始文件的[文檔]扶平,里面提供了很好的解釋。(https://gist.github.com/0mkara/b953cc2585b18ee098cd#create-custom-ethereum-network)

目前這些設(shè)置可能對你沒有多大意義蔬蕊,但稍后的帖子將詳細(xì)介紹這些細(xì)節(jié)〗岢危現(xiàn)在,請關(guān)注資產(chǎn)負(fù)債表下的原始賬戶(十六進(jìn)制地址)岸夯。我和 Pavel 都從一百萬單位的 ARD 開始麻献。

注意:以太坊定義了一個以太單位描述的面額公制系統(tǒng)。最小的單位稱為 a wei猜扮,它表示一個單位(如一便士)和ether勉吻,表示 10^18 個單位(如 1,000,000,000,000,000,000 個便士)。

帳戶和地址

再次注意一下初始文件中的原始帳戶旅赢。

片段 2:原始帳戶

"balance_sheet": {
    "0xF01813E4B85e178A83e29B8E7bF26BD830a25f32": 1000000,
    "0xdd6B972ffcc631a62CAE1BB9d80b7ff429c8ebA4": 1000000
}

我怎么知道片段 2 中哪些地址代表我和 Pavel 的帳戶齿桃?

只是看他們,我不知道煮盼。區(qū)塊鏈的一個特性是賬戶是匿名的短纵,它們只是大的十六進(jìn)制數(shù)字。最終僵控,你將用你的帳戶進(jìn)行交易香到,此時可以表名你是所有者。交易的達(dá)成或只是與他人的一般活動是因?yàn)槟銚碛羞@些資產(chǎn)。

這些地址是如何產(chǎn)生的悠就?

不同的區(qū)塊鏈?zhǔn)褂貌煌膶ぶ贩桨盖鳎ǔK鼈兪鞘褂脵E圓曲線數(shù)字簽名算法(ECDSA)生成的。該算法生成的私鑰/公鑰對只能用于簽名理卑,不能用于加密翘紊。ECDSA 是以太坊使用的算法。

在 Ardan 項(xiàng)目中藐唠,我在zblock/accounts文件夾下添加了幾個文件,其中包含一組基于Secp256k1曲線的私有 ECDSA 密鑰鹉究。

片段 3:帳戶文件夾

$ ls -l zblock/accounts
-rw-------  1 bill  staff    64B Feb  1 08:49 baba.ecdsa
-rw-------  1 bill  staff    64B Feb  1 08:49 cesar.ecdsa
-rw-------  1 bill  staff    64B Feb  1 08:49 kennedy.ecdsa
-rw-------  1 bill  staff    64B Feb  1 08:49 pavel.ecdsa

Ardan 項(xiàng)目使用這些文件來維護(hù)不同測試帳戶的私鑰宇立。你將在該文件夾中看到我和 Pavel 的文件。

片段 4:kennedy.ecdsa

9f332e3700d8fc2446eaf6d15034cf96e0c2745e40353deef032a5dbf1dfed93

片段4 顯示了我的私有 ECDSA 密鑰的十六進(jìn)制編碼版本自赔,它代表我在 Ardan 區(qū)塊鏈上的帳戶妈嘹。Ardan 數(shù)字錢包使用該密鑰代表我對 Ardan 區(qū)塊鏈執(zhí)行活動。你很快就會意識到數(shù)字錢包只不過是一個應(yīng)用程序绍妨,它可以使用私鑰作為你的帳戶身份對區(qū)塊鏈節(jié)點(diǎn)進(jìn)行網(wǎng)絡(luò)調(diào)用润脸。

注意:不同的區(qū)塊鏈?zhǔn)褂貌煌木W(wǎng)絡(luò)協(xié)議。例如他去,以太坊使用JSON-RPC毙驯。

以太坊項(xiàng)目有一個加密包,為使用 ECDSA 提供支持灾测。Ardan 項(xiàng)目使用這個包來管理數(shù)字簽名爆价。

片段5:生成私鑰

01 import "github.com/ethereum/go-ethereum/crypto"
02
03 privateKey, err := crypto.GenerateKey()
04 if err != nil {
05     return err
06 }
07
08 file := filepath.Join("zblock/accounts", "kennedy.ecdsa")
09 if err := crypto.SaveECDSA(file, privateKey); err != nil {
10     return err
11 }

片段 5 顯示了 Ardan 錢包如何在帳戶文件夾中為新用戶生成私鑰文件。

通常媳搪,私鑰是通過生成 12 或 24 個單詞的助記詞來生成的铭段。此助記詞代表你帳戶的私鑰,可用于離線存儲你的私鑰(紙質(zhì)錢包)或在你的機(jī)器壞了或如果你想從不同的機(jī)器(移動設(shè)備秦爆、新計(jì)算機(jī)等)使用你的帳戶時恢復(fù)你的帳戶序愚。

如果有人找到你的助記詞,那么他們就擁有你的私鑰等限,并且可以配置錢包應(yīng)用程序?qū)①Y金從你的帳戶中轉(zhuǎn)出爸吮。無論如何,永遠(yuǎn)不要與任何你不信任的人分享這個助記詞精刷。如果你需要共享助記詞拗胜,那么一種解決方案是使用諸如Shamir secrets之類的系統(tǒng)將助記詞分發(fā)給共享的對等組。像這樣的系統(tǒng)將允許在緊急情況下(你的意外死亡)恢復(fù)你的私鑰怒允,避免沒有人能控制你的帳戶埂软。

通過私鑰,你可以生成相應(yīng)的公鑰。公鑰代表您帳戶的身份

片段 6:地址專用

01 privateKey, err := crypto.LoadECDSA("kennedy.ecdsa")
02 if err != nil {
03     log.Fatal(err)
04 }
05
06 address := crypto.PubkeyToAddress(privateKey.PublicKey)
07 fmt.Println(address)

Output:
0xF01813E4B85e178A83e29B8E7bF26BD830a25f32

片段 6 展示了如何使用 Ethereumcrypto包從公鑰生成地址勘畔。此地址代表你的帳戶在區(qū)塊鏈上的身份所灸。如果有人知道這個地址,他們可以看到你擁有的東西以及你在區(qū)塊鏈上的所有交易(發(fā)送和接收)炫七。

例如爬立,我有一個帳戶,其地址是0x01D398ECb403BE33Cd6ED8c9Fefa1712Be48d8d8我在以太坊區(qū)塊鏈上使用的万哪。使用此地址侠驯,你可以查看我的所有交易。

圖 1:Etherscan

image.png

image.png

圖 1 顯示了我在以太坊上的帳戶的 etherscan你可以看到我是如何從我的 Coinbase 賬戶購買以太幣的奕巍,然后是我為在以太坊名稱服務(wù) ( ENS ) 上購買名稱而執(zhí)行的交易吟策。由于地址很容易輸入錯誤,因此創(chuàng)建 ENS 以充當(dāng)?shù)刂返?DNS 查找的止。

圖 2:wkennedy.eth

image.png

圖 2 顯示了我的 ENS 名稱wkennedy.eth解析為與我的帳戶關(guān)聯(lián)的地址檩坚。

交易類型

要向 Ardan 區(qū)塊鏈提交交易,需要發(fā)送特定信息诅福。

片段 5:用戶事務(wù)類型

01 type UserTx struct {
02     Nonce uint   `json:"nonce"`
03     To    string `json:"to"`
04     Value uint   `json:"value"`
05     Tip   uint   `json:"tip"`
06     Data  []byte `json:"data"`
07 }

此類型提供有關(guān)誰在獲得資金匾委、他們獲得多少以及與區(qū)塊鏈節(jié)點(diǎn)關(guān)聯(lián)的帳戶將收到多少小費(fèi)(獎金)以成功將此交易存儲在一個塊中的信息。該Data字段允許將任何額外信息與交易相關(guān)聯(lián)氓润。

請注意赂乐,此類型缺少一個字段來標(biāo)識正在提交交易的帳戶。這是因?yàn)樘峤唤灰椎馁~戶必須通過簽署交易來表明自己的身份旺芽。

片段 6:簽名交易類型

01 type SignedTx struct {
02     UserTx
03     V *big.Int `json:"v"`
04     R *big.Int `json:"r"`
05     S *big.Int `json:"s"`
06 }

該類型嵌入UserTx類型并添加三個字段沪猴,表示提交交易的賬戶的 ECDSA 簽名。向 Ardan 區(qū)塊鏈提交交易時需要提供這種類型的值采章。

簽署交易

錢包如何給UserTx簽名以便提交到區(qū)塊鏈运嗜?它首先將用戶事務(wù)散列成一個 32 字節(jié)的切片。

片段 7:散列

01 func (tx UserTx) HashWithArdanStamp() ([]byte, error) {
02     txData, err := json.Marshal(tx)
03     if err != nil {
04         return nil, err
05     }
06
07     txHash := crypto.Keccak256Hash(txData)
08     stamp := []byte("\x19Ardan Signed Message:\n32")
09     tran := crypto.Keccak256Hash(stamp, txHash.Bytes())
10
11     return tran.Bytes(), nil
12 }

該函數(shù)返回一個 32 字節(jié)的散列悯舟,代表用戶交易担租,其中嵌入了 Ardan 標(biāo)記到最終散列中。此最終哈希用于創(chuàng)建簽名抵怎、公鑰提取和簽名驗(yàn)證奋救。

在第 02 行,接收器值被編組為字節(jié)切片反惕,然后通過第 07 行的哈希函數(shù)運(yùn)行尝艘,以生成表示編組的事務(wù)數(shù)據(jù)的 32 字節(jié)數(shù)組。在第 08 行姿染,Ardan 標(biāo)記被轉(zhuǎn)換為字節(jié)切片背亥,因此它可以與第 09 行的交易數(shù)據(jù)的散列相結(jié)合,以生成用于表示交易的 32 個字節(jié)的最終散列。

Ardan 印章用于確保簽署交易時產(chǎn)生的簽名對于 Ardan 區(qū)塊鏈?zhǔn)冀K是唯一的狡汉。以太坊也使用相同的格式來做到這一點(diǎn)娄徊。

清單 8:區(qū)塊鏈印章

Ethereum Stamp Format
\x19Ethereum Signed Message:\n + length(message) + message

Ardan Stamp
"\x19Ardan Signed Message:\n32" + dataHash

注意:以太坊將此稱為簽名,而不是印章盾戴。我覺得這很令人困惑寄锐,因?yàn)檫@個字符串被用來對要簽名的散列交易數(shù)據(jù)加鹽將其視為印章對我來說不那么令人困惑。

通過將封送處理數(shù)據(jù)的散列長度強(qiáng)制為 32 字節(jié)尖啡,可以將長度硬編碼到標(biāo)記 ( \n32) 中以簡化操作橄仆。以太坊使用了這個技巧。

使用該HashWithArdanStamp方法可婶,現(xiàn)在可以簽署交易并準(zhǔn)備提交到區(qū)塊鏈沿癞。

片段 9:簽名

01 func (tx UserTx) Sign(privateKey *ecdsa.PrivateKey) (SignedTx, error) {
02
03     // Prepare the transaction for signing.
04     tran, err := tx.HashWithArdanStamp()
05     if err != nil {
06         return SignedTx{}, err
07     }
08
09     // Sign the hash with the private key to produce a signature.
10     sig, err := crypto.Sign(tran.Bytes(), privateKey)
11     if err != nil {
12         return SignedTx{}, err
13     }
14
15     // Convert the 65 byte signature into the [R|S|V] format.
16     v, r, s := toSignatureValues(sig)
17
18     // Construct the signed transaction.
19     signedTx := SignedTx{
20         UserTx: tx,
21         V:      v,
22         R:      r,
23         S:      s,
24     }
25
26     return signedTx, nil
27 }

返回的簽名是一個 65 字節(jié)的切片,使用 ECDSA 格式 [R | S | V]矛渴。前 32 個字節(jié)代表 R 值,接下來的 32 個字節(jié)代表 S 值惫搏,最后一個字節(jié)代表 V 值具温。

注意:如果您想了解有關(guān) R、S 和 V 值的更多信息筐赔,請閱讀這篇出色的文章铣猩。

以太坊將簽名作為 R、S 和 V 存儲在它們不同的交易類型中茴丰,我決定效仿达皿。

代碼 10:簽名字節(jié)到值

01 const ardanID = 29
02
03 func toSignatureValues(sig []byte) (r, s, v *big.Int) {
04    r = new(big.Int).SetBytes(sig[:32])
05    s = new(big.Int).SetBytes(sig[32:64])
06    v = new(big.Int).SetBytes([]byte{sig[64] + ardanID})
07
08    return r, s, v
09 }

以太坊和比特幣對簽名所做的事情是在 V 上添加一個任意數(shù)字。這樣做是為了清楚地表明簽名來自他們的區(qū)塊鏈贿肩。以太坊和比特幣使用的任意數(shù)字是 27峦椰。對于 Ardan 區(qū)塊鏈,我決定使用 29汰规。重要的是要注意汤功,在簽名可以用于任何加密操作之前,需要減去這個任意數(shù)字溜哮。

代碼 11:簽名值到字節(jié)

01 func toSignatureBytes(v, r, s *big.Int) []byte {
02    sig := make([]byte, crypto.SignatureLength)
03
04    copy(sig, r.Bytes())
05    copy(sig[32:], s.Bytes())
06    sig[64] = byte(v.Uint64() - ardanID)
07
08    return sig
09 }
10
11 func toSignatureBytesForDisplay(v, r, s *big.Int) []byte {
12     sig := make([]byte, crypto.SignatureLength)
13
14     copy(sig, r.Bytes())
15     copy(sig[32:], s.Bytes())
16     sig[64] = byte(v.Uint64())
17
18     return sig
19 }

toSignatureBytes函數(shù)從 V中刪除ardanID滔金,因此該值返回 0 或 1。該toSignatureBytesForDisplay函數(shù)保留V 中的ardanID并用于顯示茂嗓。

簽名到地址

現(xiàn)在您已經(jīng)知道如何簽署交易餐茵,接下來您需要了解區(qū)塊鏈節(jié)點(diǎn)如何使用簽名來提取公鑰來識別提交交易的賬戶地址。

代碼 12:地址

01 type BlockTx struct {
02     SignedTx
03     Gas uint `json:"gas"`
04 }
05
06 func (tx BlockTx) FromAddress() (string, error) {
07
08     // Prepare the transaction for public key extraction.
09     tran, err := tx.HashWithArdanStamp()
10     if err != nil {
11         return "", err
13     }
14
15     // Convert the [R|S|V] format into the original 65 bytes.
16     sig := toSignatureBytes(tx.V, tx.R, tx.S)
17
18     // Capture the public key associated with this signature.
19     publicKey, err := crypto.SigToPub(tran, sig)
20     if err != nil {
21         return "", err
22     }
23
24     // Extract the account address from the public key.
25     return crypto.PubkeyToAddress(*publicKey).String(), nil
26 }

該方法由區(qū)塊鏈節(jié)點(diǎn)執(zhí)行以檢索簽署交易的賬戶地址述吸。

在第 09 行忿族,該HashWithArdanStamp方法用于重新創(chuàng)建用于生成接收到的簽名的散列。該數(shù)據(jù)需要完全相同,否則區(qū)塊鏈節(jié)點(diǎn)將確定錯誤的公鑰肠阱。

現(xiàn)在有了公鑰票唆,可以在第 25 行使用crypto包中的PubkeyToAddress函數(shù)來提取提交并簽署交易的帳戶的地址。

驗(yàn)證簽名

最后一步是區(qū)塊鏈節(jié)點(diǎn)驗(yàn)證簽名的能力屹徘。

代碼 13:驗(yàn)證簽名

01 func (tx SignedTx) VerifySignature() error {
       . . . CHECKS ARE HERE . . .
36 }

執(zhí)行 3 次檢查以驗(yàn)證隨交易數(shù)據(jù)提供的簽名是否代表正確的帳戶走趋。

代碼 14:檢查恢復(fù) ID

03     // Check the recovery id is either 0 or 1.
04     v := tx.V.Uint64() - ardanID
05     if v != 0 && v != 1 {
06         return errors.New("invalid recovery id")
07     }

代碼 14 顯示了執(zhí)行的第一個檢查,確痹胍粒恢復(fù) id 設(shè)置為 ardan id簿煌。如果這個簽名不是由我們之前的Sign函數(shù)產(chǎn)生的,那么減去 ardan id 就不會產(chǎn)生 0 或 1 的值鉴吹。

代碼 15:檢查簽名值

09     // Check the signature values are valid.
10     if !crypto.ValidateSignatureValues(byte(v), tx.R, tx.S, false) {
11         return errors.New("invalid signature values")
12     }

代碼 15 顯示了第二個檢查姨伟,以驗(yàn)證整個簽名是否有效。這是通過crypto包中的ValidateSignatureValues功能完成的豆励。該函數(shù)接受帶有單獨(dú) R夺荒、S 和 V 值的簽名。該函數(shù)的最后一個參數(shù)是知道簽名是否是以太坊 Homestead 版本的一部分良蒸。Homestead 是以太坊平臺的第二個主要版本技扼,也是以太坊的第一個生產(chǎn)版本。

代碼 16:提取公鑰

14     // Prepare the transaction for recovery and validation.
15     tran, err := tx.HashWithArdanStamp()
16     if err != nil {
17         return err
18     }
19
20     // Convert the [R|S|V] format into the original 65 bytes.
21     sig := toSignatureBytes(tx.V, tx.R, tx.S)
22
23     // Capture the uncompressed public key associated with this signature.
24     sigPublicKey, err := crypto.Ecrecover(tran, sig)
25     if err != nil {
26         return fmt.Errorf("ecrecover, %w", err)
27     }

我正在使用crypto包中的Ecrecover函數(shù)嫩痰,因?yàn)槲倚枰獙⒐€作為 33 字節(jié)的未壓縮切片用于下一次調(diào)用剿吻。

代碼 17:檢查公鑰創(chuàng)建的數(shù)據(jù)簽名

29     // Check that the given public key created the signature over the data.
30     rs := sig[:crypto.RecoveryIDOffset]
31     if !crypto.VerifySignature(sigPublicKey, tran, rs) {
32         return errors.New("invalid signature")
33     }

代碼 17 顯示了要執(zhí)行的下一次調(diào)用和最后一次檢查。該函數(shù)需要未壓縮的 33 字節(jié)公鑰串纺、散列和標(biāo)記的交易數(shù)據(jù)丽旅,以及簽名中的 R 和 S 值。此驗(yàn)證對于確保正確的帳戶與交易相關(guān)聯(lián)至關(guān)重要纺棺。

當(dāng)區(qū)塊鏈節(jié)點(diǎn)接收到該SignedTx值時榄笙,它并不真正知道與該UserTx部分值關(guān)聯(lián)的字段是否與創(chuàng)建簽名時相同。如果不是五辽,則將生成不同的公鑰办斑,因此將使用不同的帳戶。從某人的帳戶中取出錢是多么完美的黑客行為杆逗。

UserTx重新散列值很重要∠绯幔現(xiàn)在,可以使用公鑰罪郊、重新散列UserTx的值以及簽名的 R 和 S 值來驗(yàn)證一切是否同步蠕蚜。如果VerifySignature函數(shù)沒有失敗,則可以確定該值中提供的簽名SignedTx是由該UserTx值生成的悔橄,因此公鑰確實(shí)代表了正確的帳戶靶累。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末腺毫,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子挣柬,更是在濱河造成了極大的恐慌潮酒,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件邪蛔,死亡現(xiàn)場離奇詭異急黎,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)侧到,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門勃教,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人匠抗,你說我怎么就攤上這事故源。” “怎么了汞贸?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵绳军,是天一觀的道長。 經(jīng)常有香客問我矢腻,道長删铃,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任踏堡,我火速辦了婚禮,結(jié)果婚禮上咒劲,老公的妹妹穿的比我還像新娘顷蟆。我一直安慰自己,他們只是感情好腐魂,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布帐偎。 她就那樣靜靜地躺著,像睡著了一般蛔屹。 火紅的嫁衣襯著肌膚如雪削樊。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天兔毒,我揣著相機(jī)與錄音漫贞,去河邊找鬼。 笑死育叁,一個胖子當(dāng)著我的面吹牛迅脐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播豪嗽,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼谴蔑,長吁一口氣:“原來是場噩夢啊……” “哼豌骏!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起隐锭,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤窃躲,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后钦睡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蒂窒,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年赎婚,在試婚紗的時候發(fā)現(xiàn)自己被綠了刘绣。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡挣输,死狀恐怖纬凤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情撩嚼,我是刑警寧澤停士,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站完丽,受9級特大地震影響恋技,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜逻族,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一蜻底、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧聘鳞,春花似錦薄辅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至搏嗡,卻和暖如春窿春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背采盒。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工旧乞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人纽甘。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓良蛮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親悍赢。 傳聞我的和親對象是個殘疾皇子决瞳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容