基于區(qū)塊鏈的Dapp, 在以太坊上實現(xiàn)登錄注冊

“我總偏向?qū)?quán)利分散于網(wǎng)絡(luò)。這樣一來葡缰,就沒任何組織能輕松獲取控制淆衷。我不相信巨大的中央組織缸榄,天性使然∽U”——Bob Tayor, ARPANET締造者

今年年初的“三點鐘區(qū)塊鏈群”徹底激起了以加密數(shù)字貨幣的主的區(qū)塊鏈浪潮甚带,資本的驅(qū)動加深了人們對區(qū)塊鏈技術(shù)的狂熱。然而佳头,作為區(qū)塊鏈3.0的時代的更廣的應(yīng)用來臨鹰贵,技術(shù)如何落地也是在初期需要解決的第一道坎。

所以今天就來試一下如何在以太坊上建立智能合約應(yīng)用(Dapp)畜晰,開發(fā)一個普通應(yīng)用的該有的登錄注冊砾莱,以便我們第一時間嘗鮮瑞筐。

為什么要使用區(qū)塊鏈凄鼻?

作為一名標準的web開發(fā)人員,在開始一門新技術(shù)之前聚假,需要仔細考慮一個問題就是:基于現(xiàn)有的業(yè)務(wù)如果用上區(qū)塊鏈會更好嗎块蚌?

回答這個問題之前,你需要了解區(qū)塊鏈是什么膘格?優(yōu)勢是什么峭范?這個問題就不在這里展開了,這是個相當大的話題瘪贱,不清楚的同學可以移步到這里參考一下纱控。《區(qū)塊鏈-百度百科》辆毡、《區(qū)塊鏈技術(shù)是什么?未來可能用于哪些方面甜害?》

那么區(qū)塊鏈本質(zhì)上就是一個去中心化的數(shù)據(jù)庫舶掖,只不過這個數(shù)據(jù)庫沒有中心服務(wù)器、數(shù)據(jù)無法篡改同時一定程度上能夠很好的保護數(shù)據(jù)隱私尔店。對如今的互聯(lián)網(wǎng)來說眨攘,聽起來很具有革命性的技術(shù)。所以如果對于一款涉及到數(shù)據(jù)私密性嚣州、永久性安全性高的應(yīng)用鲫售,這個確實是非常適合的。

現(xiàn)在在金融该肴、醫(yī)療情竹、溯源、社交等等領(lǐng)域匀哄,很多公司逐漸開始試水更廣泛的應(yīng)用鲤妥。而只靠發(fā)幣炒幣,這畢竟是種投機取巧的行為拱雏。

以太坊入門必備基礎(chǔ)

接下來將會從零開始搭建基于以太坊web3js項目棉安,開始閱讀之前,你需要熟練前端或后臺JavaScript語法铸抑,熟悉區(qū)塊鏈思想和原理贡耽,如果能了解solidity語法更好,因為接下來我們會用到它鹊汛,和js很像的一門語言蒲赂。

為了能夠方便大家能夠快速的了解,提供了下面幾個資料供參考:

  1. 《ethereum官網(wǎng)》以太坊官網(wǎng)刁憋。
  2. 《sails官方文檔》一款后臺的nodejs框架滥嘴。
  3. 《 we3.js 文檔1.0版本》以太坊上的前端框架,可實現(xiàn)與合約交互至耻。
  4. 《solidity 文檔》以太坊的智能合約語言若皱,熟悉常用語法,和JavaScript語法類似尘颓。

了解上面的知識之后走触,就可以開始DAPP搭建之旅了,將從下面的路線講解:

  1. 搭建以太坊環(huán)境疤苹。
  2. 創(chuàng)建創(chuàng)世區(qū)塊互广。
  3. 簡單的挖礦、創(chuàng)建賬戶。
  4. 利用以太坊錢包查詢賬戶信息惫皱。
  5. 編寫智能合約像樊。
  6. web3.js與合約交互。
  7. 登錄注冊業(yè)務(wù)邏輯實現(xiàn)旅敷。
  8. postman接口測試

項目代碼可點擊查看https://github.com/Elliottssu/web3js-api

一凶硅、以太坊環(huán)境搭建

如果已經(jīng)有以太坊環(huán)境的同學可以跳過,接下來以mac系統(tǒng)為例介紹扫皱,windows也差不多足绅。

通過Homebrew來安裝go-ethereum

brew tap ethereum/ethereum

可以添加--devel以下命令來安裝開發(fā)分支(建議用這個):

brew install ethereum --devel

執(zhí)行geth version查看版本號,如果正常的話即安裝成功韩脑。

二氢妈、新建創(chuàng)世區(qū)塊

在比特幣系統(tǒng)里,這個創(chuàng)世塊是被寫入源碼段多,但對于以太坊而言首量,創(chuàng)世塊可以是任何你喜歡的東西。你也可以把這個當成是系統(tǒng)的一個漏洞进苍。但是共識算法確保其它人除非納入你的創(chuàng)世塊加缘,否則是不會有效的。

創(chuàng)世區(qū)塊的目的是搭建私有鏈觉啊,作為鏈上的第一個塊拣宏,如果直接運行節(jié)點的話會同步公鏈的數(shù)據(jù),數(shù)據(jù)量會非常大杠人。如果想在同一個網(wǎng)絡(luò)中獲取數(shù)據(jù)勋乾,創(chuàng)世區(qū)塊也必須要一樣。

新建genesis.json文件內(nèi)容如下:

{
    "config": {},
    "nonce": "0x0000000000000042",
    "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "difficulty": "0x100",
    "alloc": {},
    "coinbase": "0x0000000000000000000000000000000000000000",
    "timestamp": "0x00",
    "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
    "extraData": "0x00",
    "gasLimit": "0xffffffffffff"
}

上面定義了一些如挖礦難度嗡善、以太幣數(shù)量辑莫、gas消耗限制等等信息。

在當前目錄下執(zhí)行geth init genesis.json 來初始化創(chuàng)世區(qū)塊節(jié)點罩引。

至此各吨,環(huán)境配置方面已經(jīng)完成。我們可以通過下面這個命令在8545端口來啟動節(jié)點:

geth --rpc --rpccorsdomain "*" --rpcapi "personal,web3,eth,net" console

三袁铐、創(chuàng)建賬戶以及挖礦

首先我們需要創(chuàng)建第一個賬戶密碼是12345678揭蜒,執(zhí)行命令:

personal.newAccount('12345678')

[圖片上傳失敗...(image-f7dd5d-1556177082135)]

創(chuàng)建賬戶之后就可以挖礦了,注意如果有多個帳戶昭躺,挖到的以太幣默認都會進入第一個賬戶的余額里忌锯。

miner.start()啟動挖礦,miner.stop()停止挖礦

[圖片上傳失敗...(image-74da39-1556177082135)]

四领炫、利用以太坊錢包查詢賬戶信息

截止到現(xiàn)在,我們已經(jīng)成功的啟動以太坊節(jié)點张咳,并可以通過命令來新建賬戶帝洪,執(zhí)行挖礦來獲取以太幣操作似舵。可是通過命令我們可能無法直觀的感受在以太坊上賬戶和余額的變化葱峡。

現(xiàn)在通過以太坊官方提供的錢包砚哗,來管理賬戶和余額。下載地址https://github.com/ethereum/mist/releases

注意:推薦安裝V0.8.10版本砰奕,可以刪除已經(jīng)部署的合約蛛芥,方便調(diào)試,最新版的移除掉了改功能军援。

如果有創(chuàng)世區(qū)塊仅淑,是私有鏈的話,以太坊錢包會默認開啟私有節(jié)點胸哥,否則默認同步公鏈上的數(shù)據(jù)涯竟。

[圖片上傳失敗...(image-b382a0-1556177082135)]

自己可以嘗試用主賬號給其他賬戶轉(zhuǎn)賬,也可以新建賬號和查詢賬戶余額空厌。

五庐船、Solidity編寫智能合約

首先我們需要清楚一個問題,什么是智能合約嘲更?智能合約概念可以概括為: 一段代碼 (智能合約)筐钟,運行在可復制、共享的賬本上的計算機程序赋朦,可以處理信息盗棵,接收、儲存和發(fā)送價值北发。通俗的來講就是可以在區(qū)塊鏈上執(zhí)行的代碼纹因,因為以太坊以前的區(qū)塊鏈只能存儲比特幣上的交易信息,無法做其他事情琳拨。而智能合約的出現(xiàn)瞭恰,可以在鏈上執(zhí)行簡單的業(yè)務(wù)邏輯,這也是區(qū)塊鏈應(yīng)用落地的關(guān)鍵狱庇。

我們基礎(chǔ)已經(jīng)準備就緒惊畏,接下來就用solidity語言來寫數(shù)據(jù)的增加和查詢邏輯。

Solidity中合約的含義就是一組代碼(它的 函數(shù) )和數(shù)據(jù)(它的 狀態(tài) )密任,它們位于以太坊區(qū)塊鏈的一個特定地址上颜启。 代碼行 uint time; 聲明一個類型為 uint (256位無符號整數(shù))的狀態(tài)變量,叫做 time 浪讳。 你可以認為它是數(shù)據(jù)庫里的一個位置缰盏,可以通過調(diào)用管理數(shù)據(jù)庫代碼的函數(shù)進行查詢和變更。對于以太坊來說,上述的合約就是擁有合約(owning contract)口猜。在這種情況下负溪,函數(shù) setget 可以用來變更或取出變量的值。

1. 定義數(shù)據(jù)結(jié)構(gòu)和變量

這里只做一個最簡單的賬戶體系济炎,定義個一個用戶的數(shù)據(jù)結(jié)構(gòu)包含用戶名川抡、用戶地址和注冊時間。

定義用戶列表數(shù)據(jù)結(jié)構(gòu)是為了存儲一個用戶名->用戶地址的映射须尚。

//user.sol
//定義用戶數(shù)據(jù)結(jié)構(gòu)
struct UserStruct {
    address userAddress;
    string username;
    uint time;
    uint index;
}

//定義用戶列表數(shù)據(jù)結(jié)構(gòu)
struct UserListStruct {
    address userAddress;
    uint index;
}

address[] public userAddresses; //所有地址集合
string[] private usernames; //所有用戶名集合
mapping(address => UserStruct) private userStruct; //賬戶個人信息

mapping(string => UserListStruct) private userListStruct; //用戶名映射地址


address[] private userAddresses; 這一行聲明了一個不可以被公開訪問的 address 類型的狀態(tài)變量崖堤。 address 類型是一個160位的值,且不允許任何算數(shù)操作耐床。這種類型適合存儲合約地址或外部人員的密鑰對密幔。如果是關(guān)鍵字 public 允許則你在這個合約之外訪問這個狀態(tài)變量的當前值。

mapping(address => UserStruct) private userStruct; mapping映射將地址映射到用戶數(shù)據(jù)結(jié)構(gòu)咙咽,這個可以初略理解為一個地址所對應(yīng)的值有哪些老玛。

2. 判斷用戶名或地址是否存在

//user.sol
//判斷用戶地址是否存在
function isExitUserAddress(address _userAddress) public constant returns(bool isIndeed) {
    if (userAddresses.length == 0) return false;
    return (userAddresses[userStruct[_userAddress].index] == _userAddress);
}

//判斷用戶名是否存在
function isExitUsername(string _username) public constant returns(bool isIndeed) {
    if (usernames.length == 0) return false;
    return (keccak256(usernames[userListStruct[_username].index]) == keccak256(_username));
}

這里我們分別去判斷用戶名和地址是否存在,判斷依據(jù)是看用戶名或地址是否存在于所對應(yīng)的數(shù)組钧敞。

需要注意的是蜡豹,在JavaScript中判斷一個值是否在數(shù)組中用到的indexOf(),但是在solidity是不支持該函數(shù)溉苛。有兩種方案:一種是循環(huán)集合來判斷是否存在镜廉,第二種是創(chuàng)建的時候為每條數(shù)據(jù)加index索引,只需按索引取值愚战。

因為第一種需要遍歷整個數(shù)組娇唯,當數(shù)據(jù)量非常大的時候效率不高,所以通過索引取值的方式更加快速寂玲。

3. 新建數(shù)據(jù)和查詢數(shù)據(jù)

對于數(shù)據(jù)的插入和查詢塔插,其實就是往數(shù)組集合中添加和讀取數(shù)據(jù)。

//user.sol
//根據(jù)用戶名查找對于的address
function findUserAddressByUsername(string _username) public constant returns (address userAddress) {
    require(isExitUsername(_username));
    return userListStruct[_username].userAddress;
}


//創(chuàng)建用戶信息
function createUser(address _userAddress, string _username) public returns (uint index) {
    require(!isExitUserAddress(_userAddress)); //如果地址已存在則不允許再創(chuàng)建

    userAddresses.push(_userAddress); //地址集合push新地址
    userStruct[_userAddress] = UserStruct(_userAddress, _username, now, userAddresses.length - 1);

    usernames.push(_username); //用戶名集合push新用戶
    userListStruct[_username] = UserListStruct(_userAddress, usernames.length - 1); //用戶所對應(yīng)的地址集合

    return userAddresses.length - 1;
}


//獲取用戶個人信息
function findUser(address _userAddress) public constant returns (address userAddresses, string username, uint time, uint index) {
    require(isExitUserAddress(_userAddress));
    return (
        userStruct[_userAddress].userAddress,
        userStruct[_userAddress].username,
        userStruct[_userAddress].time,
        userStruct[_userAddress].index); 
}

當然拓哟,除了增加和查詢之外想许,還可對相應(yīng)的數(shù)組進行修改和刪除。這里的修改和刪除操作其實并不是真正的更改數(shù)據(jù)断序,因為區(qū)塊鏈上的數(shù)據(jù)是無法篡改的流纹。當然除非迫不得已的話,不建議直接在鏈上修改和刪除數(shù)據(jù)违诗。

六漱凝、web3.js與合約交互

現(xiàn)在我們把智能合約已經(jīng)寫好了,可以通過js來讀取和添加數(shù)據(jù)了诸迟,但在這之前需要我們部署剛才寫的合約茸炒。部署合約有一種比較快捷方便的方法愕乎,就是在以太坊錢包里部署。

[圖片上傳失敗...(image-56d6ab-1556177082135)]
需要注意的是扣典,部署完成后妆毕,需要執(zhí)行挖礦才能成功慎玖,因為部署合約(包括寫數(shù)據(jù))贮尖,需要節(jié)點通過挖礦來確認交易。

完了之后我們可以在合約列表中找到剛才部署的合約趁怔。

tips: 第一次合約部署完成湿硝,如果想要推出要執(zhí)行一次exit,否則合約無法保存润努。

這時候可以點進去关斜,執(zhí)行寫入數(shù)據(jù)和讀取數(shù)據(jù)操作了。那么怎樣才能使用代碼進行操作呢铺浇?

先提前看一下sails文件目錄:

[圖片上傳失敗...(image-83b87-1556177082135)]

1. 安裝truffle

truffle可以將solidity語言的智能合約痢畜,編譯成.json格式的配置文件,可以用它來和web3.js交互鳍侣。

全局安裝truffle丁稀,npm install -g truffle

編譯solidity智能合約,truffle compile

執(zhí)行之后會在build目錄下輸出編譯后的結(jié)果倚聚。

2. 拷貝編譯后的文件中的abi的值

我們編譯的目的是為了拿到abi屬性所對于的配置參數(shù)线衫,手動拷貝到,nodejs的配置文件中惑折。

ps: 這種做法雖然有些傻瓜授账,但是項目官方推薦的合約部署與讀取要簡單很多。

3. web3.js讀取與創(chuàng)建合約內(nèi)容

先看看web3.js上是如何調(diào)用合約的:

讀取methods.myMethod.call惨驶,將調(diào)用“constant”方法并在EVM中執(zhí)行其智能合約方法白热,而不發(fā)送任何事務(wù)。注意調(diào)用不能改變智能合約狀態(tài)粗卜;修改methods.myMethod. send屋确,將交易發(fā)送到智能合約并執(zhí)行其方法。請注意休建,這可以改變智能合約狀態(tài)乍恐。

那現(xiàn)在就根據(jù)以太坊的合約內(nèi)容,封裝一些web3.js調(diào)用智能合約的類测砂。

//Contract.js
const web3Util = require('./Web3Util.js')

class Contract {

    constructor() {
    }

    //user 合約

    /**
     * 判斷用戶名是否存在
     */

    static isExitUsername(username, cb) {
        web3Util.contractUser.methods.isExitUsername(username).call()
            .then(result => {
                cb(null, result)
            })
            .catch(err => {
                cb(err.message)
            });
    }

    /**
     * 根據(jù)用戶名查找對于的地址
     */
    static findUserAddressByUsername(username, cb) {
        web3Util.contractUser.methods.findUserAddressByUsername(username).call()
            .then(result => {
                cb(null, result)
            })
            .catch(err => {
                cb(err.message)
            });
    }

    /**
     * 查找用戶信息
     */
    static findUser(userAddress, cb) {
        web3Util.contractUser.methods.findUser(userAddress).call()
            .then(result => {
                cb(null, result)
            })
            .catch(err => {
                cb(err.message)
            });
    }

    /**
     * 創(chuàng)建用戶信息 (發(fā)送合約需要先解鎖)
     */
    static createUser(userAddress, username, cb) {
        let options = {
            from: Web3Util.ACCOUNT_ADDRESS_MAIN, //創(chuàng)建賬戶用主賬號
            gas: 10000000 //最大的gas數(shù)值
        }
        web3Util.contractUser.methods.createUser(userAddress, username).send(options)
            .then(result => {
                cb(null, result)
            })
            .catch(err => {
                cb(err.message)
            });
    }

}
module.exports = Contract;

上面的文件中在Web3Util.js定義了一些公共常量茵烈,如合約地址,賬戶地址等等砌些。需要注意的是在使用.send()來創(chuàng)建合約內(nèi)容的時候要給gas即小費呜投,讀取內(nèi)容的時候不需要加匈,這個是以太坊智能合約的必填項,關(guān)于gas是如何消耗的大家可以查閱相關(guān)資料了解仑荐。

七雕拼、登錄注冊業(yè)務(wù)邏輯實現(xiàn)

截止到目前為止,我們已經(jīng)成功的將js與solidity連接在一起并且實現(xiàn)互動粘招,那接下來就是實現(xiàn)登錄和注冊啥寇。

登錄其實就是看能否解鎖用戶,然后將用戶的個人資料返回洒扎,注冊就是調(diào)取智能合約來寫入一條記錄辑甜。

解鎖賬戶(只有解鎖才能執(zhí)行合約)方法:

//Web3Util.js
/**
 * 解鎖賬戶
 * @param account 賬戶名
 * @param password 密碼
 */
static unlockAccount(account, password, cb) {
    Web3.eth.personal.unlockAccount(account, password, 600)
        .then(result => {
            cb(null, result)
        })
        .catch(err => {
            cb(err.message)
        });
}

登錄注冊執(zhí)行代碼:

//AccountController.js

module.exports = {
    //判斷用戶名是否存在
    isExitUsername: (req, res) => {
        let username = req.query.username;
        if (!username) return res.json(Message.errMessage('用戶名不能為空'));
        Contract.isExitUsername(username, (err, result) => {
            Message.handleResult(res, err, result)
        })
    },

    //登錄(用戶名或地址登錄)
    login: (req, res) => {
        let account = req.body.account
        let password = req.body.password;
        if (!account || !password) return res.json(Message.errMessage('用戶名或密碼不能為空'));

        if (Web3.utils.isAddress(account)) { //account is address

            Web3Util.unlockAccount(account, password, (err, result) => {
                if (err) return res.json(Message.errMessage('用戶名或密碼錯誤'));
                Contract.findUser(account, (err, result) => {
                    Message.handleResult(res, err, result)
                })
            })
        } else { //account is username

            Contract.findUserAddressByUsername(account, (err, address) => {
                if (err) return res.json(Message.errMessage('用戶名或密碼錯誤'));
                Web3Util.unlockAccount(address, password, (err, result) => {
                    if (err) return res.json(Message.errMessage('用戶名或密碼錯誤'));
                    Contract.findUser(address, (err, result) => {
                        Message.handleResult(res, err, result)
                    })
                })
            })

        }
    },

    /**
     * 注冊賬戶,在以太坊生成address,用戶名會寫在合約中
     */
    register: (req, res) => {
        let username = req.body.username
        let password = req.body.password;
        if (!username || !password) return res.json(Message.errMessage('用戶名或密碼不能為空'));
        async.waterfall([
            function (callback) { //檢查用戶名是否存在
                Contract.isExitUsername(username, (err, result) => {
                    if (result) return res.json(Message.errMessage('用戶名已存在'));
                    callback(null, result)
                })
            },
            function (result, callback) {  //創(chuàng)建用戶 > 生成地址
                Web3.eth.personal.newAccount(password).then(address => {
                    callback(null, address)
                })
            },
            function (address, callback) {  //解鎖主賬戶并合約注冊信息
                Web3Util.unlockAccount(Web3Util.ACCOUNT_ADDRESS_MAIN, Web3Util.ACCOUNT__PASSWORD_MAIN, (err, result) => {
                    if (err) return res.json(Message.errMessage(err));
                    Contract.createUser(address, username, (err, result) => {
                        if (err) return res.json(Message.errMessage(err));
                        callback(err, result)
                    })
                })
            },
        ], (err, result) => {
            Message.handleResult(res, err, result)
        })
    },

};


八袍冷、postman接口測試

我們已經(jīng)在router中配置好了路由磷醋,接下來使用接口調(diào)試工具來測試一下,這里使用postman來測試:

注意胡诗,開始測試之前需要開啟以太坊節(jié)點邓线,保證8545端口開啟:geth --rpc --rpccorsdomain "*" --rpcapi "personal,web3,eth,net" console

因為注冊需要更改合約數(shù)據(jù),需要挖礦來確定交易煌恢,所以為了方便調(diào)試骇陈,順便開啟挖礦:miner.start()

1.注冊賬號

[圖片上傳失敗...(image-bb913f-1556177082135)]

因為是執(zhí)行合約交易,注冊完了之后會返回本次交易詳情如塊症虑、消耗的gas等等缩歪。如果本次交易失敗,比如再注冊重復的用戶名谍憔,在solidity中做了攔截匪蝙,本次交易會失敗,失敗的標志是返回的gas是自己設(shè)置的最大值习贫。

這樣我們就在鏈上創(chuàng)建了一個address逛球,以及這個相對應(yīng)的用戶名和注冊時間信息。

2.登錄賬號(賬號同時支持address和用戶名)

[圖片上傳失敗...(image-fcc1be-1556177082135)]

后續(xù)

現(xiàn)在以及能夠通過接口與智能合約交互了苫昌,我們可以稍微加個前端頁面颤绕,就可以當成一個正常app了,只是數(shù)據(jù)庫是區(qū)塊鏈祟身,是不是很酷奥务。

當然區(qū)塊鏈上只能存儲很少的數(shù)據(jù),如果要存儲視頻或者圖片袜硫,可以借助IPFS氯葬,(是永久的、去中心化保存和共享文件的方法婉陷,這是一種內(nèi)容可尋址帚称、版本化官研、點對點超媒體的分布式協(xié)議。)配合著區(qū)塊鏈能夠?qū)崿F(xiàn)更加豐富的功能闯睹。

目前的缺點在于戏羽,讀取和存儲交易數(shù)據(jù)比較慢,這也是目前Dapp應(yīng)用無法大規(guī)模的開展的一部分原因楼吃,但這個并不會阻礙區(qū)塊鏈技術(shù)的發(fā)展始花,因為它解決的是生產(chǎn)關(guān)系,它的思想在于去中心化來防止中央組織的濫用所刀。

在我構(gòu)思這篇文章的時候衙荐,正好是Facebook創(chuàng)始人扎克伯格因數(shù)據(jù)泄漏丑聞在聽證會被輪流質(zhì)問捞挥,利用幾百萬用戶數(shù)據(jù)來干涉總統(tǒng)大選浮创。用戶隱私數(shù)據(jù)一旦被攻破或濫用或商業(yè)分析推薦,后果也是非称龊可怕斩披,這也是當今互聯(lián)網(wǎng)全球化所帶來的弊端。

所以讹俊,如果想要區(qū)塊鏈解決這樣的問題還需要多長的路要走垦沉?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市仍劈,隨后出現(xiàn)的幾起案子厕倍,更是在濱河造成了極大的恐慌,老刑警劉巖贩疙,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件讹弯,死亡現(xiàn)場離奇詭異,居然都是意外死亡这溅,警方通過查閱死者的電腦和手機组民,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來悲靴,“玉大人臭胜,你說我怎么就攤上這事●校” “怎么了耸三?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長浇揩。 經(jīng)常有香客問我仪壮,道長,這世上最難降的妖魔是什么临燃? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任睛驳,我火速辦了婚禮烙心,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘乏沸。我一直安慰自己淫茵,他們只是感情好,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布蹬跃。 她就那樣靜靜地躺著匙瘪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蝶缀。 梳的紋絲不亂的頭發(fā)上丹喻,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天,我揣著相機與錄音翁都,去河邊找鬼碍论。 笑死,一個胖子當著我的面吹牛柄慰,可吹牛的內(nèi)容都是我干的鳍悠。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼坐搔,長吁一口氣:“原來是場噩夢啊……” “哼藏研!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起概行,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤蠢挡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后凳忙,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體业踏,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年消略,在試婚紗的時候發(fā)現(xiàn)自己被綠了堡称。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡艺演,死狀恐怖却紧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情胎撤,我是刑警寧澤晓殊,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站伤提,受9級特大地震影響巫俺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜肿男,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一介汹、第九天 我趴在偏房一處隱蔽的房頂上張望却嗡。 院中可真熱鬧,春花似錦嘹承、人聲如沸窗价。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽撼港。三九已至,卻和暖如春骤竹,著一層夾襖步出監(jiān)牢的瞬間帝牡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工蒙揣, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留靶溜,地道東北人。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓鸣奔,卻偏偏與公主長得像墨技,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子挎狸,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345

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