Java搭建区块链

2023-11-11

前言

为了更好的理解区块链的底层实现原理,决定自己动手模拟实现一条区块链。

思路分析

通过之前的学习,从文本知识的角度,我们知道,创世区块、记账原理、挖矿原理、工作量证明、共识机制等等区块链的相关知识。

创建一条区块链,首先默认构造创世区块。在此基础上,我们可以发布交易,并进行挖矿,计算出工作量证明,将交易记录到区块中,每成功的挖一次矿,块高就+1。当然在此过程中,可能会出现“造假”的问题。也就是说,每一个新注册的节点,都可以有自己的链。这些链长短不一,为了保证账本的一致性,需要通过一种一致性共识算法来找到最长的链,作为样本,同步数据,保证每个节点上的账本信息都是一致的。

数据结构

  • 区块链
    这里写图片描述
    如图所示,索引为1的区块即为创始区块。可想而知,可以用List<区块>来表示区块链。其中,区块链的高度即为链上区块的块数,上图区块高度为4。
  • 区块
    这里写图片描述
    单个区块的数据结构有索引、交易列表、时间戳、工作量证明、上一个区块的hash组成。
  • 交易列表
    这里写图片描述
    整个区块链就是一个超级大的分布式账本,当发生交易时,矿工们通过计算工作量证明的方法来进行挖矿(本文中挖到矿将得到1个币的奖励),将发生的交易记录到账本之中。

Web API

我们将通过Postman来模拟请求。请求API如下:

/nodes/register 注册网络节点
/nodes/resolve 一致性共识算法
/transactions/new 新建交易
/mine 挖矿
/chain 输出整条链的数据

项目目录结构

Gradle Web 项目
这里写图片描述

dependencies {
    compile('javax:javaee-api:7.0')
    compile('org.json:json:20160810')

    testCompile('junit:junit:4.12')
}

实现代码

注释写的很详细,如果遇到不懂的地方,欢迎大家一同讨论。

  • BlockChain类 ,所有的核心代码都在其中。
    // 存储区块链
    private List<Map<String, Object>> chain;
    // 该实例变量用于当前的交易信息列表
    private List<Map<String, Object>> currentTransactions;
    // 网络中所有节点的集合
    private Set<String> nodes;


    private static BlockChain blockChain = null;

    private BlockChain() {
        // 初始化区块链以及当前的交易信息列表
        chain = new ArrayList<Map<String, Object>>();
        currentTransactions = new ArrayList<Map<String, Object>>();
        // 初始化存储网络中其他节点的集合
        nodes = new HashSet<String>();

        // 创建创世区块
        newBlock(100, "0");
    }

    /**
     * 在区块链上新建一个区块
     * @param proof 新区块的工作量证明
     * @param previous_hash 上一个区块的hash值
     * @return 返回新建的区块
     */
    public Map<String, Object> newBlock(long proof, String previous_hash) {

        Map<String, Object> block = new HashMap<String, Object>();
        block.put("index", getChain().size() + 1);
        block.put("timestamp", System.currentTimeMillis());
        block.put("transactions", getCurrentTransactions());
        block.put("proof", proof);
        // 如果没有传递上一个区块的hash就计算出区块链中最后一个区块的hash
        block.put("previous_hash", previous_hash != null ? previous_hash : hash(getChain().get(getChain().size() - 1)));

        // 重置当前的交易信息列表
        setCurrentTransactions(new ArrayList<Map<String, Object>>());

        getChain().add(block);

        return block;
    }

    // 创建单例对象
    public static BlockChain getInstance() {
        if (blockChain == null) {
            synchronized (BlockChain.class) {
                if (blockChain == null) {
                    blockChain = new BlockChain();
                }
            }
        }
        return blockChain;
    }

    /**
     * @return 得到区块链中的最后一个区块
     */
    public Map<String, Object> lastBlock() {
        return getChain().get(getChain().size() - 1);
    }

    /**
     * 生成新交易信息,信息将加入到下一个待挖的区块中
     * @param sender 发送方的地址
     * @param recipient 接收方的地址
     * @param amount 交易数量
     * @return 返回该交易事务的块的索引
     */
    public int newTransactions(String sender, String recipient, long amount) {

        Map<String, Object> transaction = new HashMap<String, Object>();
        transaction.put("sender", sender);
        transaction.put("recipient", recipient);
        transaction.put("amount", amount);

        getCurrentTransactions().add(transaction);

        return (Integer) lastBlock().get("index") + 1;
    }

    /**
     * 生成区块的 SHA-256格式的 hash值
     * @param block 区块
     * @return 返回该区块的hash
     */
    public static Object hash(Map<String, Object> block) {
        return new Encrypt().Hash(new JSONObject(block).toString());
    }

    /**
     * 注册节点
     * @param address 节点地址
     * @throws MalformedURLException
     */
    public void registerNode(String address) throws MalformedURLException {
        URL url = new URL(address);
        String node = url.getHost() + ":" + (url.getPort() == -1 ? url.getDefaultPort() : url.getPort());
        nodes.add(node);
    }

    /**
     * 验证是否为有效链,遍历每个区块验证hash和proof,来确定一个给定的区块链是否有效
     * @param chain
     * @return
     */
    public boolean vaildChain(List<Map<String,Object>> chain) {
        Map<String,Object> lastBlock = chain.get(0);
        int currentBlockIndex = 1;
        while (currentBlockIndex < lastBlock.size()) {
            Map<String,Object> currentBlock = chain.get(currentBlockIndex);
            //检查区块的hash是否正确
            if (!currentBlock.get("previous_hash").equals(hash(lastBlock))) {
                return false;
            }
            lastBlock = currentBlock;
            currentBlockIndex ++;
        }
        return true;
    }

    /**
     * 使用网络中最长的链. 遍历所有的邻居节点,并用上一个方法检查链的有效性,
     * 如果发现有效更长链,就替换掉自己的链
     * @return 如果链被取代返回true, 否则返回false
     * @throws IOException
     */
    public boolean resolveConflicts() throws IOException {
        //获得当前网络上所有的邻居节点
        Set<String> neighbours = this.nodes;

        List<Map<String, Object>> newChain = null;

        // 寻找最长的区块链0
        long maxLength = this.chain.size();

        // 获取并验证网络中的所有节点的区块链
        for (String node : neighbours) {

            URL url = new URL("http://" + node + "/chain");
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.connect();

            if (connection.getResponseCode() == 200) {
                BufferedReader bufferedReader = new BufferedReader(
                        new InputStreamReader(connection.getInputStream(), "utf-8"));
                StringBuffer responseData = new StringBuffer();
                String response = null;
                while ((response = bufferedReader.readLine()) != null) {
                    responseData.append(response);
                }
                bufferedReader.close();

                JSONObject jsonData = new JSONObject(responseData.toString());
                long length = jsonData.getLong("blockLength");
                List<Map<String, Object>> chain = (List) jsonData.getJSONArray("chain").toList();

                // 检查长度是否长,链是否有效
                if (length > maxLength && vaildChain(chain)) {
                    maxLength = length;
                    newChain = chain;
                }
            }

        }
        // 如果发现一个新的有效链比我们的长,就替换当前的链
        if (newChain != null) {
            this.chain = newChain;
            return true;
        }
        return false;
    }
  • Proof 类 ,计算工作量证明
/**
     * 计算当前区块的工作量证明
     * @param last_proof 上一个区块的工作量证明
     * @return
     */
    public long ProofOfWork(long last_proof){
        long proof = 0;
        while (!(vaildProof(last_proof,proof))) {
            proof ++;
        }
        return proof;
    }

    /**
     * 验证证明,是否拼接后的Hash值以4个0开头
     * @param last_proof 上一个区块工作量证明
     * @param proof 当前区块的工作量证明
     * @return
     */
    public boolean vaildProof(long last_proof, long proof) {
        String guess = last_proof + "" + proof;
        String guess_hash = new Encrypt().Hash(guess);
        boolean flag = guess_hash.startsWith("0000");
        return  flag;
    }
  • Encrypt 类 ,Hash计算工具类
public class Encrypt {
     /**
      * 传入字符串,返回 SHA-256 加密字符串
      * @param strText
      * @return
      */
     public String Hash(final String strText) {
         // 返回值
         String strResult = null;
         // 是否是有效字符串
         if (strText != null && strText.length() > 0) {
             try {
                 // 创建加密对象,传入要加密类型
                 MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
                 // 传入要加密的字符串
                 messageDigest.update(strText.getBytes());
                 // 执行哈希计算,得到 byte 数组
                 byte byteBuffer[] = messageDigest.digest();
                 // 將 byte 数组转换 string 类型
                 StringBuffer strHexString = new StringBuffer();
                 // 遍历 byte 数组
                 for (int i = 0; i < byteBuffer.length; i++) {
                     // 转换成16进制并存储在字符串中
                     String hex = Integer.toHexString(0xff & byteBuffer[i]);
                     if (hex.length() == 1) {
                         strHexString.append('0');
                     }
                     strHexString.append(hex);
                 }
                 // 得到返回結果
                 strResult = strHexString.toString();
             } catch (NoSuchAlgorithmException e) {
                 e.printStackTrace();
             }
         }
         return strResult;
     }
 }
  • FullChain 类,输出整条链的信息。
/**
 * @Author: cfx
 * @Description: 该Servlet用于输出整个区块链的数据(Json)
 * @Date: Created in 2018/5/9 17:24
 */
@WebServlet("/chain")
public class FullChain extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        BlockChain blockChain = BlockChain.getInstance();
        Map<String,Object> response = new HashMap<String, Object>();
        response.put("chain",blockChain.getChain());
        response.put("blockLength",blockChain.getChain().size());

        JSONObject jsonObject = new JSONObject(response);
        resp.setContentType("application/json");
        PrintWriter printWriter = resp.getWriter();
        printWriter.println(jsonObject);
        printWriter.close();
    }
}
  • InitialID 类 ,初始化时执行,随机的uuid作为矿工的账户地址。
/**
 * @Author: cfx
 * @Description: 初始化时,使用UUID来作为节点ID
 * @Date: Created in 2018/5/9 17:17
 */
@WebListener
public class InitialID implements ServletContextListener {

    public void contextInitialized(ServletContextEvent sce) {
        ServletContext servletContext = sce.getServletContext();
        String uuid = UUID.randomUUID().toString().replace("-", "");
        servletContext.setAttribute("uuid", uuid);
        System.out.println("uuid is : "+servletContext.getAttribute("uuid"));
    }

    public void contextDestroyed(ServletContextEvent sce) {
    }
}
  • Register 类 ,节点注册类,记录网络上所有的节点,用户共识算法,保证所有的节点上的账本都是一致的。
/**
 * @Author: cfx
 * @Description: 注册网络节点
 * @Date: Created in 2018/5/10 11:26
 */
@WebServlet("/nodes/register")
public class Register extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("utf-8");
        // 读取客户端传递过来的数据并转换成JSON格式
        BufferedReader reader = req.getReader();
        String input = null;
        StringBuffer requestBody = new StringBuffer();
        while ((input = reader.readLine()) != null) {
            requestBody.append(input);
        }
        JSONObject jsonValue = new JSONObject(requestBody.toString());
        BlockChain blockChain = BlockChain.getInstance();
        blockChain.registerNode(jsonValue.getString("nodes"));

        PrintWriter printWriter = resp.getWriter();
        printWriter.println(new JSONObject().append("message","The Nodes is : " + blockChain.getNodes()));
        printWriter.close();

    }
}
  • NewTransaction 类,新建交易类。
/**
 * @Author: cfx
 * @Description: 该Servlet用于接收并处理新的交易信息
 * @Date: Created in 2018/5/9 17:22
 */
@WebServlet("/transactions/new")
public class NewTransaction extends HttpServlet {

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        req.setCharacterEncoding("utf-8");
        // 读取客户端传递过来的数据并转换成JSON格式
        BufferedReader reader = req.getReader();
        String input = null;
        StringBuffer requestBody = new StringBuffer();
        while ((input = reader.readLine()) != null) {
            requestBody.append(input);
        }
        JSONObject jsonValues = new JSONObject(requestBody.toString());

        // 检查所需要的字段是否位于POST的data中
        String[] required = { "sender", "recipient", "amount" };
        for (String string : required) {
            if (!jsonValues.has(string)) {
                // 如果没有需要的字段就返回错误信息
                resp.sendError(400, "Missing values");
            }
        }

        // 新建交易信息
        BlockChain blockChain = BlockChain.getInstance();
        int index = blockChain.newTransactions(jsonValues.getString("sender"), jsonValues.getString("recipient"),
                jsonValues.getLong("amount"));

        // 返回json格式的数据给客户端
        resp.setContentType("application/json");
        PrintWriter printWriter = resp.getWriter();
        printWriter.println(new JSONObject().append("message", "Transaction will be added to Block " + index));
        printWriter.close();
    }
}
  • Mine , 挖矿类。
/**
 * @Author: cfx
 * @Description: 该Servlet用于运行工作算法的证明来获得下一个证明,也就是所谓的挖矿
 * @Date: Created in 2018/5/9 17:21
 */
@WebServlet("/mine")
public class Mine extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        BlockChain blockChain = BlockChain.getInstance();

        //计算出工作量证明
        Map<String,Object> lastBlock = blockChain.lastBlock();
        Long last_proof = Long.parseLong(lastBlock.get("proof") + "");
        Long proof = new Proof().ProofOfWork(last_proof);

        //奖励计算出工作量证明的矿工1个币的奖励,发送者为"0"表明这是新挖出的矿。
        String uuid = (String) this.getServletContext().getAttribute("uuid");
        blockChain.newTransactions("0",uuid,1);

        //构建新的区块
        Map<String,Object> newBlock = blockChain.newBlock(proof,null);
        Map<String, Object> response = new HashMap<String, Object>();
        response.put("message", "New Block Forged");
        response.put("index", newBlock.get("index"));
        response.put("transactions", newBlock.get("transactions"));
        response.put("proof", newBlock.get("proof"));
        response.put("previous_hash", newBlock.get("previous_hash"));

        // 返回新区块的数据给客户端
        resp.setContentType("application/json");
        PrintWriter printWriter = resp.getWriter();
        printWriter.println(new JSONObject(response));
        printWriter.close();
    }
}
  • Consensus 类 ,通过判断不同节点上链的长度,来找出最长链,这就是一致性共识算法。
/**
 * @Author: cfx
 * @Description: 一致性共识算法,解决共识冲突,保证所有的节点都在同一条链上(最长链)
 * @Date: Created in 2018/5/10 11:38
 */
@WebServlet("/nodes/resolve")
public class Consensus extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        BlockChain blockChain = BlockChain.getInstance();
        boolean flag = blockChain.resolveConflicts();
        System.out.println("是否解决一致性共识冲突:" + flag);
    }
}

运行结果

以下是本人之前的测试记录:

首次请求/chain:
    初始化Blockchain
    {
        "chain": [
            {
                "index": 1,
                "proof": 100,
                "transactions": [],
                "timestamp": 1526284543591,
                "previous_hash": "0"
            }
        ],
        "chainLenth": 1
    }

请求/nodes/register,进行网络节点的注册。
request:
    {
      "nodes": "http://lcoalhost:8080"
    }
response:
    {"message":["All Nodes are:[lcoalhost:8080]"]}

请求/mine,进行挖矿。
{
    "index": 2,
    "proof": 35293,
    "message": "New Block Forged",
    "transactions": [
        {
            "amount": 1,
            "sender": "0",
            "recipient": "e91467fe51bd43b8ad7892b3bc09bd4e"
        }
    ],
    "previous_hash": "c4b2bb2f6e042680aed249309791cac96da6c1f65b811c306088723ae3c73f66"
}
请求/chain,查看链上所有区块的数据
{
    "chain": [
        {
            "index": 1,
            "proof": 100,
            "transactions": [],
            "timestamp": 1526284543591,
            "previous_hash": "0"
        },
        {
            "index": 2,
            "proof": 35293,
            "transactions": [
                {
                    "amount": 1,
                    "sender": "0",
                    "recipient": "e91467fe51bd43b8ad7892b3bc09bd4e"
                }
            ],
            "timestamp": 1526284661678,
            "previous_hash": "c4b2bb2f6e042680aed249309791cac96da6c1f65b811c306088723ae3c73f66"
        }
    ],
    "chainLenth": 2
}

请求/transactions/new,新建交易。
request: 
    {
     "sender": "d4ee26eee15148ee92c6cd394edd974e",
     "recipient": "someone-other-address",
     "amount": 6
    }
response:
    {
        "message": [
            "Transaction will be added to Block 3"
        ]
    }
请求/mine,计算出工作量证明。将上面的交易记录到账本之中。
{
    "index": 3,
    "proof": 35089,
    "message": "New Block Forged",
    "transactions": [
        {
            "amount": 6,
            "sender": "d4ee26eee15148ee92c6cd394edd974e",
            "recipient": "someone-other-address"
        },
        {
            "amount": 1,
            "sender": "0",
            "recipient": "e91467fe51bd43b8ad7892b3bc09bd4e"
        }
    ],
    "previous_hash": "a12748a35d57a4a371cefc4a8c294236d69c762d28b889abb2ae34a31d2b7597"
}

请求/chain,查看链上所有区块的数据
{
    "chain": [
        {
            "index": 1,
            "proof": 100,
            "transactions": [],
            "timestamp": 1526284543591,
            "previous_hash": "0"
        },
        {
            "index": 2,
            "proof": 35293,
            "transactions": [
                {
                    "amount": 1,
                    "sender": "0",
                    "recipient": "e91467fe51bd43b8ad7892b3bc09bd4e"
                }
            ],
            "timestamp": 1526284661678,
            "previous_hash": "c4b2bb2f6e042680aed249309791cac96da6c1f65b811c306088723ae3c73f66"
        },
        {
            "index": 3,
            "proof": 35089,
            "transactions": [
                {
                    "amount": 6,
                    "sender": "d4ee26eee15148ee92c6cd394edd974e",
                    "recipient": "someone-other-address"
                },
                {
                    "amount": 1,
                    "sender": "0",
                    "recipient": "e91467fe51bd43b8ad7892b3bc09bd4e"
                }
            ],
            "timestamp": 1526284774452,
            "previous_hash": "a12748a35d57a4a371cefc4a8c294236d69c762d28b889abb2ae34a31d2b7597"
        }
    ],
    "chainLenth": 3
}

存在的问题

有一个问题没有解决,就是我们启动多实例来模拟不同的网络节点时,并不能解决节点加入同一个Set的问题,也就是说根本无法通过节点本身来获得其他网络节点,进而判断最长链。所以/nodes/resolve请求暂时时无用的。期间也有想方法解决,比如通过所谓的“第三方”–数据库,当一个节点注册时,保存到数据库中;当第二个节点加入时,也加入到数据库中…当需要请求解决一致性算法时,去数据库中读取节点信息遍历即可。但是,自己没有去实现。这是我的想法,毕竟是两个不相干的实例。如果有朋友有其他的解决方案,请一定要告诉我!谢谢。

总结

通过简单的Demo实现区块链,当然其中简化了大量的实现细节,所以说其实并没有多少实际参考价值。但是意义在于,能帮助我们更容易的理解区块链,为之后的学习打下夯实的基础。

项目源码

Java从零开始创建区块链Demo

参考文章

https://learnblockchain.cn/2017/11/04/bitcoin-pow/
http://blog.51cto.com/zero01/2086195等。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java搭建区块链 的相关文章

  • iOS和macOS上Swift编写的EOS区块链开源框架SwiftyEOS

    SwiftyEOS是一个用于与EOS交互的开源框架 用Swift编写 可以在iOS和macOS上使用 特点 EOS密钥对生成 私钥导入 签名哈希 基本的RPC API 链 历史 可查询客户端 交易 EOS token 转账 帮助类处理iOS
  • [区块链安全-CTF Protocol]区块链智能合约安全实战(已完结)

    区块链安全 CTF Protocol 区块链智能合约安全实战 前言 1 The Lost Kitty 2 RootMe 3 Trickster 4 The Golden Ticket 5 Smart Horrocrux 6 Gas Valv
  • 区块链应用开发(智能合约的开发和WeBASE合约IDE的使用)

    文章目录 四 智能合约的开发和WeBASE合约IDE的使用 一 实验概述 二 实验目标 三 实验环境及建议 四 实验步骤 4 1 启动Webase 4 2 智能合约开发 4 2 1 合约功能设计 4 2 2 存证合约开发 4 2 3 工厂合
  • 课程笔记3

    一 以太坊 比特币被称为区块链1 0 以太坊被称为区块链2 0 以太坊的符号是ETH 以太币的符号是Ether 单位是Wei 比特币的符号是BTC 单位是Satoshi 以太坊做出的改进 在以太坊中出块时间减少到十几秒 比特币的mining
  • 期货开户手续费的组成和收费模式

    期货公司的费用 公开透明 不会私自提高费率 A级别的期货公司 不会私自提高期货投资者的交易费率 不会私自提高期货投资者的保证金比例 说一下投资者最关系的费率问题 期货投资交易的手续费是由两部分组成 1 交易所手续费 这个是固定标准也是市场上
  • 首个数字银行卡明年发行,广州出台区块链措施支持大湾区

    锌链接作为首个提出产业区块链的机构媒体 一直积极推动产业区块链落地 通过深度报道直戳行业痛点 通过分享会聆听行业声音 通过周报呈现行业大观 通过评论展现独特产业观察视角 本周 广州出台66条措施支持粤港澳大湾区金融发展 其中多项与区块链有关
  • 交易的本质 什么样的信仰,决定什么样的交易人生

    什么样的信仰 决定什么样的生活 同样 什么样的理念 也决定了什么样的交易 多数的交易员都把能否在交易市场稳定化盈利归结于自己从事这个行业的时间 通常很多人会说五年入门 十年小成等等 好像只要坚持个五年十年就能够在交易市场找到自己的位置 你信
  • 区块链+物联网 BOT

    不可否认 我们的一只脚已经迈入万物智联时代 但另一只脚迈入还存在一定的阻碍 区块链技术的出现将会促进这一进程的发展 智能音响 主人你好 我是小Q 现在是早上08点29分 上班时间要到咯 智能门锁 主人你摔疼我了 你总是这样匆忙 下次赶紧麻溜
  • 圆石说│彭一鸣:运用区块链技术赋能实体旅游产业;微软开放6万项专利包括一个开源区块链项目……

    智联招聘 区块链岗位需求主要集中在一线和新一线城市 智联招聘报告显示 从目前区块链职位的城市分布来看 该领域的岗位需求主要集中在一线和新一线城市中 其中 北京 上海和深圳位于第一梯队 职位占比分别达到24 20 和10 杭州 广州和成都紧随
  • 区块链中的哈希算法

    区块链中的密码学 密码学在区块链中的应用主要有两个 哈希算法与非对称加密算法 这次主要对哈希算法进行详细的说明 哈希算法 哈希算法的特点有 1 输入可以为任意大小的字符串 2 产生固定大小的输出 3 可以在合理的时间内算出输出值 若要满足密
  • hyperledger fabric介绍

    一 Hyperledger Fabric介绍 2015年 Linux基金会启动了Hyperledger项目 目标是发展跨行业的区块链技术 Hyperledger Fabric是Hyperledger中的一个区块链项目 包含一个账本 使用智能
  • 使用web3和infura开发以太坊ethereum区块链

    web3 Github https github com ethereum web3 js web3 js是以太坊提供的一个Javascript库 它封装了以太坊的RPC通信API 提供了一系列与区块链交互方法 使js与以太坊交互变得简单
  • 【区块链与密码学】第2-3讲:区块链基础技术大剖析之哈希函数

    本课堂内容全部选编自PlatON首席密码学家 武汉大学国家网络安全学院教授 博士生导师何德彪教授的 区块链与密码学 授课讲义 教材及互联网 版权归属其原作者所有 如有侵权请立即与我们联系 我们将及时处理 2 4 1 哈希函数 区块链作为一个
  • 区块链交易平台服务器该怎么选

    区块链交易平台服务器该怎么选 随着互联网技术的发展 区块链也发展成为一种潮流 越来越多的人加入到区块链行业中来 尤其是区块链交易平台 但也有很多人不了解区块链对服务器的要求 那么我们就要好好说说搭建区块链交易平台服务器该怎么选 1 区块链交
  • Solidity之旅(七)单位以及全局变量

    01 以太币单位 Ether 甭管是虚拟货币还是现实中的 稳定币 他们都有各自的货币单位 当然咯 作为以太坊区块链上交易的虚拟货币以太坊也是有属于自己的那一套货币单位的 而目前以太币 Ether 主要分为这三个 wei gwei以及ethe
  • Solidity之旅(十)OOP-抽象合约

    抽象合约 abstractcontract 前文在讲合约继承的基类构造函数的参数时 有提到抽象合约 也就是说 如果派生合约未能给其继承的基合约指定构造函数参数时 那么 该派生合约必须声明为抽象合约 abstractcontract 我们知道
  • 期货和期权哪个风险更大?有哪些相同和不同的地方?

    期货和期权这两个都是高风险 高收益的投资工具是两个相同的部分 而期货呢是保证金交易理论上亏损是无限的 而期权呢买入期权的话最大亏损也就是权利金 这个是两者的最大区别 下文科普期货和期权哪个风险更大 有哪些相同和不同的地方 本文来自 期权酱
  • 期权开户最低多少钱个人可以开?

    大家新年好 现在2024年龙年 很多想玩期权的小伙伴都知道期权开通需要50万的门槛 那么今天来给大家详细介绍下期权开户最低多少钱个人可以开 本文将对期权开户最低金额进行探讨 帮助投资者更好地了解期权交易的投资门槛 本文来自 期权酱 一 期权
  • 申泰勇教练的独家人物化身系列即将登陆 The Sandbox

    申泰勇 Shin Tae yong 教练是足球界的传奇人物 他来到 The Sandbox 推出了自己的专属人物化身系列 作为前 K 联赛中场球员和印尼队取得历史性成就的幕后教练 他的传奇经历现在已经影响到了虚拟世界 向过去 现在和未来致敬
  • 【网络安全】——区块链安全和共识机制

    区块链安全和共识机制 摘要 区块链技术作为一种分布式去中心化的技术 在无需第三方的情况下 使得未建立信任的交易双方可以达成交易 因此 区块链技术近年来也在金融 医疗 能源等多个行业得到了快速发展 然而 区块链为无信任的网络提供保障的同时 也

随机推荐

  • Swagger的使用详细教程

    Swagger的使用详细教程 Swagger是一款开源的API文档工具 它提供了一种简单且强大的方式来描述 展示和测试RESTful风格的Web服务接口 本文将详细介绍Swagger的使用方法 包括安装配置和使用示例 步骤 1 添加Swag
  • 基于Python的机器学习实践(portein)

    目录 数据集 简介 代码 1 数据的读入 2 数据理解 3 数据规整化处理 数据准备 4 数据建模 5 查看模型 6 模型预测 7 结果输出 数据集 https download csdn net download llf000000 86
  • JMeter使用命令行模式生成HTML测试报告

    自动生成html图形化报告 win r 输入 cmd 说明 jmeter n t Jmx脚本位置 l 结果文件result jtl存放的位置 e o 生成HTML报告指定文件夹 n 表示non gui mode 就是非图形化模式 t 指定J
  • 怎么更改dns_ESHOP连不上?SWITCH最新实用DNS地址分享

    虽然任天堂Switch采用的是不锁区的方式 但是由于各种虚拟墙的存在已经网络延迟等问题 经常导致玩家连不上eshop 买不了游戏 更新个游戏显示都要好几万小时 当然这个可以使用各种加速器等方式来解决 但是好的加速器需要付费 免费的又会经常抽
  • Receive port always be disabled.

    I configured a receive port in FILE to a local folder Biztalk administration console keep show that port is disables I f
  • 支付宝个人收款解决方案之支付宝签约方案

    关键词 签约支付 签约收款 支付宝收款 个人签约收款 背景 有做网赚或者在网上售卖个人小产品小服务的 需要进行收款 如果零星个别的收款可能直接走个人转账然后手动发货即可 但是一旦流程标准下来 量走起来之后 付款发货就需要自动化了 以提高人效
  • TCP实现socket通信(python)

    socket简介 UDP实现socket通信 python TCP实现socket通信 python 1 套接字工作流程 服务器端先初始化Socket 建立一个套接字 与端口绑定 bind 用 bind 函数来绑定一个端口号和 IP 地址
  • Java开发中的23种设计模式详解

    设计模式 Design Patterns 可复用面向对象软件的基础 设计模式 Design pattern 是一套被反复使用 多数人知晓的 经过分类编目的 代码设计经验的总结 使用设计模式是为了可重用代码 让代码更容易被他人理解 保证代码可
  • Hibernate Validator的使用以及自定义

    Hibernate Validator的英文官方文档 https hibernate org validator documentation Hibernate Validator的作用 Hibernate Validator是一个校验框架
  • Java五子棋的实现(附源码)

    学习目的 熟悉java中swing类与java基础知识的巩固 文末有源代码文件和打包的jar文件 效果图 思路 1 首先构建一个Frame框架 来设置菜单选项与按钮点击事件 MyFrame java文件代码如下 package StartG
  • http传输字符编码与转义(深度好文)

    一 引言 最近陆陆续续看了好多关于字节 字符 字符编码 字符转义的文章 终于对这个过程有了比较清晰深刻的认识 和后台开发相结合知道了乱码出现的理论具体原因 和前台开发结合知道了get与post请求的过程 这里分析下供大家学习分享 字符转义指
  • centos7离线安装sql server2019

    关闭SELINUX root localhost sed i SELINUX s enforcing disabled g etc selinux config setenforce 0 上传rpm包和依赖包 下载地址 https pkgs
  • SQL create file遇到操作系统错误5拒绝访问

    客户操作系统重新安装之后 也重新安装的了SQL Server2008R2 但是附加原来的数据的时候出现下面的错 尝试打开或创建物理文件 E liudaxitong D Data MDF 时 CREATE FILE 遇到操作系统错误 5 拒绝
  • kubernetes Service(SVC)几种4层代理的不同用法,ClusterIP、Headless、NodePort、LoadBalancer

    kubernetes Service SVC 个人学习记录 kubernetes Service SVC service 概念 service 类型 SVC 访问流程组件 VIP 和 Service 代理 代理模式分类 userspace
  • 怎么用Python设置Tkinter(TK)窗口屏幕居中且获得/设置Tkinter窗口的标题

    要修改窗口位置和修改窗口大小 要用到是tk对象提供的geometry方法 该方法的用法是geometry 字符串 这个字符串格式为 窗口宽x窗口高 窗口位于屏幕x轴 窗口位于屏幕y轴 可以只设置窗口大小或者是只设置窗口的x轴和y轴 例如ge
  • 《百万在线 大型游戏服务端开发》前两章概念笔记

    第1章 从角色走路说起 游戏网络通信的流程则是服务端先开启监听 等待客户端的连接 然后交互操作 最后断开 套接字 每个Socket都包含网络连接中一端的信息 每个客户端需要一个Socket结构 服务端则需要N 1个Socket结构 其中N为
  • MySQL数据库表的合并及分区

    今天我们来聊聊处理大数据时Mysql的存储优化 当数据达到一定量时 一般的存储方式就无法解决高并发问题了 最直接的MySQL优化就是分区分表 以下是我个人对分区分表的笔记 1 合并表 把多个结果相同的的表合并为一个容器 容器的类型 Myis
  • 欢聚集团 -- 前端二面

    面试形式 牛客网 电话面试 30多分钟 我二面进行两次 第一次二面自我介绍完 输出等腰三角形代码还没写完牛客网面试页面就死掉了 第一次二面就这样结束了 第二次二面牛客网还是不行就直接电话面试了 面试内容 用JS在控制台输出由 构成的等腰三角
  • Harbor仓库自启动设置

    1 配置文件 cd etc systemd system vi harbor service Unit Description Harbor After docker service systemd networkd service sys
  • Java搭建区块链

    前言 为了更好的理解区块链的底层实现原理 决定自己动手模拟实现一条区块链 思路分析 通过之前的学习 从文本知识的角度 我们知道 创世区块 记账原理 挖矿原理 工作量证明 共识机制等等区块链的相关知识 创建一条区块链 首先默认构造创世区块 在