Skip to content

MacOMNI/WalletAdapter

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

51 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Solana Java Sdk

Solana for java

参考链接

链共识机制

  • Solana 中应用的共识机制包括 Proof of History(POH) +Tower BFT+Proof of Replicate(复制证明)。POH 可将事件的时间编码排序输入到分布式账本中,随后利用 Tower BFT 共识机制来确认 POH 顺序的一致性。可将 Solana 将出块和验证分为两个不同的阶段,由一个节点(leader)负责收集交易并排序出块,其它节点负责验证。

链结构说明

  • Solana 中没有分片等结构,每笔交易都包含了前一笔交易都 hash,因此类似于每笔交易都是一个区块。

链角色说明

  • 领导者

    1. Solana领导者的任务是生产新区块,它们每四个块(1.6秒)旋转一次。处于领导地位的节点将所有交易放入该节点正在生产的四个区块中。该节点将这些包含事务的块显示给名为Solana Clusters的相关节点组。集群使用数字时间戳作为参考来验证交易,并将记录快速传递给其他节点;

    2. 在工作历史证明的支持下,领导者会不断轮换,无论网络状况如何,整个网络都无需任何验证者交流,遇到错误也不会停止,而是马上在新的区块高度上开始接下来的行动。这意味着Solana的网络成为了“永动机”。因为领导者和验证者都是可轮换的;

    3. 同时,Solana领导者的轮换决策是异步进行的。

    4. 视图 领导者

  • 验证者

    1. 验证节点参与交易验证;
    2. 验证者在投票时不断更新自己的根叉;
    3. 每次槽高度越过一个纪元(EPOCH)边界时,验证者都会更新其领导者时间表。

链的治理模型

使用委托权益证明共识算法,激励代币持有者验证交易。SOL三个常用治理模型:

  • Staking 质押过程
    1. 质押竞选成为Leader,通过质押的数量的占比来轮换,所以这成了一个内卷的游戏;
    2. SOL 每年 -15% 代币通货膨胀,将 95% 膨胀的代币 分配给质押者;
  • Fee
    1. Solana 中的交易费用会根据系统负载动态调整。50% 的费用被烧掉,这间接使 SOL 持有者受益,因为这降低了 SOL 的整体供应量。其余部分由提议包含交易的区块的验证者保留;
  • DAO

链的算法调研

  • 公私钥

    1. 算法 ed25519
  • 地址

    1. 地址生成过程 未命名文件没看见看见
  • 签名

    1. 签名就是ED25519的签名,没有特殊化,具体主要看代码演示过程 sign
  • Hash 算法说明

    1. 使用的散列算法是 SHA-256
  • 手续费模型

    1. Solana 中的交易费用会根据系统负载动态调整。
  • 暂不支持交易加速

  • 如何防止假充值

    1. 目前扫链没有进行中的中间状态,当交易 finalized 才给出交易结果;
  • 扫块注意问题

    1. 暂时没有特别注意的状态
  • sol 和 spl 交易类型分类:

    1. sol 转账,目标地址为 spl token account 也可正常上链,但 token account 上的 sol 无法正常转出,通过 closing-accounts 关闭账号,从而实现对账号中余额的回收;
    2. spl 交易目标类型只能是 spl token account,如果目标是 sol account 无法上链,交易失败;
    3. spl token account 地址派生算法(可离线计算默认关联账户);
    4. 目标spl token account 不存在,对手续费无影响,但创建关联账户时需要转账 0.002 SQL 保持关联账户激活状态,有相关 rpc 可判断目标 spl token account 是否存在;
    5. sol account + spl token + nonce(0~255) 可计算出多个 关联账户;
    6. 全部转出 sol: total - fee;
    7. 全部转出 spl token: spl total + 足够手续费;
  • 如何和 sol 自定义合约交互(example-helloworld

    1. 合约示例
    2. 合约代码
    3. 其他教程

SDK 需求

SDK API

 /**
 * Chain
 */
public interface Chain {
   /**
    * 检测地址有效性
    * @param address 
    * @return
    */
    boolean checkAddress(String address); 
    /**
     * 随机生成密钥 以及 地址
     * @return
     */  
    WalletPair genPair();
    /**
     *  pub2Address
     * @param publicKey 公钥
     * @return
     */
    String pub2Address(String publicKey);
    /**
     * 构建 TxPayload
     * @param input 
     * @return
     * @throws RpcException
     */
    TTransaction buildTxPayload(TSignInput input) throws RpcException;
    /**
     * 签名原始交易
     * @param secretKey 私钥
     * @param message 待签名数据
     * @return
     */
    String signTransaction(String secretKey,byte[] message);
    /**
     * 合并交易并序列化
     * @param transaction
     * @param signatures 签名后的数组
     * @return
     */
    SignResult combineTransaction(TTransaction transaction,List<String> signatures);
    /**
     * 提交交易上链
     * @param rawtx
     * @return
     * @throws RpcException
     */
    RpcResult submitTransaction(String rawtx) throws RpcException;
    /**
     * 获取 手续费 
     * @param input 暂时可为空
     * @return
     * @throws RpcException
     */
    RpcResult  getTxFees(RpcInput input) throws RpcException;
    /**
     * 获取 账户余额
     * @param input
     * @return
     * @throws RpcException
     */
    RpcResult  getBanlance(RpcInput input) throws RpcException;
    /**
     * 获取最新块高
     * @return
     * @throws RpcException
     */
    long  getLatestBlockHeight() throws RpcException;
    /**
     * 指定块高获取 交易块信息
     * @param blockHeight
     * @return
     * @throws RpcException
     */
    RpcBlock  getBlockHeightTransactions(long blockHeight) throws RpcException;
   /**
     * 获取特定 txhash 相关的交易
     * @param txHash
     * @return
     * @throws RpcException
     */
    List<RpcTransaction>  getTxHashTransaction(String txHash) throws RpcException;

}

离线交易序列化和签名

  1. 生成公私钥对
    public class WalletPair {
    String publicKey;
    String secretKey;
    String address;
    }
    public void generateAccountPairTest() {
        Chain solanaChain = new Solana(Cluster.MAINNET.getEndpoint(),"");
        WalletPair pair = solanaChain.genPair();
    }
  2. 公钥derive地址
    public void public2AddressTest() {
        Chain solanaChain = new Solana(Cluster.MAINNET.getEndpoint(),"");
        String publicKey = "CuBUgjUkk1F9zubiy2Ns19cnLpk9UNMCQx13zZ8QAtJR";
        String emptyAddress = solanaChain.pub2Address("CuBUgjUkk1F9zubiy2Ns19");
        String address = solanaChain.pub2Address(publicKey);
        assertEquals(null, emptyAddress);
        assertEquals("CuBUgjUkk1F9zubiy2Ns19cnLpk9UNMCQx13zZ8QAtJR", address);
    }
  3. 交易签名分以下几种
    1. Sol Tranfer
    2. Token Tranfer
    3. CreateAccount And TokenTranfer 组装
    4. 复杂的合约交易
    case 1: Sol Tranfer     
    case 2: Token Tranfer 
    case 3: CreateAccount And Token Tranfer 
    详见单元测试 buildTxPayload
  4. 进行私钥签名sign,返回签名后的数据 。
    byte[]  message =  solTx.getTransaction().messageSerialize();
    Logger.info("message  = " + Hex.toHexString(message));
    String signature = solanaChain.signTransaction(HexSecretKey, message);
  5. 交易和私钥签名组装combine,返回最终上链的序列化数据。
    List<String> signatures = new ArrayList<String>();
    signatures.add(signature);
    SignResult result =  solanaChain.combineTransaction(solTx, signatures);
  6. 计算submit交易hash:需要根据交易签名组装交易后,预计算出此交易的hash。
     RpcResult res = solanaChain.submitTransaction(result.getRawTx());

封装和链交互接口

  1. 查询最新块高度

    Chain solanaChain = new Solana(Cluster.DEVNET.getEndpoint(),"");
    ("BlockHeight = " + solanaChain.getLatestBlockHeight());
  2. 指定高度查询区块信息,包含解析块交易,获取块交易中的主链币交易和Token交易,数据如下

    public abstract class RpcBlock {
    /**块 时间 */
    private long blockTime;
    /**块高 */
    private String blockHeight;
    /**块哈希 */
    private String blockhash;
    /**交易列表 */
    private List<RpcTransaction> transactions;
    }
    
    public abstract class RpcTransaction {
        /**
         * owner 下某合约币的关联账户
        */
        private  String fromAccount;
        /**
         * dest  下某合约币的关联账户
        */
       private String toAccount;
       /**
         * 交易类型
        */
       private TransactionType type;
        /**
         * from address
        */
        private String from;
         /**
         * to address
        */
        private String to;
        /**
         * 合约地址 address
        */
        private String contractAddress;
        /**
         * 转账数量
         */
        private String amount;
        /**
         * 转账数量 暂定整数 long
         */
        private String uiAmount;
         /**
         *  手续费
         */
        private String fee;
         /**
         *  手续费
         */
        private String uiFee;
         /**
         *  token 精度
         */
        private int decimal;
        /**
         *  txhash
         */
        private String txhash;
        /**
         *  status
         */
        private Commitment status;
    }
  3. 根据交易Hash获取指定交易

    /**交易列表 */
    List<RpcTransaction> transactions = getTxHashTransaction("2Z91u...c3Vy");
  4. 预估手续费

    public class FeeInfo {
    public string fee;
    public String uiFee;
    }
    详见单元测试: getFeeInfo()
  5. 转账前置参数

    public abstract class TSignInput{
        /**
         * owner 下某合约币的关联账户
        */
        private String fromAccount;
        /**
         * dest  下某合约币的关联账户, 可不传
        */
        private String toAccount;
        /**
         * 最近 blockHash
        */
        private String recentBlockHash;
        /**
         * from address
        */
        private String from;
         /**
         * to address
        */
        private String to;
         /**
         * 合约地址 address
        */
        private String contractAddress;
        /**
         * 转账数量
         */
        private String amount;
         /**
         *  手续费
         */
        private String fee;
         /**
         *  token 精度
         */
        private int decimal;
        /**
         * 操作类型
         */
        private ActionType actionType;
    }
  6. 查询余额方法,包括主链币和合约token币

    public class BanlanceInfo {
    public String amount;
    public String uiAmount;
    public int decimals;
    }
    主链币详见:getOwnerBanlance()
    代币详见:getTokenBanlance()
  7. 提交上链方法

    RpcResult res = solanaChain.submitTransaction(result.getRawTx());
    Logger.info("RpcResult = " + res.getTxHash());
  8. 检测地址

    public void checkAddressTest() {
        Chain solanaChain = new Solana(Cluster.MAINNET.getEndpoint(),"MAINNET");
        boolean isAddress1 = solanaChain.checkAddress("CuBUgjUkk1F9zubiy2Ns19cnLpk9UNMCQx13zZ8QAtJR");
        boolean isAddress2 = solanaChain.checkAddress("CuBUgjUkk1F9aubiy2Ns19cnLpk9UNMCQx13zZ8QAtJ");
        assertEquals(true, isAddress1);
        assertEquals(false, isAddress2);
    }

节点搭建文档

  1. 节点性能要求高
  2. 节点:
    1. 全节点(全部节点数据,占用大量磁盘)
    2. Rpc 节点(推荐搭建,定时删除冗余数据)
    3. 验证节点(在 Rpc 基础上,可以参与交易验证)
  3. 节点启动参数说明 Solana启动验证节点教程
  4. 节点配置说明
    1. 配置推荐:64core 256mem 2x2080Ti
    2. 磁盘推荐: 1T GPT分区
  5. 节点运行是否正常,提供校验命令
    1. 查看端口
    solana 端口:  8899
    root@solana:~#  lsof -i:8899
    COMMAND     PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
    solana-va 11967 root  116u  IPv4  54896      0t0  TCP *:8899 (LISTEN)
    1. 查看mainnet集群信息(包含我们自己的节点信息)
    root@solana:~#  curl -X POST -H "Content-Type: application/json" -d '{"jsonrpc":"2.0","id":1, "method":"getClusterNodes"}' http://api.mainnet-beta.solana.com

About

solana for java

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages