软件工程与实践jdchain数据账户模型介绍合约类型介绍支持传入数据类型

Posted 林梓豪 sdu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了软件工程与实践jdchain数据账户模型介绍合约类型介绍支持传入数据类型相关的知识,希望对你有一定的参考价值。

2021SC@SDUSC

一、数据账本的设计核心

1.数据账本模型

数据账本的核心任务是对数据进行有效地组织和管理,因此,需要定义数据的结构和数据处理的操作模型。

JD Chain的数据账本模型以“键值”结构来组织业务数据,定义标准的读写操作,记录数据变更历史,维护数据完整性与不可否认性,管理数据的存在性证明。

二、数据账本的介绍

数据账本为各参与方提供区块链底层服务功能,包括区块、账户、配置和存储等。

区块是JD Chain账本主要组成部分,包含交易信息和交易执行状态的数据快照哈希值,但不存储具体的交易操作和状态数据。JD Chain将账本状态和合约进行分离,并约束合约对账本状态的访问,来实现数据与逻辑分离,提供无状态逻辑抽象。

JD Chain通过细化账户分类、分级分类授权的方式,对区块链系统中的账户进行管理,达到逻辑清晰化、隔离业务和保护相关数据内容的目的。

配置文件包括密钥信息,存储信息以及共享的参与者身份信息等内容,使JD Chain系统中各节点能够执行诸如连接其他节点、验证信息、存储并更新账本等操作。

存储格式采用简洁的KV数据类型, 使用较为成熟的NoSQL数据库来实现账本的持久化存储,使区块链系统能够支持海量交易。

三、合约样例一览

提供通过合约创建用户/数据账户/事件账户,写入KV,发布事件等功

1.设置KV

/**
     * 设置KV
     *
     * @param address 数据账户地址
     * @param key     键
     * @param value   值
     * @param version 版本
     */
    @ContractEvent(name = "setKVWithVersion")
    void setKVWithVersion(String address, String key, String value, long version);

    /**
     * 设置KV,基于最新数据版本
     *
     * @param address 数据账户地址
     * @param key     键
     * @param value   值
     */
    @ContractEvent(name = "setKV")
    void setKV(String address, String key, String value);

如上代码,我们可以看到,第一段代码调用了setKVWithVersion的方法,该方法可以帮助初始数据账户、键、值、以及版本的信息。

@Override
    public void setKVWithVersion(String address, String key, String value, long version) {
        eventContext.getLedger().dataAccount(Bytes.fromBase58(address)).setText(key, value, version);
    }

第二段代码的setKV可以基于最新版本的KV进行设置,if语句用于判别该版本是否为最新版本,若不为最新版本则version = entries[0].getVersion();该语句可以更新到最新版本。

@Override
    public void setKV(String address, String key, String value) {
        // 查询最新版本,初始为-1
        // 查询已提交区块数据,不包括此操作所在未提交区块的所有数据
        // TypedKVEntry[] entries = eventContext.getLedger().getDataEntries(eventContext.getCurrentLedgerHash(), address, key);
        // 可查询包括此操作所在未提交区块的所有数据
        TypedKVEntry[] entries = eventContext.getUncommittedLedger().getDataEntries(address, key);
        long version = -1;
        if (null != entries && entries.length > 0) {
            version = entries[0].getVersion();
        }
        eventContext.getLedger().dataAccount(Bytes.fromBase58(address)).setText(key, value, version);
    }

2.注册用户、数据账户、事件账户

 /**
     * 注册用户
     *
     * @param seed 种子,不小于32个字符
     */
    @ContractEvent(name = "registerUser")
    String registerUser(String seed);

    /**
     * 注册数据账户
     *
     * @param seed 种子,不小于32个字符
     */
    @ContractEvent(name = "registerDataAccount")
    String registerDataAccount(String seed);

    /**
     * 注册事件账户
     *
     * @param seed 种子,不小于32个字符
     */
    @ContractEvent(name = "registerEventAccount")
    String registerEventAccount(String seed);

如上代码分别使用了三个方法

1.这一段代码使用了registerUser(String seed)、getAlgorithm(“ed25519”)、getSignatureFunction(algorithm)、generateKeypair(seed.getBytes())、getPrivKey()、getPubKey()的方法用于获取用户输入的密码账号名等信息

return keypair.getAddress().toBase58();最终会返回一个邮箱的信息,该信息的格式是Base58。

@Override
    public String registerUser(String seed) {
        CryptoAlgorithm algorithm = Crypto.getAlgorithm("ed25519");
        SignatureFunction signFunc = Crypto.getSignatureFunction(algorithm);
        AsymmetricKeypair cryptoKeyPair = signFunc.generateKeypair(seed.getBytes());
        BlockchainKeypair keypair = new BlockchainKeypair(cryptoKeyPair.getPubKey(), cryptoKeyPair.getPrivKey());
        eventContext.getLedger().users().register(keypair.getIdentity());

        return keypair.getAddress().toBase58();
    }

2.下面两段代码与上面一段代码可以当作类似来处理。

@Override
    public String registerDataAccount(String seed) {
        CryptoAlgorithm algorithm = Crypto.getAlgorithm("ed25519");
        SignatureFunction signFunc = Crypto.getSignatureFunction(algorithm);
        AsymmetricKeypair cryptoKeyPair = signFunc.generateKeypair(seed.getBytes());
        BlockchainKeypair keypair = new BlockchainKeypair(cryptoKeyPair.getPubKey(), cryptoKeyPair.getPrivKey());
        eventContext.getLedger().dataAccounts().register(keypair.getIdentity());

        return keypair.getAddress().toBase58();
    }

    @Override
    public String registerEventAccount(String seed) {
        CryptoAlgorithm algorithm = Crypto.getAlgorithm("ed25519");
        SignatureFunction signFunc = Crypto.getSignatureFunction(algorithm);
        AsymmetricKeypair cryptoKeyPair = signFunc.generateKeypair(seed.getBytes());
        BlockchainKeypair keypair = new BlockchainKeypair(cryptoKeyPair.getPubKey(), cryptoKeyPair.getPrivKey());
        eventContext.getLedger().eventAccounts().register(keypair.getIdentity());

        return keypair.getAddress().toBase58();
    }

4.发布事件

/**
     * 发布事件
     *
     * @param address  事件账户地址
     * @param topic    消息名称
     * @param content  内容
     * @param sequence 当前消息名称下最大序号(初始为-1)
     */
    @ContractEvent(name = "publishEventWithSequence")
    void publishEventWithSequence(String address, String topic, String content, long sequence);

    /**
     * 发布事件,基于最新时间序号
     *
     * @param address 事件账户地址
     * @param topic   消息名称
     * @param content 内容
     */
    @ContractEvent(name = "publishEvent")
    void publishEvent(String address, String topic, String content);

上面的代码使用了如下的方法

1.调用这个方法可以调取事件的各项信息进行发布

 @Override
    public void publishEventWithSequence(String address, String topic, String content, long sequence) {
        eventContext.getLedger().eventAccount(Bytes.fromBase58(address)).publish(topic, content, sequence);
    }

2.下面这段代码用if语句判断事件是否为空,若不为空则可以获取用getSequence()方法来获取event的时间序列,以达成案最新时间序列输出的功能。

    @Override
    public void publishEvent(String address, String topic, String content) {
        // 查询最新序号,初始为-1
        // 查询已提交区块数据,不包括此操作所在未提交区块的所有数据
        // Event event = eventContext.getLedger().getRuntimeLedger().getLatestEvent(address, topic);
        // 可查询包括此操作所在未提交区块的所有数据
        Event event = eventContext.getUncommittedLedger().getLatestEvent(address, topic);
        long sequence = -1;
        if (null != event) {
            sequence = event.getSequence();
        }
        eventContext.getLedger().eventAccount(Bytes.fromBase58(address)).publish(topic, content, sequence);
    }

四、支持数据类型

setText,字符类型

setInt64,长整型

setJSON,JSON串

setBytes,字节数组

setTimestamp,时间戳,长整型

setXML,XML文本

setImage,图片字节数据

本质上仅支持String/Long/[]byte这三种数据类型,JSON/XML/Image/Timestamp等起标识作用,用于扩展差异化数据展示等场景需求
setText(“key1”, “value1”, -1)中第三个参数即为数据版本,需要传入JD Chain网络中当前key1的最高数据版本,首次写入时传入-1。

以上是关于软件工程与实践jdchain数据账户模型介绍合约类型介绍支持传入数据类型的主要内容,如果未能解决你的问题,请参考以下文章

以太坊

智能合约从入门到精通:完整范例

以太坊智能合约项目-Token合约开发与部署

智能合约bug以及修改方案

以太坊外部账户EOA与合约账户CA的区别

3.以太坊之秘钥文件