<|start_filename|>test/so/asch/sdk/impl/DelegateServiceTest.java<|end_filename|>
package so.asch.sdk.impl;

import org.testng.Assert;
import so.asch.sdk.AschResult;
import so.asch.sdk.AschSDK;
import so.asch.sdk.TestData;
import so.asch.sdk.dto.query.DelegateQueryParameters;

public  class DelegateServiceTest {

    @org.testng.annotations.Test
    public void testGetCount() throws Exception {
        Assert.assertNotNull(AschSDK.Delegate);
        AschResult result= AschSDK.Delegate.getDelegatesCount();
        Assert.assertTrue(result.isSuccessful());
    }

    @org.testng.annotations.Test
    public void testGetVoters() throws Exception {
        AschResult result= AschSDK.Delegate.getVoters(TestData.publicKey());
        Assert.assertTrue(result.isSuccessful());
    }

    @org.testng.annotations.Test
    public void testGetDelegateByPublicKey() throws Exception {
        AschResult result= AschSDK.Delegate.getDelegateByPublicKey(TestData.publicKey());
        Assert.assertTrue(result.isSuccessful());
    }

    @org.testng.annotations.Test
    public void testGetDelegateByName() throws Exception {
        AschResult result= AschSDK.Delegate.getDelegateByName(TestData.userName);
        Assert.assertTrue(result.isSuccessful());
    }

    @org.testng.annotations.Test
    public void testGetDelegates() throws Exception {
        DelegateQueryParameters query = new DelegateQueryParameters()
                .setLimit(10);
        AschResult result= AschSDK.Delegate.queryDelegates(query);
        Assert.assertTrue(result.isSuccessful());
    }

    @org.testng.annotations.Test
    public void testGetDelegateFee() throws Exception {
        AschResult result= AschSDK.Delegate.getDelegateFee(TestData.publicKey());
        Assert.assertTrue(result.isSuccessful());
    }

    @org.testng.annotations.Test
    public void testGetForging() throws Exception {
    }

    @org.testng.annotations.Test
    public void testRegisterDelegate() throws Exception {
        AschResult result= AschSDK.Delegate.registerDelegate(TestData.userName, TestData.secret, TestData.secondSecret);
        Assert.assertTrue( result.isSuccessful()||
                "Account is already a delegate".equals(result.getError()));
    }

    @org.testng.annotations.Test
    public void testEnableForge() throws Exception {
    }

    @org.testng.annotations.Test
    public void testDisableForge() throws Exception {
    }

    @org.testng.annotations.Test
    public void testGetForgingStatus() throws Exception {
    }
}

<|start_filename|>src/so/asch/sdk/impl/AschFactory.java<|end_filename|>
package so.asch.sdk.impl;

import so.asch.sdk.*;
import so.asch.sdk.security.DefaultSecurityStrategy;
import so.asch.sdk.security.SecurityStrategy;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 简单的Asch服务对象工厂，可替换成DI工具管理
 * @author eagle
  */
public final class AschFactory {
    private final static AschFactory instance = new AschFactory();

    private AschFactory(){ }

    public static AschFactory getInstance(){
        return instance;
    }

    private final SecurityStrategy securityStrategy = new DefaultSecurityStrategy();

    private static Map<Class<? extends AschInterface> , AschInterface> serviceContainer = new ConcurrentHashMap<>();

    /**
     * 注册服务类
     * @param interfaceType Asch接口类
     * @param serviceType Asch接口实现类
     * @return 工厂对象本身，实现链式访问
     * */
    protected AschFactory register(Class<? extends AschInterface> interfaceType, Class<? extends AschInterface> serviceType){
        try{
            serviceContainer.put(interfaceType, serviceType.newInstance());
        }
        catch (Exception ex){
            //do nothing;
        }

        return this;
    }

    /**
     * 获取Asch接口服务实例
     * @param interfaceType 接口类型
     * @return 服务对象实例
     * */
    public <AI> AI getService(Class<? extends AschInterface> interfaceType){
        try {
            return (AI) serviceContainer.get(interfaceType);
        }
        catch (Exception ex){
            return null;
        }
    }

    public SecurityStrategy getSecurity(){ return securityStrategy; }

    static {
        getInstance()
                .register(Account.class, AccountService.class)
                .register(Delegate.class, DelegateService.class)
                .register(Block.class, BlockService.class)
                .register(Transaction.class, TransactionService.class)
                .register(Signature.class, SignatureService.class)
                .register(Dapp.class, DappService.class)
                .register(UIA.class, UIAService.class)
                .register(Peer.class, PeerService.class)
                .register(Misc.class, MiscService.class);
    }

}


<|start_filename|>test/so/asch/sdk/impl/AccountServiceTest.java<|end_filename|>
package so.asch.sdk.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.io.FileUtils;
import org.testng.Assert;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.Test;
import so.asch.sdk.AschResult;
import so.asch.sdk.AschSDK;
import so.asch.sdk.TestData;
import so.asch.sdk.dto.query.QueryParameters;

import java.io.File;
import java.io.IOException;

/**
 * AccountService Tester.
 *
 * @author eagle
 * @since <pre>07/16/2017</pre>
 * @version 1.0
 */
public class AccountServiceTest {
    @BeforeSuite
    public void SetUp(){
        AschSDK.Config.setAschServer(TestData.root);
    }

    @Test
    public void testLogin() throws Exception {
        AschResult result= AschSDK.Account.login(TestData.secret);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testSecureLogin() throws Exception {
        AschResult result= AschSDK.Account.secureLogin(TestData.secret);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testGetAccount() throws Exception {
        AschResult result= AschSDK.Account.getAccount(TestData.address);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testGetBalance() throws Exception {
        AschResult result= AschSDK.Account.getBalance(TestData.address);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testGetPublicKey() throws Exception {
        AschResult result= AschSDK.Account.getPublicKey(TestData.address);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testGeneratePublicKey() throws Exception {
        AschResult result= AschSDK.Account.generatePublicKey(TestData.secret);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testVote() throws Exception {
        AschResult result= AschSDK.Account.vote(
                TestData.voted,
                TestData.canceled,
                TestData.secret,
                TestData.secondSecret
        );

        Assert.assertTrue(result.isSuccessful() ||
                "account has already voted for this delegate".equals(result.getError())||
                "Failed to remove vote, account has not voted for this delegate".equals(result.getError()));
    }

    @Test
    public void testTransfer() throws Exception {
        AschResult result= AschSDK.Account.transfer(
                TestData.targetAddress,
                AschSDK.Helper.amountForCoins(1),
                "Transfer by Test",
                TestData.secret,
                TestData.secondSecret);

        Assert.assertTrue(result.isSuccessful() && result.getRawJson().contains("transactionId"));
    }

    @Test
    public void testGetDelegatesFee() throws Exception {
        AschResult result= AschSDK.Account.getDelegatesFee();
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testGetVotedDelegates() throws Exception {
        AschResult result= AschSDK.Account.getVotedDelegates(TestData.address);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testGetTopAccounts() throws Exception {
        QueryParameters parameters = new QueryParameters()
                .setLimit(50)
                .setOffset(0);

        AschResult result= AschSDK.Account.getTopAccounts(parameters);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void main() throws IOException {
        File a = FileUtils.getFile("D:/a.txt");
        String str = FileUtils.readFileToString(a,"utf-8");
        JSONObject json = JSON.parseObject(str);
        JSONArray arry = JSONArray.parseArray(json.get("delegates").toString());
        for(int i = 0;i<arry.size();i++){
            JSONObject obj= (JSONObject) arry.get(i);
            String username =  obj.getString("username");
            String productivity =  obj.getString("productivity");
            String producedblocks = obj.getString("producedblocks");
            String balance = obj.getString("balance");
            String approval = obj.getString("approval");
            System.out.println(username +"||" + productivity +"||" + producedblocks + "||" + balance + "||" + approval);
        }
    }
}


<|start_filename|>src/so/asch/sdk/transaction/asset/TransferAssetInfo.java<|end_filename|>
package so.asch.sdk.transaction.asset;

import java.nio.ByteBuffer;

public class TransferAssetInfo extends AssetInfo{

    //如果transaction中assset不能为空
    @Override
    public void addBytes(ByteBuffer buffer){
        //do nothing
    }
}


<|start_filename|>src/so/asch/sdk/AschInterface.java<|end_filename|>
package so.asch.sdk;

/**
 * Asch接口
 * @author eagle
 *
 */
public interface AschInterface {
}


<|start_filename|>src/so/asch/sdk/Misc.java<|end_filename|>
package so.asch.sdk;

/**
 * Created by eagle on 17-7-10.
 */
public interface Misc extends AschInterface{
    //查看本地区块链加载状态
    //接口地址：/api/loader/status
    //请求方式：get
    //支持格式：无
    //请求参数说明：无参数
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //loaded	boole
    //blocksCount	integer
    AschResult getLoadStatus();

    //查看区块同步信息
    //接口地址：/api/loader/status/sync
    //请求方式：get
    //支持格式：无
    //请求参数说明：无参数
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //height	int	区块高度
    AschResult getSyncStatus();

    //上传数据
    //接口地址：/api/storages
    //请求方式：PUT
    //支持格式：json
    //接口备注：创建者账户需在web端钱包登陆过
    //请求参数说明：
    //secondSecret	string	N	发送者二级密码，最小长度1，最大长度：100
    //content	string	Y	上传数据内容
    //encode	string	N	上传数据的格式，可选项为：raw/base64/hex，默认为raw
    //wait	number	N	等待确认数，范围为0-6，默认为0。wait为0表示不等待，速度最快，但无法保证数据在掉电情况下不丢失，大于2时，可以100%确保数据已经同步到大部分机器上了，但需要时间较长10-20秒之间，折中的方案是1,wait为1时虽然不能100%保证同步到其他机器，但失败的几率非常小，只是理论上存在，实际上还没遇到过
    //返回参数说明：
    //success	boole	是否成功获得response数据。
    //transactionId	string	交易id
    AschResult storeData(String content, ContentEncoding encoding, int wait, String secret, String secondSecret);

    //查询存储的数据
    //接口地址：/api/storages
    //请求方式：GET
    //支持格式：urlencode
    //请求参数说明：
    //transactionId(id)	string	Y	交易id
    //返回参数说明：
    //success	boole	是否成功获得response数据。
    //id	string	交易id
    AschResult getStoredData(String transactionId);

}


<|start_filename|>src/so/asch/sdk/impl/MiscService.java<|end_filename|>
package so.asch.sdk.impl;

import so.asch.sdk.AschResult;
import so.asch.sdk.ContentEncoding;
import so.asch.sdk.Misc;
import so.asch.sdk.codec.Decoding;
import so.asch.sdk.dbc.Argument;
import so.asch.sdk.transaction.TransactionInfo;

public class MiscService extends AschRESTService implements Misc {
    @Override
    public AschResult getLoadStatus() {
        return get(AschServiceUrls.Misc.GET_LOAD_STATUS);
    }

    @Override
    public AschResult getSyncStatus() {
        return get(AschServiceUrls.Misc.GET_SYNC_STATUS);
    }

    @Override
    public AschResult storeData(String content, ContentEncoding encoding, int wait, String secret, String secondSecret) {
        try {
            Argument.notNullOrEmpty(content, "content");
            Argument.notNull(encoding, "encoding");
            Argument.require(Validation.isValidContent(content, encoding), "invalid content");
            Argument.require(Validation.isValidWait(wait), "invalid wait");
            Argument.require(Validation.isValidSecret(secret), "invalid secret");
            Argument.optional(secondSecret, Validation::isValidSecondSecret, "invalid second secret");

            TransactionInfo transaction = getTransactionBuilder()
                    .buildStore(getContentBuffer(content, encoding), wait, secret, secondSecret);

            return broadcastTransaction(transaction);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    private byte[] getContentBuffer(String content, ContentEncoding encoding){
        try {
            switch (encoding) {
                case Base64:
                    return Decoding.base64(content);
                case Hex:
                    return Decoding.hex(content);
                case Raw:
                    return content.getBytes();
                default:
                    return new byte[0];
            }
        }catch (Exception ex){
            return new byte[0];
        }
    }

    @Override
    public AschResult getStoredData(String transactionId) {
        try {
            Argument.require(Validation.isValidTransactionId(transactionId), "invalid transactionId");

            ParameterMap parameters = new ParameterMap().put("id", transactionId);

            return get(AschServiceUrls.Misc.GET_STORED_DATA, parameters);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }
}


<|start_filename|>src/so/asch/sdk/impl/REST.java<|end_filename|>
package so.asch.sdk.impl;

import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URL;
import java.util.Map;


/**
 * 简单的REST服务访问类
 * @author eagle
 */
public final class REST {

        private static Logger logger = LoggerFactory.getLogger(REST.class);

        protected static void addCustomeHeads(Map<String, String> heads, HttpEntityEnclosingRequest request) {
            if (null == heads ) return;

            for (Map.Entry<String, String> entry : heads.entrySet()){
                request.setHeader(entry.getKey(), entry.getValue());
            }
        }

        protected static StringEntity createEntity(String parameterString, String charset) throws UnsupportedEncodingException
        {
            StringEntity  entity = new StringEntity(parameterString, charset);
            entity.setContentType("application/json");

            return entity;
        }

        protected static HttpResponse rawPost(String url, ParameterMap parameters, Map<String,String> customeHeads, String charset ) throws IOException{
            String parameterString = parameters == null ? "" : parameters.toJSONString();
            return rawPost(url, parameterString, customeHeads, charset);
        }

        protected static HttpResponse rawPost(String url, String requestBody, Map<String,String> customeHeads, String charset ) throws IOException{
            CloseableHttpClient httpClient = HttpClients.createDefault();
            HttpPost post = new HttpPost(encodeUrl(url));

            addCustomeHeads(customeHeads, post);
            StringEntity entity = createEntity(requestBody, charset);
            post.setEntity(entity);

            logger.debug(String.format("POST url:%s, body:%s", url, requestBody));
            return httpClient.execute(post);
        }

        protected static String getResponseContent(HttpResponse response) throws IOException{

            if (null == response)
                throw new IOException("Get response failed");

            String content = EntityUtils.toString(response.getEntity());

            if (logger.isDebugEnabled()) {
                logger.debug(String.format("RESPONSE code:%d, reason:%s, content:%s", response.getStatusLine().getStatusCode(),
                        response.getStatusLine().getReasonPhrase(),
                        content));
            }

            if (!content.contains("\"success\":")){
                throw new IOException(String.format("Http server response failed, code:%d, reason:%s.\n content:%s",
                        response.getStatusLine().getStatusCode(),
                        response.getStatusLine().getReasonPhrase(),
                        content));
            }

            return content;
        }

        protected static String encodeUrl(String url)throws IOException{
            try{
                URL uri = new URL(url);

                return new URI(uri.getProtocol(), uri.getUserInfo(), uri.getHost(), uri.getPort(),
                        uri.getPath(), uri.getQuery(), null)
                        .toString();
            }
            catch(Exception ex){
                throw new IOException("invalid url: "+ url, ex);
            }
        }

        public static String post(String url, String parameters,  Map<String, String> customeHeaders, String charset) throws IOException{
            try {
                HttpResponse response = rawPost(url, parameters, customeHeaders, charset);
                return getResponseContent(response);
            }
            catch (IOException ex){
                String errorInfo = String.format("Exception when post,url:%s,data:%s", url, parameters);
                logger.error(errorInfo, ex);
                throw ex;
            }
        }

        public static String post(String url, ParameterMap parameters, Map<String,String> customeHeads, String charset) throws IOException {
            String parametersString = parameters == null ? "" : parameters.toJSONString();
            return post(url, parametersString, customeHeads, charset);
        }

        public static String post(String url, String parameters, Map<String,String> customeHeads ) throws IOException {
            return post(url, parameters, customeHeads, null);
        }

        public static String post(String url, ParameterMap parameters, Map<String,String> customeHeads ) throws IOException {
            return post(url, parameters, customeHeads, null);
        }

        public static String post(String url, String parameters ) throws IOException {
            return post(url, parameters, null, null);
        }

        public static String post(String url, ParameterMap parameters ) throws IOException {
            String parametersString = parameters == null ? "" : parameters.toJSONString();
            return post(url, parametersString, null, null);
        }

        public static HttpResponse rawGet(String url, String queryString) throws IOException{
            CloseableHttpClient httpClient = HttpClients.createDefault();

            String fullUrl = queryString == null ? url : url + "?" + queryString;

            logger.debug("GET url:" + fullUrl);
            HttpGet get = new HttpGet(encodeUrl(fullUrl));

            return httpClient.execute(get);
        }

        public static HttpResponse rawGet(String url, ParameterMap parameters) throws IOException{
            return rawGet(url, parameters == null ? null : parameters.toQueryString());
        }

        public static String get(String url, ParameterMap parameters) throws IOException {
            return getResponseContent(rawGet(url, parameters));
        }

}


<|start_filename|>src/so/asch/sdk/transaction/asset/SignatureAssetInfo.java<|end_filename|>
package so.asch.sdk.transaction.asset;

import so.asch.sdk.codec.Decoding;

import java.nio.ByteBuffer;

public class SignatureAssetInfo extends AssetInfo {

    public static class SignatureInfo {
        public String getPublicKey() {
            return publicKey;
        }

        private SignatureInfo(String publicKey) {
            this.publicKey = publicKey;
        }

        private String publicKey;
    }

    public SignatureInfo getSignature() {
        return signature;
    }

    public SignatureAssetInfo(String publicKey){
        signature = new SignatureInfo(publicKey);
    }

    private SignatureInfo signature = null;

    @Override
    public void addBytes(ByteBuffer buffer){
        buffer.put(Decoding.unsafeDecodeHex(signature.getPublicKey()));
    }
}


<|start_filename|>src/so/asch/sdk/impl/TransactionService.java<|end_filename|>
package so.asch.sdk.impl;

import so.asch.sdk.AschResult;
import so.asch.sdk.Transaction;
import so.asch.sdk.dbc.Argument;
import so.asch.sdk.dto.query.TransactionQueryParameters;

public class TransactionService extends AschRESTService implements Transaction {
    @Override
    public AschResult queryTransactions(TransactionQueryParameters parameters) {
        try {
            Argument.require(Validation.isValidTransactionQueryParameters(parameters), "invalid parameters");

            ParameterMap getParameters = parametersFromObject(parameters);
            return get(AschServiceUrls.Transaction.QUERY_TRANSACTIONS, getParameters);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult getTransaction(String transactionId) {
        try {
            Argument.require(Validation.isValidTransactionId(transactionId), "invalid transaction id");

            ParameterMap parameters = new ParameterMap().put("id", transactionId);
            return get(AschServiceUrls.Transaction.GET_TRANSACTION, parameters);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult getUnconfirmedTransaction(String unconfirmedTransactionId){
        try {
            Argument.require(Validation.isValidTransactionId(unconfirmedTransactionId), "invalid transaction id");

            ParameterMap parameters = new ParameterMap()
                    .put("id", unconfirmedTransactionId);
            return get(AschServiceUrls.Transaction.GET_UNCONFIRMED_TRANSACTION, parameters);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult getUnconfirmedTransactions(String senderPublicKey, String address) {
        try {
            Argument.optional(senderPublicKey, Validation::isValidPublicKey, "invalid senderPublicKey");
            Argument.optional(address, Validation::isValidAddress, "invalid address");

            ParameterMap parameters = new ParameterMap()
                    .put("senderPublicKey", senderPublicKey)
                    .put("address", address);

            return get(AschServiceUrls.Transaction.GET_UNCONFIRMED_TRANSACTIONS, parameters);
        } catch (Exception ex) {
            return fail(ex);
        }
    }

    @Override
    public AschResult addTransaction(String secret, int amount, String recipientId, String senderPublicKey, String secondSecret, String multiSignAccountPublicKey) {
        try {
            Argument.require(Validation.isValidSecret(secret), "invalid secret");
            Argument.require(Validation.isValidSecondSecret(secondSecret), "invalid secondSecret");
            Argument.require(Validation.isValidAmount(amount), "invalid amount");
            Argument.require(Validation.isValidPublicKey(senderPublicKey), "invalid senderPublicKey");
            Argument.optional(multiSignAccountPublicKey, Validation::isValidPublicKey, "invalid multiSignAccountPublicKey");

            ParameterMap parameters = new ParameterMap()
                    .put("secret", secret)
                    .put("amount", amount)
                    .put("recipientId", recipientId)
                    .put("secondSecret", secondSecret)
                    .put("senderPublicKey", senderPublicKey)
                    .put("multisigAccountPublicKey", multiSignAccountPublicKey);

            return post(AschServiceUrls.Transaction.CREATE_TRANSACTION, parameters);
        } catch (Exception ex) {
            return fail(ex);
        }
    }
}


<|start_filename|>src/so/asch/sdk/transaction/asset/DappAssetInfo.java<|end_filename|>
package so.asch.sdk.transaction.asset;

public class DappAssetInfo {
}


<|start_filename|>src/so/asch/sdk/AschSecret.java<|end_filename|>
package so.asch.sdk;

public interface AschSecret {

    enum SecondSecretState{
        Required,
        Needless,
        Unknow
    }

    String getPublicKey();
    String getSecondPublicKey();
    boolean isSecretPresented();
    boolean isSecondSecretPresented();
    SecondSecretState getSecondSecretState();
    byte[] sign(byte[] content);
    byte[] secondSign(byte[] content);
}


<|start_filename|>src/so/asch/sdk/impl/BlockService.java<|end_filename|>
package so.asch.sdk.impl;


import so.asch.sdk.AschResult;
import so.asch.sdk.Block;
import so.asch.sdk.dbc.Argument;
import so.asch.sdk.dto.query.BlockQueryParameters;

public class BlockService extends AschRESTService implements Block {
    @Override
    public AschResult getBlockById(String id, boolean fullBlockInfo) {
        try {
            Argument.notNull(id, "id is null");

            ParameterMap parameters = new ParameterMap().put("id", id);
            String url = fullBlockInfo ?
                    AschServiceUrls.Block.GET_FULL_BLOCK_INFO:
                    AschServiceUrls.Block.GET_BLOCK_INFO ;
            return get(url, parameters);
        } catch (Exception ex) {
            return fail(ex);
        }
    }

    @Override
    public AschResult getBlockByHeight(long height, boolean fullBlockInfo) {
        ParameterMap parameters = new ParameterMap().put("height", height);
        String url = fullBlockInfo ?
                AschServiceUrls.Block.GET_FULL_BLOCK_INFO:
                AschServiceUrls.Block.GET_BLOCK_INFO ;
        return get(url, parameters);
    }

    @Override
    public AschResult getBlockByHash(String hash, boolean fullBlockInfo) {
        try {
            Argument.notNull(hash, "hash is null");

            ParameterMap parameters = new ParameterMap().put("hash", hash);
            String url = fullBlockInfo ?
                    AschServiceUrls.Block.GET_FULL_BLOCK_INFO :
                    AschServiceUrls.Block.GET_BLOCK_INFO;
            return get(url, parameters);
        } catch (Exception ex) {
            return fail(ex);
        }
    }


    @Override
    public AschResult queryBlocks(BlockQueryParameters parameters) {
        try {
            //Argument.require(Validation.isValidBlockQueryParameters(parameters), "invalid parameters");

            ParameterMap query = parametersFromObject(parameters);
            return get(AschServiceUrls.Block.QUERY_BLOCKS,  query);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult getHeight() {
        return get(AschServiceUrls.Block.GET_HEIGHT);
    }

    @Override
    public AschResult getFree() {
        return get(AschServiceUrls.Block.GET_FREE);
    }

    @Override
    public AschResult getMilestone() {
        return get(AschServiceUrls.Block.GET_MILESTONE);
    }

    @Override
    public AschResult getReward() {
        return get(AschServiceUrls.Block.GET_REWARD);
    }

    @Override
    public AschResult getSupply() {
        return get(AschServiceUrls.Block.GET_SUPPLY);
    }


    @Override
    public AschResult getStauts() {
        return get(AschServiceUrls.Block.GET_STATUS);
    }
}


<|start_filename|>src/so/asch/sdk/impl/DelegateService.java<|end_filename|>
package so.asch.sdk.impl;

import so.asch.sdk.AschResult;
import so.asch.sdk.Delegate;
import so.asch.sdk.dbc.Argument;
import so.asch.sdk.dto.query.DelegateQueryParameters;
import so.asch.sdk.transaction.TransactionInfo;

public class DelegateService extends AschRESTService implements Delegate {

    @Override
    public AschResult getDelegatesCount() {
        return get(AschServiceUrls.Delegate.GET_DELEGATES_COUNT);
    }

    @Override
    public AschResult getVoters(String publicKey) {
        return getByPublicKey(AschServiceUrls.Delegate.GET_VOTES, publicKey);
    }

    @Override
    public AschResult getDelegateByPublicKey(String publicKey) {
        return getByPublicKey(AschServiceUrls.Delegate.GET_DELEGATE, publicKey);
    }

    @Override
    public AschResult getDelegateByName(String userName){
        try {
            Argument.notNull(userName, "invalid user name");

            ParameterMap parameters = new ParameterMap().put("username", userName);
            return get(AschServiceUrls.Delegate.GET_DELEGATE, parameters);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult queryDelegates( DelegateQueryParameters parameters) {
        try {
            Argument.require(Validation.isValidDelegateQueryParameters(parameters), "invalid parameters");

            ParameterMap query = parametersFromObject(parameters);
            return get(AschServiceUrls.Delegate.QUERY_DELEGATES,  query);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult getDelegateFee(String publicKey){
        return getByPublicKey(AschServiceUrls.Delegate.GET_DELEGATE_FEE, publicKey);
    }

    @Override
    public AschResult getForging(String publicKey) {
        return getByPublicKey(AschServiceUrls.Delegate.GET_FORGING, publicKey);
    }

    @Override
    public AschResult registerDelegate(String userName, String secret, String secondSecret ) {
        try {
            Argument.notNull(userName, "invalid username");
            Argument.require(Validation.isValidSecret(secret), "invalid secret");
            Argument.optional(secondSecret, Validation::isValidSecondSecret, "invalid secondSecret");

            TransactionInfo transaction = getTransactionBuilder().buildDelegate(userName, secret, secondSecret);
            return broadcastTransaction(transaction);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    /**
    *    enableForge和disableForge接口不知接口地址，待确认
    * */
    @Override
    public AschResult enableForge( String publicKey, String secret ) {

        return null;
    }

    @Override
    public AschResult disableForge(String publicKey, String secret ) {
        return null;
    }

    @Override
    public AschResult getForgingStatus(String publicKey) {
        return getByPublicKey(AschServiceUrls.Delegate.GET_FORGING_STATUS, publicKey);
    }
}


<|start_filename|>test/so/asch/sdk/impl/TransactionServiceTest.java<|end_filename|>
package so.asch.sdk.impl;

import org.testng.Assert;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.Test;

import so.asch.sdk.AschResult;
import so.asch.sdk.AschSDK;
import so.asch.sdk.TestData;
import so.asch.sdk.TransactionType;
import so.asch.sdk.dto.query.QueryParameters;
import so.asch.sdk.dto.query.TransactionQueryParameters;

/**
 * @author fisher
 * @version $Id: TransactionServiceTest.java, v 0.1 2017/8/7 15:16 fisher Exp $
 */
public class TransactionServiceTest {
    @BeforeSuite
    public void SetUp(){
        AschSDK.Config.setAschServer(TestData.root);
    }

    @Test
    public void testQueryTransactionsEmpty() throws Exception {
        TransactionQueryParameters parameters = new TransactionQueryParameters();
        AschResult result = AschSDK.Transaction.queryTransactions(parameters);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testQueryTransactionsByBlockId() throws Exception {
        TransactionQueryParameters parameters = new TransactionQueryParameters();
        parameters.setBlockId("0dc51ce12b5a58f206f15cb546a29375c30e7cfce31f95fa9244133fc894ea33");
        AschResult result = AschSDK.Transaction.queryTransactions(parameters);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testQueryTransactionsByLimit()throws Exception{
        TransactionQueryParameters parameters = new TransactionQueryParameters();
        parameters.setLimit(10);
        AschResult result = AschSDK.Transaction.queryTransactions(parameters);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testQueryTransactionsByType()throws Exception{
        TransactionQueryParameters parameters = new TransactionQueryParameters();
        parameters.setTransactionType(TransactionType.Transfer);
        AschResult result = AschSDK.Transaction.queryTransactions(parameters);
        Assert.assertTrue(result.isSuccessful());
    }
    @Test
    // TODO: 2017/8/8 orderBy condition error
    public void testQueryTransactionsByOffset()throws Exception{
        TransactionQueryParameters parameters = new TransactionQueryParameters();
        parameters.setOffset(0);
        parameters.setOrderBy("amount", QueryParameters.SortOrder.DESC);
        AschResult result = AschSDK.Transaction.queryTransactions(parameters);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testQueryTransactionsBySendPublicKey()throws Exception{
        TransactionQueryParameters parameters = new TransactionQueryParameters();
        parameters.setSenderPublicKey("df4fbcc996be9834a70fc58e30d42b3febc289277a004632f91a54c4e8b39ced");
        AschResult result = AschSDK.Transaction.queryTransactions(parameters);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testQueryTransactionsByOwnPublicKey()throws Exception{
        TransactionQueryParameters parameters = new TransactionQueryParameters();
        parameters.setOwnerPublicKey("df4fbcc996be9834a70fc58e30d42b3febc289277a004632f91a54c4e8b39ced");
        AschResult result = AschSDK.Transaction.queryTransactions(parameters);
        Assert.assertTrue(result.isSuccessful());
    }

    // TODO: 2017/8/8 test error 
    @Test
    public void testQueryTransactionsByOwnerAddress()throws Exception{
        TransactionQueryParameters parameters = new TransactionQueryParameters();
        parameters.setOwnerAddress("4516770862894053894");
        AschResult result = AschSDK.Transaction.queryTransactions(parameters);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testQueryTransactionsBySenderId()throws Exception{
        TransactionQueryParameters parameters = new TransactionQueryParameters();
        parameters.setSenderId("16502644983291819723");
        AschResult result = AschSDK.Transaction.queryTransactions(parameters);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testQueryTransactionsByRecipientId()throws Exception{
        TransactionQueryParameters parameters = new TransactionQueryParameters();
        parameters.setRecipientId("14762548536863074694");
        AschResult result = AschSDK.Transaction.queryTransactions(parameters);
        Assert.assertTrue(result.isSuccessful());
    }

    // TODO: 2017/8/9 ambiguous condition (amount,fee)
    @Test
    public void testQueryTransactionsByAmount()throws Exception{
        TransactionQueryParameters parameters = new TransactionQueryParameters();
        parameters.setAmount(100L);
        AschResult result = AschSDK.Transaction.queryTransactions(parameters);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testGetTransactions()throws Exception{
        AschResult result = AschSDK.Transaction.getTransaction(TestData.transactionId);
        Assert.assertTrue(result.isSuccessful());
    }

    // TODO: 2017/8/9 The time is too short for testing unconfirm transaction.
    @Test
    public void testGetUnconfirmedTransaction()throws Exception{
        AschResult result =AschSDK.Transaction.getUnconfirmedTransaction(TestData.transactionId);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testGetUnconfirmedTransactions()throws Exception{
        AschResult result =AschSDK.Transaction.getUnconfirmedTransactions(null, null);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testGetUnconfirmedTransactionsByConditions()throws Exception{
        AschResult result = AschSDK.Transaction.getUnconfirmedTransactions("df4fbcc996be9834a70fc58e30d42b3febc289277a004632f91a54c4e8b39ced","ACsJqgmPRjoHm6fb3EswuWoaxu4KRAjv4R");
        Assert.assertTrue(result.isSuccessful());
    }

    // TODO: 2017/8/14 interface not found 
    @Test
    public void testAddTransaction()throws Exception{
        AschResult result =  AschSDK.Transaction.addTransaction(TestData.secret,
                1,"APS3jUBQ<KEY>",TestData.senderPublicKey,
                TestData.secondSecret,null);
        Assert.assertTrue(result.isSuccessful());
    }
}


<|start_filename|>src/so/asch/sdk/Block.java<|end_filename|>
package so.asch.sdk;

import so.asch.sdk.dto.query.BlockQueryParameters;

/**
 * Asch区块接口
 * @author eagle
 * 参见 https://github.com/AschPlatform/asch-docs/blob/master/asch_http_interface.md#23-%E5%8C%BA%E5%9D%97blocks
 */
public interface Block extends AschInterface {
    //接口地址：/api/blocks/get
    //请求方式：get
    //支持格式：urlencoded
    //请求参数说明：
    //id	string	参数3选1	区块id
    //height	string	参数3选1	区块高度
    //hash	string	参数3选1	区块hash
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //block	json	区块详情
    AschResult getBlockById(String id, boolean fullBlockInfo);
    AschResult getBlockByHeight(long height, boolean fullBlockInfo);
    AschResult getBlockByHash(String hash, boolean fullBlockInfo);


    //接口地址：/api/blocks
    //请求方式：get
    //支持格式：urlencoded
    //接口说明：不加参数则获取全网区块详情
    //请求参数说明：
    //limit	integer	N	限制结果集个数，最小值：0,最大值：100
    //orderBy	string	N	根据表中字段排序，如height:desc
    //offset	integer	N	偏移量，最小值0
    //generatorPublicKey	string	N	区块生成者公钥
    //totalAmount	integer	N	交易总额，最小值：0，最大值：10000000000000000
    //totalFee	integer	N	手续费总额，最小值：0，最大值：10000000000000000
    //reward	integer	N	奖励金额，最小值：0
    //previousBlock	string	N	上一个区块
    //height	integer	N	区块高度
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //blocks	Array	由区块详情json串构成的数组
    //count	integer	区块链高度
    AschResult queryBlocks(BlockQueryParameters parameters);

    //接口地址：/api/blocks/getHeight
    //请求方式：get
    //支持格式：无
    //请求参数说明：无
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //height	integer	区块链高度
    AschResult getHeight();

    //接口地址：/api/blocks/getFee
    //接口说明： 获取交易手续费
    //请求方式：get
    //支持格式：无
    //请求参数说明：无
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //milestone	integer	交易手续费
    AschResult getFree();

    //接口地址：/api/blocks/getMilestone
    //接口说明：获取里程碑
    //请求方式：get
    //支持格式：无
    //请求参数说明：无
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //milestone	integer	里程碑
    AschResult getMilestone();

    //接口地址：/api/blocks/getReward
    //接口说明：获取单个区块奖励
    //请求方式：get
    //支持格式：无
    //请求参数说明：无
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //reward	integer	区块奖励
    AschResult getReward();

    //接口地址：/api/blocks/getSupply
    //接口说明：获取区块链当前最大供应值
    //请求方式：get
    //支持格式：无
    //请求参数说明：无
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //supply	integer	全网XAS个数
    AschResult getSupply();


    //接口地址：/api/blocks/getStatus
    //请求方式：get
    //支持格式：无
    //请求参数说明：无
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //height	integer	区块链高度
    //fee	integer	交易手续费
    //milestone	integer
    //reward	integer	区块奖励
    //supply	integer	全网XAS个数
    AschResult getStauts();

}


<|start_filename|>src/so/asch/sdk/Main.java<|end_filename|>
package so.asch.sdk;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.LoggerContext;
import so.asch.sdk.dto.query.TransactionQueryParameters;
import so.asch.sdk.impl.Validation;

import java.util.List;
import java.util.Map;


public class Main {

    public static void main(String[] args) {
        try {

            //如果不需要在控制台查看HTTP通讯细节，可以把下面这行代码注释掉。
            initLog();

            String url = "http://127.0.0.1:4096";
            String secret = "early sugar cannon mansion expose tunnel piece manual destroy exhaust helmet rather";
            String address = "7286541193277597873";
            String secondSecret = "asch111111";
            String userName = "asch_g2";

            //String secret2 = "raise cloud royal wonder cradle job gate wife depth device bitter hope";
            //asch_g101	11705168753296944226 00dd0e70fe22e9b580ba0ccf696f1d108a6475bb303b8689947ba346b0b02ad9
            //asch_g96	16093201530526106149 0225c340addf24211f4b51ea24cb0565c67f09600f57bad89af350b38b08a366
            //asch_g32	4354832300657989346 0ae2e3bcd8c959bccc34445a9473eab1bece60300f3aa00d89612923470dee75
            String[] voted = "00dd0e70fe22e9b580ba0ccf696f1d108a6475bb303b8689947ba346b0b02ad9,0225c340addf24211f4b51ea24cb0565c67f09600f57bad89af350b38b08a366,0ae2e3bcd8c959bccc34445a9473eab1bece60300f3aa00d89612923470dee75".split(",");

            //asch_g23	4752137788839516181 486179424b4bcfaf7960a4a121277d73e4a7c9e0c27b254edf978762d5a6dfe6
            //asch_g40	16494449392359591122 49b369ff2635e2ac083d62a6c59baf872fbdef6990297f296c95e1830118aba1
            String[] canceled = "486179424b4bcfaf7960a4a121277d73e4a7c9e0c27b254edf978762d5a6dfe6,49b369ff2635e2ac083d62a6c59baf872fbdef6990297f296c95e1830118aba1".split(",");
            String publicKey = AschSDK.Helper.getPublicKey(secret);

//            long lastCheckedBlockHeight = 0;
//
//
//            //设置Asch服务地址
//            AschSDK.Config.setAschServer(url);
//            //设置成对应的网络Magic值
//            AschSDK.Config.setMagic("5f5b3cf5");
//
//
//            //生成10个一级密钥（账户）
//            for( int i=0; i<10; i++) {
//                String newSecret = AschSDK.Helper.generateSecret();
//                System.out.println(newSecret);
//            }
//
//            //登录
//            AschResult result = AschSDK.Account.secureLogin(secret);
//            System.out.println(result.getRawJson());
//            if(result.isSuccessful()){
//                Map<String,Object> accountMap = (Map<String,Object>)result.parseMap().get("account");
//                String accountPublicKey = AschSDK.Helper.getPublicKey(secret);
//                String accountAddress = accountMap.get("address").toString();
//                BigDecimal balance = BigDecimal.valueOf(Long.parseLong(accountMap.get("balance").toString()), 8);
//
//                System.out.println(String.format("登录成功, publicKey:%s, address:%s, XAS余额：%s", accountPublicKey, accountAddress, balance.toString()));
//            }
//
//            //转账(金额为1XAS)
//            result = AschSDK.Account.transfer("11705168753296944226",
//                    AschSDK.Helper.amountForXAS(BigDecimal.valueOf(1)),
//                    //"Transfer by Test"
//                    "  ", secret, secondSecret);
//            System.out.println(result.getRawJson());
//            if(result.isSuccessful()){
//                String transactionId = result.parseMap().get("transactionId").toString();
//                System.out.println("交易成功,transaction id：" + transactionId);
//
//                int retry = 10 ;
//                do {
//                    //查询单条交易，注意：刚完成的交易查不到，正常情况需要1s-10s不等。建议多等一段时间。
//                    result = AschSDK.Transaction.getTransaction(transactionId);
//                    if (!result.isSuccessful())
//                    {
//                        System.out.println("查询交易失败或未查询到交易信息，3秒后重试...");
//                        Thread.sleep(3000);
//                    }
//                    else
//                    {
//                        Map<String,Object> transactionMap = (Map<String,Object>)result.parseMap().get("transaction");
//                        long blockHeight = Integer.parseInt(transactionMap.get("height").toString());
//                        String blockId = transactionMap.get("blockId").toString();
//                        TransactionType type = TransactionType.fromCode(Integer.parseInt(transactionMap.get("type").toString()));
//                        Date time = AschSDK.Helper.dateFromAschTimestamp(Integer.parseInt(transactionMap.get("type").toString()));
//                        String senderPublicKey = transactionMap.get("senderPublicKey").toString();
//                        String senderId = transactionMap.get("senderId").toString();
//                        String recipientId = transactionMap.get("recipientId").toString();
//                        BigDecimal xasAmount = BigDecimal.valueOf(Long.parseLong(transactionMap.get("amount").toString()), 8);
//                        BigDecimal fee = BigDecimal.valueOf(Long.parseLong(transactionMap.get("fee").toString()), 8);
//                        //确认数，一般认为确认数达到6就可以认为交易已经成功了。。
//                        int confirmations = Integer.parseInt(transactionMap.get("confirmations").toString());
//
//                        String transactionInfo = String.format("block height:%d,\n block id:%s,\n transaction type:%s,\n " +
//                                "time:%s,\n sender public key:%s,\n sender id:%s,\n recipient id:%s,\n XAS amount:%s,\n fee:%s,\n confirmations:%d ",
//                                blockHeight, blockId, type.getCode(), time.toString(), senderPublicKey, senderId, recipientId,
//                                xasAmount.toString(), fee.toString(), confirmations);
//                        System.out.println("查询交易成功，交易信息：\n" +transactionInfo);
//                    }
//
//                }while(!result.isSuccessful() && retry-- > 0);
//
//            }
//
//            //查询交易transaction
//            TransactionQueryParameters parameters = new TransactionQueryParameters()
//                    .setRecipientId("21705168753296944226")
//                    .setLimit(10)
//                    .orderByAscending("t_timestamp");
//            result = AschSDK.Transaction.queryTransactions(parameters);
//            System.out.println(result.getRawJson());
//
//            //这个值建议保存到数据库中，每次接着上次检查的块后开始。
//            //下面的代码建议放到线程中循环执行，两次调用可间隔一段时间。
//            long currentHeight = 0;
//            result = AschSDK.Block.getHeight(); /*监控系统产生的当前最新区块信息*/
//            if (result.isSuccessful()){
//                currentHeight = Long.parseLong(result.parseMap().get("height").toString());
//                if (currentHeight > lastCheckedBlockHeight++){
//                    //枚举区块中的所有交易，判断是否有接收人为自己的交易
//                    handleBlockTransactions(lastCheckedBlockHeight);
//                }
//            }

            String base58Address = "APSr4a1W5hnyqvAeu95xcYnTM6g1GEGGXr";
            System.out.println(Validation.isValidAddress(base58Address));
       }
        catch (Exception ex){
            System.out.println(ex.getMessage());

        }
    }

    private static boolean handleBlockTransactions(long height){
        AschResult result = AschSDK.Block.getBlockByHeight(height, false);
        if (!result.isSuccessful()){
            return false;
        }

        Map<String,Object> block = ( Map<String,Object>) result.parseMap().get("block");
        int numberOftransactions = (int)block.get("numberOfTransactions");
        if (numberOftransactions == 0) {
            return true;
        }

        String blockId = block.get("id").toString();
        result = AschSDK.Transaction.queryTransactions(new TransactionQueryParameters().setBlockId(blockId));
        if (!result.isSuccessful()){
            return false;
        }

        List<Map<String, Object>> transactions = (List<Map<String, Object>>)result.parseMap().get("transactions");
        for (Map<String, Object> trans : transactions) {
            String recipientId = trans.get("recipientId").toString();
            if (recipientId == "自己平台的地址"){
                //TODO:处理自己的交易，交易信息结构请参考：
                /*
                {
                    "id": "5a61b58b75a70a42a6d51deba4dba560c78b2d671dfac68d37984eb464421d81", // 交易id
                    "height": "3183940",    //区块高度
                    "blockId": "951e14ef5100a9724a133f74e8f5c35e0d872aee654e7ea5323e57cd1c7b004e",  //区块id
                    "type": 0, // 交易类型，0：普通转账
                    "timestamp": 36252686,  // 交易时间戳，Asch时间，可以换算成现实世界的时间
                    "senderPublicKey": "<KEY>",
                    "senderId": "AC4i4srjg1TyW24p8M4B8NTcYApUgvTpkd",   // 发送地址
                    "recipientId": "ALu3f2GaGrWzG4iczamDmGKr4YsbMFCdxB", // 接收地址,如果是平台地址，则需要做处理
                    "amount": 80000000, //转账金额，除以100000000后是真实的XAS个数，这里0.8XAS
                    "fee": 10000000,
                    "signature": "08a97ba29f7db324b31f782272e17c048f4b99d1761830bd7f541c484c28fcf14b1ee0dbbdd05ab2e80d186473e67d9bfed8e27b8c5e096d29a7f521236d8900",
                    "signSignature": "",
                    "signatures": null,
                    "confirmations": "20",  // 区块确认数
                    "args": [],
                    "message": "",  // 转账备注
                    "asset": {
                    }
                }
                * */
            }
        }

        return true;
    }

    protected static void initLog(){

        if (AschSDK.Config.isDebugMode()) {
            final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
            ctx.getConfiguration()
                    .getRootLogger()
                    .setLevel(Level.ALL);
        }
    }

}


<|start_filename|>src/so/asch/sdk/impl/AschServiceUrls.java<|end_filename|>
package so.asch.sdk.impl;

public final class AschServiceUrls {
     final static class Account {
        static final String LOGIN ="/api/accounts/open";
        static final String SECURE_LOGIN ="/api/accounts/open2";
        static final String GET_ACCOUNT ="/api/accounts";
        static final String GET_BALANCE ="/api/accounts/getBalance";
        static final String GET_PUBLIC_KEY ="/api/accounts/getPublickey";
        static final String GENERATE_PUBLIC_KEY ="/api/accounts/generatePublicKey";
        static final String GET_VOTED_DELEGATES ="/api/accounts/delegates";
        static final String GET_DELEGATE_FEE ="/api/accounts/delegates/fee";
        static final String GET_TOP_ACCOUNTS ="/api/accounts/top";
    }

    final static class Delegate{
        static final String GET_DELEGATES_COUNT ="/api/delegates/count";
        static final String GET_VOTES ="/api/delegates/voters";
        static final String GET_DELEGATE ="/api/delegates/get";
        static final String QUERY_DELEGATES ="/api/delegates";
        static final String GET_DELEGATE_FEE ="/api/delegates/fee";
        static final String GET_FORGING = "/api/delegates/forging/getForgedByAccount";
        static final String ENABLE_FORGE = "/api/delegates/forging/enable";
        static final String DISABLE_FORGE = "/api/delegates/forging/disable";
        static final String GET_FORGING_STATUS ="/api/delegates/forging/status";
    }

    final static class Block{
        static final String GET_BLOCK_INFO = "/api/blocks/get";
        static final String GET_FULL_BLOCK_INFO = "/api/blocks/full";
        static final String QUERY_BLOCKS = "/api/blocks/";
        static final String GET_HEIGHT = "/api/blocks/getHeight";
        static final String GET_FREE="/api/blocks/getFee";
        static final String GET_MILESTONE = "/api/blocks/getMilestone";
        static final String GET_REWARD = "/api/blocks/getReward";
        static final String GET_SUPPLY = "/api/blocks/getSupply";
        static final String GET_STATUS = "/api/blocks/getStatus";

    }

    final static class Transaction{
        static final String QUERY_TRANSACTIONS = "/api/transactions";
        static final String GET_TRANSACTION = "/api/transactions/get";
        static final String GET_UNCONFIRMED_TRANSACTION = "/api/transactions/unconfirmed/get";
        static final String GET_UNCONFIRMED_TRANSACTIONS = "/api/transactions/unconfirmed";
        static final String CREATE_TRANSACTION = "/api/transactions";
    }

    final static class Peer{
        static final String BROADCAST_TRANSACTION = "/peer/transactions";
        static final String QUERY_PEERS = "/api/peer/getPeers";
        static final String GET_PEER = "/api/peer/get";
        static final String GET_VERSION = "/api/peer/version";
    }

    final static class Signature{
        static final String GET_SIGNATURE_FEE = "/api/signatures/fee";
        //static final String SET_SIGNATURE = "/api/signatures";

        //static final String SET_MULTI_SIGNATURE = "/api/multisignatures/addMultisignature";
        static final String MULTI_SIGNATURE = "/api/multisignatures/sign";
        static final String GET_PENDING_TRANSACTIONS = "/api/multisignatures/pending";
        static final String GET_MULTI_SIGNATURE_ACCOUNTS = "/api/multisignatures/getAccounts";
    }

    final static class Misc{
        static final String  GET_LOAD_STATUS ="/api/loader/status";
        static final String  GET_SYNC_STATUS ="/api/loader/status/sync";
        static final String  GET_STORED_DATA ="/api/storages";
        //static final String  GET_LOAD_STATUS ="";
    }

    final static class UIA{
        static final String GET_ISSUERS = "/api/uia/issuers";
        static final String GET_ISSUER = "/api/uia/issuers/{0}";
        static final String QUERY_ISSUER_ASSETS = "/api/uia/issuers/{0}/assets";
        static final String GET_ASSETS = "/api/uia/assets";
        static final String GET_ASSET= "/api/uia/assets/{0}";
        static final String GET＿ASSET＿ACL = "/api/uia/assets/{0}/acl/flag";
        static final String GET_ADDRESS_BALANCES = "/api/uia/balances/";
        static final String GET_TRANSACTIONS = "/api/uia/transactions";
    }

    final static class Dapp{
         static final String GET_BLOCKS_HEIGHT = "/api/dapps/{0}/blocks/height";
         static final String GET_BLOCKS = "/api/dapps/{0}/blocks";
         static final String GET_ACCOUNT = "/api/dapps/{0}/accounts/{1}";
    }

}


<|start_filename|>src/so/asch/sdk/impl/DappService.java<|end_filename|>
package so.asch.sdk.impl;

import so.asch.sdk.AschResult;
import so.asch.sdk.Dapp;
import so.asch.sdk.dbc.Argument;
import so.asch.sdk.dbc.ContractException;
import so.asch.sdk.dto.query.DappQureyParameters;
import so.asch.sdk.transaction.TransactionInfo;

import java.text.MessageFormat;

public class DappService extends AschRESTService implements Dapp {
    @Override
    public AschResult getBlocksHeight(String dappId) {
        try {
            Argument.notNull(dappId, "dappId is null");
            return get(MessageFormat.format(AschServiceUrls.Dapp.GET_BLOCKS_HEIGHT, dappId));
        } catch (Exception ex) {
            return fail(ex);
        }
    }

    @Override
    public AschResult getBlocks(String dappId, DappQureyParameters parameters) {
        try {
            Argument.notNull(dappId, "dappId is null");
            ParameterMap query = parametersFromObject(parameters);
            return get(MessageFormat.format(AschServiceUrls.Dapp.GET_BLOCKS, dappId),  query);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult getAccount(String dappId,String address) {
        try {
            Argument.notNull(dappId, "dappId is null");
            return get(MessageFormat.format(AschServiceUrls.Dapp.GET_ACCOUNT,dappId,address));
        } catch (ContractException ex) {
            return fail(ex);
        }
    }

    @Override
    public AschResult dappDeposit(String dappId, String currency, long amount, String secret, String secondSecret) {
        try {
            Argument.notNull(dappId, "dappId is null");
            Argument.require(Validation.isValidSecret(secret), "invalid secret");
            Argument.optional(secondSecret, Validation::isValidSecondSecret, "invalid second secret");
            TransactionInfo transaction = getTransactionBuilder()
                    .buildInTransfer(dappId, currency,amount, secret, secondSecret);
            return broadcastTransaction(transaction);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

}


<|start_filename|>src/so/asch/sdk/Signature.java<|end_filename|>
package so.asch.sdk;

/**
 * Asch签名接口
 * @author eagle
 * 参见 https://github.com/AschPlatform/asch-docs/blob/master/asch_http_interface.md#27-%E4%BA%8C%E7%BA%A7%E5%AF%86%E7%A0%81signatures
 *     https://github.com/AschPlatform/asch-docs/blob/master/asch_http_interface.md#28-%E5%A4%9A%E9%87%8D%E7%AD%BE%E5%90%8Dmultisignatures
 */
public interface Signature extends AschInterface{

    //设置二级密码
    //接口地址：/api/signatures
    //请求方式：put
    //支持格式：json
    //请求参数说明：
    //secret	string	Y	asch账户密码
    //publicKey	string	N	公钥
    //secondSecret	string	Y	asch账户二级密码，最小长度：1，最大长度：100
    //multisigAccountPublicKey	string	N	多重签名账户公钥
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //transaction	json	设置二级密码产生的交易详情
    AschResult setSignature(String secret, String secondSecret, String publicKey, String multiSignAccountPublicKey);

    //获取二级密码设置费
    //接口地址：/api/signatures/fee
    //请求方式：get
    //支持格式：无
    //请求参数说明：无
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //fee	integer	费用
    AschResult getSignatureFee();


    //设置普通账户为多重签名账户
    //接口地址：/api/multisignatures
    //请求方式：put
    //支持格式：json
    //接口说明：返回结果只是生成交易id，还需要其他人签名后该账户才能成功设置成多重签名账户。注册多重签名账户后任意一笔转账都需要多人签名，
    // 签名最少个数为min的值（含交易发起人自身）
    //请求参数说明：
    //secret	string	Y	asch账户密码
    //publicKey	string	N	公钥
    //secondSecret	string	N	asch账户二级密码，最小长度：1，最大长度：100
    //min	integer	Y	多重签名交易账户的任意一笔转账都需要多人签名的最少个数，如果是注册多重签名账户操作，这该值不生效（此时需要所有人都签名）。
    //                  最小值：2，最大值：16,该值需要小于keysgroup.length+1
    //lifetime	integer	Y	多重签名交易的最大挂起时间，最小值：1，最大值：24，暂时不生效
    //keysgroup	array	Y	其它签名人的公钥数组，每个公钥前需要加上+或者-号，代表增加/删除多重签名账户，数组最小长度：1，数组最大长度：10
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //transactionId	string	多重签名交易的id
    AschResult setMultiSignature(int minAccount, int lifetime, String[] addKeys, String[] removeKeys,
                                  String secret, String secondSecret, String publicKey);

    //非交易发起人对交易进行多重签名
    //接口地址：/api/multisignatures/sign
    //请求方式：post
    //支持格式：json
    //请求参数说明：
    //secret	string	Y	asch账户密码
    //secondSecret	string	N	asch账户二级密码，最小长度：1，最大长度：100
    //publicKey	string	N	公钥
    //transactionId	string	Y	交易id
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //transactionId	string	多重签名交易id
    AschResult multiSignature(String transactionId, String secret, String secondSecret, String publicKey );

    //获取挂起的多重签名交易详情
    //接口地址：/api/multisignatures/pending
    //请求方式：get
    //支持格式：urlencoded
    //请求参数说明：
    //publicKey	string	Y	公钥
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //transactions	Array	交易json组成的数组
    AschResult getPendingTransactions(String publicKey);

    //获取多重签名账户信息
    //接口地址：/api/multisignatures/accounts
    //请求方式：get
    //支持格式：urlencoded
    //请求参数说明：
    //publicKey	string	Y	多重签名参与者之一的公钥
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //accounts	Array	多重签名账户详情
    AschResult getMultiSignatureAccounts(String publicKey);

}


<|start_filename|>src/so/asch/sdk/impl/Validation.java<|end_filename|>
package so.asch.sdk.impl;


import so.asch.sdk.ContentEncoding;
import so.asch.sdk.dto.query.*;
import so.asch.sdk.security.Bip39;

import java.util.HashSet;
import java.util.function.Predicate;

/**
 * Created by eagle on 17-7-18.
 */
public class Validation {
    private static final int MIN_SECURE_LENGTH = 1;
    private static final int MAX_SECURE_LENGTH = 100;
    private static final int MIN_ADDRESS_LENGTH = 10;
    private static final int MAX_ADDRESS_LENGTH = 64;
    private static final int PUBLIC_KEY_LENGTH = 32;

    private static final String HEX_PATTERN = "^([0-9]|[A-F]|[a-f])+$";
    private static final String NUMBER_PATTERN = "^\\d+$";
    private static final String BASE58_PATTERN = "^([1-9]|[A-H]|[J-Z]|[a-k]|[m-z])+$";
    private static final String BASE64_PATTERN = "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$";
    private static final String IP_PATTERN =
            "^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\."
            +"(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."
            +"(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\."
            +"(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)$";

    public static boolean isHex(String hexString){
        return  (null != hexString) && hexString.matches(HEX_PATTERN);
    }

    public static boolean isValidSecret(String secret) {
        return secret != null &&
                Bip39.isValidMnemonicCode(secret);
    }

    public static boolean isValidSecondSecret(String secure) {
        return secure != null &&
                (secure.length() >= MIN_SECURE_LENGTH && secure.length()<= MAX_SECURE_LENGTH) ;
    }

    public static boolean isValidPublicKey(String publicKey){
        return publicKey != null &&
                publicKey.length() == PUBLIC_KEY_LENGTH * 2 &&
                isHex(publicKey);
    }

    public static boolean isValidAddress(String address){
        return  address != null &&
                ( address.length() >= MIN_ADDRESS_LENGTH && address.length() <= MAX_ADDRESS_LENGTH) &&
                ( address.matches(NUMBER_PATTERN) ||
                        ( address.matches(BASE58_PATTERN) && AschFactory.getInstance().getSecurity().isValidBase58Address(address))
                );
    }

    public static boolean isValidAmount(int amount){
        //TODO:validate amount
        return amount > 0 && amount <100000000;
    }

    public static boolean isValidTransactionId(String transactionId){
        //TODO:validate transaction id
        return transactionId != null;
    }

    public static boolean isValidLimit(Integer limit){
        return limit == null || (limit >= 1 && limit <=100);
    }

    public static boolean isValidOffset(int offset){
        return  offset >= 0;
    }

    public static boolean isValidIP(String ip){
        return ip != null && ip.matches(IP_PATTERN);
    }

    public static boolean isValidPort(int port){
        return port >0 && port <=65535;
    }

    public static boolean isValidMultiSignatureMinAccount(int minAccount){
        return minAccount>=2 && minAccount <=16;
    }

    public static boolean isValidMultiSignatureLifetime(int lifetime){
        return lifetime>=1 && lifetime <=72;
    }

    public static boolean isValidWait(int wait){
        return wait >= 0 && wait<= 6;
    }

    public static boolean isValidVoteKeys(String[] upvotes, String[] downvotes){
        return  (upvotes != null || downvotes != null) &&
                (!isIntersected(upvotes, downvotes)) &&
                (!(isDuplicate(upvotes) || isDuplicate(downvotes)))&&
                ((upvotes == null ? 0 : upvotes.length) + (downvotes == null ? 0 : downvotes.length) <= 33)&&
                (all(upvotes, Validation::isValidPublicKey)) &&
                (all(downvotes, Validation::isValidPublicKey));
    }

    public static boolean isValidMultiSignatureKeys(String[] addKeys, String[]removeKeys){
        return  (addKeys != null || removeKeys != null) &&
                (!isIntersected(addKeys, removeKeys)) &&
                (!(isDuplicate(addKeys) || isDuplicate(removeKeys)))&&
                ((addKeys == null ? 0 : addKeys.length) + (removeKeys == null ? 0 : removeKeys.length) <= 10)&&
                (all(addKeys, Validation::isValidPublicKey)) &&
                (all(removeKeys,Validation::isValidPublicKey));

    }

    public static boolean isValidContent(String content, ContentEncoding encoding){
        if (null == content )  return false;
        switch (encoding){
            case Hex:
                return isHex(content);
            case Base64:
                return content.matches(BASE64_PATTERN);
            case Raw:
                return true;
            default:
                return false;
        }
    }

    public static boolean isValidPeerQueryParameters(PeerQueryParameters queryParameters){
        //TODO: validate queryParameters
        return queryParameters != null;
    }

    private static boolean isValidQueryParameters(QueryParameters queryParameters){
        return queryParameters != null &&
                isValidLimit(queryParameters.getLimit());
    }

    public static boolean isValidAccountQueryParameters(QueryParameters queryParameters){
        return isValidQueryParameters(queryParameters);
    }

    public static boolean isValidTransactionQueryParameters(TransactionQueryParameters queryParameters){
        //todo: validate queryParameters
        return isValidQueryParameters(queryParameters);
    }

    public static boolean isValidDelegateQueryParameters(DelegateQueryParameters queryParameters){
        //TODO: validate queryParameters
        return isValidQueryParameters(queryParameters);
    }

    public static boolean isValidBlockQueryParameters(BlockQueryParameters queryParameters){
        //TODO: validate queryParameters
        return isValidQueryParameters(queryParameters);
    }


    public static <T> boolean all(T[] items, Predicate<T> predicate){
        if (items == null || items.length ==0)
            throw new IllegalArgumentException("items must not null or empty");

        for(T o : items){
            if (!predicate.test(o))
                return false;
        }
        return true;
    }

    public static <T> boolean any(T[] items, Predicate<T> predicate){
        if (items == null || items.length ==0)
            throw new IllegalArgumentException("items must not null or empty");

        for(T o : items){
            if (predicate.test(o))
                return true;
        }
        return false;
    }

    private static <T>boolean isIntersected(T[] array1, T[] array2){
        if (array1 == null || array2 == null)
            return false;

        HashSet<T> set = new HashSet<>();
        for (T item: array1) {
            if (!set.contains(item)) set.add(item);
        }

        for(T item : array2){
            if (set.contains(item)) return true;
        }

        return false;
    }

    private static <T> boolean isDuplicate(T[] array){
        if (array == null)
            return false;

        HashSet<T> set = new HashSet<>();
        for (T item: array) {
            if (!set.contains(item))
                set.add(item);
            else
                return true;
        }

        return false;
    }
}


<|start_filename|>src/so/asch/sdk/impl/AschRESTService.java<|end_filename|>
package so.asch.sdk.impl;

import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import so.asch.sdk.AschInterface;
import so.asch.sdk.AschResult;
import so.asch.sdk.AschSDKConfig;
import so.asch.sdk.dbc.Argument;
import so.asch.sdk.security.SecurityStrategy;
import so.asch.sdk.transaction.TransactionBuilder;
import so.asch.sdk.transaction.TransactionInfo;

import java.util.HashMap;
import java.util.Map;

/**
 * Asch服务基类
 * @author eagle
 */
public abstract class AschRESTService implements AschInterface{

    protected static final  Logger logger = LoggerFactory.getLogger(AschRESTService.class);
    private static final String CHAR_SET = "UTF-8";

    protected static final AschSDKConfig config = AschSDKConfig.getInstance();
    private static final Map<String, String> customeHeaders =  new HashMap<>();

    static {
        customeHeaders.put("magic", config.getMagic());
        customeHeaders.put("version", "");
    }

    protected TransactionBuilder getTransactionBuilder(){
        return new TransactionBuilder();
    }

    protected SecurityStrategy getSecurity(){
        return AschFactory.getInstance().getSecurity();
    }

    protected Map<String, String> getCustomeHeaders(){
        if (! config.getMagic().equals(customeHeaders.get("magic"))){
            customeHeaders.put("magic", config.getMagic());
        }
        return customeHeaders;
    }

    protected String getFullUrl(String relativeUrl){
        return config.getAschServer() + relativeUrl;
    }

    protected AschResult get(String relativeUrl){
        try{
            String jsonString = REST.get(getFullUrl(relativeUrl), null);
            return AschResult.FromJsonString(jsonString);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    protected AschResult get(String relativeUrl, ParameterMap parameters){
        try{
            String jsonString =  REST.get(getFullUrl(relativeUrl), parameters);
            return AschResult.FromJsonString(jsonString);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    protected AschResult post(String relativeUrl, ParameterMap parameters){
        try{
            String jsonString =  REST.post(getFullUrl(relativeUrl), parameters, null, CHAR_SET);
            return AschResult.FromJsonString(jsonString);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    protected AschResult post(String relativeUrl, String parameters){
        try{
            String jsonString =  REST.post(getFullUrl(relativeUrl), parameters, null, CHAR_SET);
            return AschResult.FromJsonString(jsonString);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    protected AschResult postMagic(String relativeUrl, ParameterMap parameters){
        try{
            String jsonString =  REST.post(getFullUrl(relativeUrl), parameters, getCustomeHeaders(), CHAR_SET);
            return AschResult.FromJsonString(jsonString);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    protected AschResult postMagic(String relativeUrl, String parameters){
        try{
            String jsonString =  REST.post(getFullUrl(relativeUrl), parameters, getCustomeHeaders(), CHAR_SET);
            return AschResult.FromJsonString(jsonString);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    protected AschResult broadcastTransaction(TransactionInfo transaction){
        ParameterMap transactionParameter = new ParameterMap()
                .put("transaction", transaction);
        return postMagic(AschServiceUrls.Peer.BROADCAST_TRANSACTION, transactionParameter );
    }

    protected AschResult fail(Exception ex){
        logger.error("rest call failed", ex);
        return AschResult.Failed(ex);
    }

    protected ParameterMap parametersWithPublicKeyField(String publicKey){
        return new ParameterMap().put("publicKey", publicKey);
    }

    protected AschResult getByPublicKey(String relativeUrl, String publicKey){
        try {
            Argument.require(Validation.isValidPublicKey(publicKey), "invalid public key");

            ParameterMap parameters = parametersWithPublicKeyField(publicKey);
            return get(relativeUrl, parameters);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    protected AschResult getByAddress(String relativeUrl, String address){
        try {
            Argument.require(Validation.isValidAddress(address), "invalid public address");

            ParameterMap parameters = new ParameterMap().put("address", address);
            return get(relativeUrl, parameters);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    protected ParameterMap parametersFromObject(Object object){
        ParameterMap map = new ParameterMap();
        map.putAll(JSONObject.parseObject( JSONObject.toJSONString(object) ));

        return map;
    }
}


<|start_filename|>src/so/asch/sdk/security/SecurityException.java<|end_filename|>
package so.asch.sdk.security;

/**
 * 加解密签名异常类
 * @author eagle
 *
 */
public class SecurityException extends Exception {
    private static final long serialVersionUID = 1L;

    public SecurityException(String message, Throwable parent) {
        super(message, parent);
    }

    public SecurityException(String message) {
        super(message);
    }

    public SecurityException(Throwable t) {
        super(t);
    }
}


<|start_filename|>src/so/asch/sdk/dto/query/QueryParameters.java<|end_filename|>
package so.asch.sdk.dto.query;

/**
 * Created by eagle on 17-7-16.
 */
public class QueryParameters{

    public enum SortOrder {
        ASC("asc"),
        DESC("desc");

        private String sortOrder;

        private SortOrder(String sortOrder){
            this.sortOrder = sortOrder;
        }

        public String getSortOrder() {
            return sortOrder;
        }
    }

    public Integer getLimit() {
        return limit;
    }

    public <T extends QueryParameters> T setLimit(Integer limit) {
        this.limit = limit;
        return (T)this;
    }

    public Integer getOffset() {
        return offset;
    }

    public <T extends QueryParameters> T setOffset(Integer offset) {
        this.offset = offset;
        return  (T) this;
    }

    public String getOrderBy() {
        return (null == orderByField || "" == orderByField) ? null :
                orderByField + ":" + order.getSortOrder();
    }

    public <T extends QueryParameters> T setOrderBy(String orderField, SortOrder order) {
        this.orderByField = orderField;
        this.order = order;
        return (T)this;
    }

    public <T extends QueryParameters> T orderByAscending(String fieldName){
        return this.setOrderBy(fieldName, SortOrder.ASC);
    }

    public  <T extends QueryParameters> T  orderByDescending(String fieldName){
        return this.setOrderBy(fieldName, SortOrder.DESC);
    }

    private Integer limit = null;
    private Integer offset = null;
    private String orderByField = null;
    private SortOrder order = SortOrder.DESC;
}

<|start_filename|>src/so/asch/sdk/impl/UIAService.java<|end_filename|>
package so.asch.sdk.impl;


import so.asch.sdk.AschResult;
import so.asch.sdk.UIA;
import so.asch.sdk.dbc.Argument;
import so.asch.sdk.transaction.TransactionInfo;

import java.text.MessageFormat;

public class  UIAService extends AschRESTService implements UIA {
    @Override
    public AschResult getIssuers(int limit, int offset) {
        try {
            Argument.require(Validation.isValidLimit(limit), "invalid limit");
            Argument.require(Validation.isValidOffset(offset), "invalid offset");

            return get(AschServiceUrls.UIA.GET_ISSUERS ,createLimitAndOffsetParameters(limit, offset));
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult getIssuer(String nameOrAddress) {
        try{
            Argument.notNullOrEmpty(nameOrAddress, "invalid nameOrAddress");

            return get(MessageFormat.format(AschServiceUrls.UIA.GET_ISSUER,nameOrAddress));
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult queryIssuerAssets(String nameOrAddress, int limit, int offset) {
        try {
            Argument.require(Validation.isValidLimit(limit), "invalid limit");
            Argument.require(Validation.isValidOffset(offset), "invalid offset");
            Argument.notNullOrEmpty(nameOrAddress, "invalid nameOrAddress");

            ParameterMap parameters = createLimitAndOffsetParameters(limit, offset);

            return get(MessageFormat.format(AschServiceUrls.UIA.QUERY_ISSUER_ASSETS,nameOrAddress), parameters);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult getAssets(int limit, int offset) {
        try {
            Argument.require(Validation.isValidLimit(limit), "invalid limit");
            Argument.require(Validation.isValidOffset(offset), "invalid offset");

            return get(AschServiceUrls.UIA.GET_ASSETS, createLimitAndOffsetParameters(limit, offset));
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult getAsset(String assetName) {
        try {
            Argument.notNullOrEmpty(assetName, "assetName");

            return get(MessageFormat.format(AschServiceUrls.UIA.GET_ASSET, assetName));
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult getAssetACL(String assetName, boolean whiteOrBlack, int limit, int offset) {
        try {
            Argument.require(Validation.isValidLimit(limit), "invalid limit");
            Argument.require(Validation.isValidOffset(offset), "invalid offset");
            Argument.notNullOrEmpty(assetName, "invalid assetName");

            ParameterMap parameters = createLimitAndOffsetParameters(limit, offset)
                    .put("name", assetName)
                    .put("flag", whiteOrBlack);

            return get(MessageFormat.format(AschServiceUrls.UIA.GET＿ASSET＿ACL,assetName), parameters);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult getAddressBalances(String address, int limit, int offset) {
        try {
            Argument.require(Validation.isValidLimit(limit), "invalid limit");
            Argument.require(Validation.isValidOffset(offset), "invalid offset");
            Argument.require(Validation.isValidAddress(address), "invalid address");

            ParameterMap parameters = createLimitAndOffsetParameters(limit, offset);

            return get(AschServiceUrls.UIA.GET_ADDRESS_BALANCES + address, parameters);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult getTransactions(String ownerPublicKey, int limit, int offset) {
        try {
            Argument.require(Validation.isValidLimit(limit), "invalid limit");
            Argument.require(Validation.isValidOffset(offset), "invalid offset");
            Argument.notNullOrEmpty(ownerPublicKey, "invalid ownerPublicKey");

            ParameterMap parameters = createLimitAndOffsetParameters(limit, offset)
                    .put("publicKey", ownerPublicKey);

            return get(AschServiceUrls.UIA.GET_TRANSACTIONS, parameters);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult createIssuer(String name, String desc, String secret, String secondSecret) {
        return null;
    }

    @Override
    public AschResult createAsset(String currency, String desc, long maximum, byte precision, String strategy, String secret, String secondSecret) {
        return null;
    }

    @Override
    public AschResult setAssetACL(String currency, int assertStatus, boolean whiteListMode, String secret, String secondSecret) {
        return null;
    }

    @Override
    public AschResult issue(String currency, long amount, String secret, String secondSecret) {
        return null;
    }

    @Override
    public AschResult transfer(String currency, String recipientId, long amount, String message, String secret, String secondSecret) {
        try {
            Argument.notNullOrEmpty(currency, "invalid currency");
            Argument.require(Validation.isValidAddress(recipientId), "invalid recipientId");
            Argument.require(Validation.isValidSecret(secret), "invalid secret");
            Argument.optional(secondSecret, Validation::isValidSecondSecret, "invalid second secret");

            TransactionInfo transaction = getTransactionBuilder()
                    .buildUIATransfer(currency, amount, recipientId, message, secret, secondSecret);

            return broadcastTransaction(transaction);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult setAssetStatus(String currency, int assertStatus, boolean whiteListMode, String secret, String secondSecret) {
        return null;
    }

    private ParameterMap createLimitAndOffsetParameters(int limit, int offset){
        return new ParameterMap()
                .put("limit", limit)
                .put("offset", offset);
    }

}


<|start_filename|>src/so/asch/sdk/impl/AccountService.java<|end_filename|>
package so.asch.sdk.impl;

import so.asch.sdk.Account;
import so.asch.sdk.AschResult;
import so.asch.sdk.dbc.Argument;
import so.asch.sdk.dto.query.QueryParameters;
import so.asch.sdk.transaction.TransactionInfo;

import java.security.KeyPair;

/**
 * {@link Account}服务实现
 * @author eagle
 */
public class AccountService extends so.asch.sdk.impl.AschRESTService implements Account  {

    @Override
    public AschResult login(String secret){
        ParameterMap parameters = new ParameterMap().put("secret", secret);
        return post(AschServiceUrls.Account.LOGIN, parameters);
    }

    @Override
    public AschResult secureLogin(String secret){
        try{
            Argument.require(Validation.isValidSecret(secret), "invalid secret");

            KeyPair keyPair = getSecurity().generateKeyPair(secret);
            String publicKey = getSecurity().encodePublicKey(keyPair.getPublic());
            ParameterMap parameters = parametersWithPublicKeyField(publicKey);

            return post(AschServiceUrls.Account.SECURE_LOGIN, parameters);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult getAccount(String address){
            return getByAddress(AschServiceUrls.Account.GET_ACCOUNT, address);
    }

    @Override
    public AschResult getBalance(String address){
        return getByAddress(AschServiceUrls.Account.GET_BALANCE, address);
    }

    @Override
    public AschResult getPublicKey(String address){
        return  getByAddress(AschServiceUrls.Account.GET_PUBLIC_KEY, address);
    }

    @Override
    public AschResult generatePublicKey(String secret){
        try {
            Argument.require(Validation.isValidSecret(secret), "invalid secret");

            ParameterMap parameters = new ParameterMap().put("secret", secret);
            return post(AschServiceUrls.Account.GENERATE_PUBLIC_KEY, parameters);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult getVotedDelegates(String address){
        return getByAddress(AschServiceUrls.Account.GET_VOTED_DELEGATES, address);
    }

    @Override
    public AschResult getDelegatesFee(){
        return get(AschServiceUrls.Account.GET_DELEGATE_FEE);
    }

    //todo:验证投票和取消投票的数组都符合规则
    @Override
    public AschResult vote(String[] upvotePublicKeys, String[] downvotePublicKeys, String secret, String secondSecret){
        try {
            Argument.require(Validation.isValidSecret(secret), "invalid secret");
            Argument.optional(secondSecret, Validation::isValidSecondSecret, "invalid secondSecret");
            Argument.require(Validation.isValidVoteKeys(upvotePublicKeys, downvotePublicKeys), "invalid upvoteKeys or downvoteKeys");

            TransactionInfo transaction = getTransactionBuilder()
                    .buildVote( upvotePublicKeys, downvotePublicKeys,secret, secondSecret);
            return broadcastTransaction(transaction);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult transfer(String targetAddress, long amount, String message, String secret, String secondSecret){
        try {
            Argument.require(Validation.isValidAddress(targetAddress), "invalid target address");
            Argument.require(Validation.isValidSecret(secret), "invalid secret");
            Argument.optional(secondSecret, Validation::isValidSecondSecret, "invalid second secret");

            TransactionInfo transaction = getTransactionBuilder()
                    .buildTransfer(targetAddress, amount, message, secret, secondSecret);
            return broadcastTransaction(transaction);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult getTopAccounts(QueryParameters parameters){
        try {
            Argument.require(Validation.isValidAccountQueryParameters(parameters), "invalid parameters");

            ParameterMap getParameters = parametersFromObject(parameters);
            return get(AschServiceUrls.Account.GET_TOP_ACCOUNTS, getParameters);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }
}


<|start_filename|>src/so/asch/sdk/AschSDK.java<|end_filename|>
package so.asch.sdk;

import so.asch.sdk.impl.AschFactory;

/**
 * Asch接口门面类，对外提供简单的访问模式
 * @author eagle
 *
 */
public final class AschSDK {
    public final static Account Account;
    public final static Delegate Delegate;
    public final static Transaction Transaction;
    public final static Block Block;
    public final static Signature Signature;
    public final static Dapp Dapp;
    public final static UIA UIA;
    public final static Peer Peer;
    public final static Misc Misc;

    public final static AschSDKConfig Config = AschSDKConfig.getInstance();
    public final static AschHelper Helper = new AschHelper();

    static {
        AschFactory factory = AschFactory.getInstance();

        Account = factory.getService(so.asch.sdk.Account.class);
        Block = factory.getService(so.asch.sdk.Block.class);
        Delegate = factory.getService(so.asch.sdk.Delegate.class);
        Transaction = factory.getService(so.asch.sdk.Transaction.class);
        Signature = factory.getService(so.asch.sdk.Signature.class);
        Dapp = factory.getService(so.asch.sdk.Dapp.class);
        UIA = factory.getService(so.asch.sdk.UIA.class);
        Peer = factory.getService(so.asch.sdk.Peer.class);
        Misc = factory.getService(so.asch.sdk.Misc.class);
    }

}


<|start_filename|>src/so/asch/sdk/Peer.java<|end_filename|>
package so.asch.sdk;

import so.asch.sdk.dto.query.PeerQueryParameters;

/**
 * Asch节点接口
 * @author eagle
 * 参见 https://github.com/AschPlatform/asch-docs/blob/master/asch_http_interface.md#25-%E8%8A%82%E7%82%B9peers
 */
public interface Peer extends AschInterface {
    //接口地址：/api/peers
    //请求方式：get
    //支持格式：urlencoded
    //请求参数说明：
    //state	integer	N	节点状态,0: ,1:,2:,3:
    //os	string	N	内核版本
    //version	string	N	asch版本号
    //limit	integer	N	限制结果集个数，最小值：0,最大值：100
    //orderBy	string	N
    //offset	integer	N	偏移量，最小值0
    //port	integer	N	端口，1~65535
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //peers	Array	节点信息json构成的数组
    //totalCount	integer	当前正在运行的节点个数
    AschResult queryPeers(PeerQueryParameters parameters);

    //接口地址：/api/peers/version
    //请求方式：get
    //支持格式：无
    //请求参数说明：无参数
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //version	string	版本号
    //build	timestamp	构建时间
    //net	string	主链或者测试链
    AschResult getVersion();

    //接口地址：/api/peers/get
    //请求方式：get
    //支持格式：urlencoded
    //请求参数说明：
    //ip	string	Y	待查询节点ip
    //port	integer	Y	待查询节点端口，1~65535
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //peer	json
    AschResult getPeer(String ip, int port);

}


<|start_filename|>src/so/asch/sdk/security/Ed25519.java<|end_filename|>
package so.asch.sdk.security;

import net.i2p.crypto.eddsa.EdDSAEngine;
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
import net.i2p.crypto.eddsa.EdDSAPublicKey;
import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
import net.i2p.crypto.eddsa.spec.EdDSAParameterSpec;
import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
import so.asch.sdk.dbc.ContractException;

import java.security.*;

/**
 * asch兼容加密及签名功能
 * @author eagle
 *
 */
 public class Ed25519 {
    private static final int SIGNATURE_LENGTH = 64;
    private static final int PUBLIC_KEY_LENGTH = 32;

    private static final String EDDSA_CURVE_TABLE = "Ed25519";
    private static final EdDSAParameterSpec EDDSA_PARAMETER_SPEC = EdDSANamedCurveTable.getByName(EDDSA_CURVE_TABLE);

    private static Signature signature ;
    static
    {
        try {
            signature = new EdDSAEngine(MessageDigest.getInstance(EDDSA_PARAMETER_SPEC.getHashAlgorithm()));
        }
        catch (Exception ex) {
            //
        }
    }

    public static KeyPair generateKeyPairBySeed(byte[] seed) throws ContractException {
        EdDSAPrivateKeySpec keySpec = new EdDSAPrivateKeySpec(seed, EDDSA_PARAMETER_SPEC);
        EdDSAPrivateKey privateKey = new EdDSAPrivateKey(keySpec);
        EdDSAPublicKey publicKey = new EdDSAPublicKey(new EdDSAPublicKeySpec(privateKey.getAbyte(), EDDSA_PARAMETER_SPEC));

        return new KeyPair(publicKey, privateKey);
    }

    /**
     * 对消息进行签名
     * @param message 消息内容
     * @param privateKey 私钥
     * @return 签名
     * */
    public static byte[] signature (byte[] message, PrivateKey privateKey) throws InvalidKeyException, SignatureException {
        signature.initSign(privateKey);
        signature.update(message);
        return signature.sign();
    }

    /**
     * 对消息签名进行验证
     * @param message 消息内容
     * @param sign 私钥
     * @param publicKey 公钥
     * @return 签名是否正确
     * */
    public static boolean verify (byte[] message, byte[] sign, byte[] publicKey) throws InvalidKeyException,SignatureException {

        EdDSAPublicKeySpec spec = new EdDSAPublicKeySpec(publicKey, EdDSANamedCurveTable.getByName(EDDSA_CURVE_TABLE));
        EdDSAPublicKey pKey = new EdDSAPublicKey(spec);
        signature.initVerify(pKey);

        signature.update(message);
        return signature.verify(sign);
    }
}





<|start_filename|>src/so/asch/sdk/AschResult.java<|end_filename|>
package so.asch.sdk;

import com.alibaba.fastjson.JSONObject;

import java.util.Map;

public class AschResult {
    public boolean isSuccessful() {
        return successful;
    }

    public String getError() {
        return error;
    }

    public String getRawJson() {
        return rawJson;
    }
    public Exception getException() {
        return exception;
    }

    private boolean successful = false;
    private String error = null;
    private String rawJson = null;
    private Exception exception;
    private JSONObject jsonObject;

    public boolean isLocalError(){
        return exception != null;
    }

    public Map<String, Object> parseMap(){
        return JSONObject.parseObject(rawJson);
    }

    public <T> T parseObject(Class<T>  classzz){
        return jsonObject == null ?
                null :
                jsonObject.toJavaObject(classzz);
    }

    public String toString(){
        return String.format("success:%s, error:%s, exception:%s rawJson:%s",
                this.successful,
                this.error,
                this.exception,
                this.rawJson);
    }

    public static AschResult FromJsonString(String jsonString){
        AschResult result = new AschResult();

        result.rawJson = jsonString;
        result.jsonObject = JSONObject.parseObject(jsonString);

        JSONObject json = result.jsonObject;
        if (json.containsKey("success")){
            result.successful = json.getBoolean("success");
        }

        if (json.containsKey("error")){
            result.error = json.getString("error");
        }

        return result;
    }

    public static AschResult Failed(Exception ex){
        AschResult result = new AschResult();
        result.successful = false;
        result.error = ex.getMessage();
        result.exception = ex;

        return result;
    }
}


<|start_filename|>src/so/asch/sdk/impl/AschConst.java<|end_filename|>
package so.asch.sdk.impl;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

/**
 * Created by eagle on 17-7-18.
 */
public final class AschConst {
    public static final int CLIENT_DRIFT_SECONDS = 5;
    public static final int COIN = 100000000;
    public static final char BASE58_ADDRESS_PREFIX = 'A';
    public static final int MIN_BASE58_ADDRESS_LEN = 30;
    public static final Date ASCH_BEGIN_EPOCH;

    static {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
        df.setTimeZone(TimeZone.getTimeZone("UTC"));
        Date date = null;
        try {
            date = df.parse("2016-06-27T20:00:00Z");
        }
        catch (Exception ex){
            //never
        }
        ASCH_BEGIN_EPOCH = date;
    }

    public static class Fees{
        public static final long TRANSFER = 10000000;
        public static final long UIA_TRANSFER = 10000000;
        public static final long VOTE = 10000000;
        public static final long SECOND_SIGNATURE =500000000;
        public static final long MULTI_SIGNATURE =500000000;
        public static final long DELEGATE = 10000000000L;
        public static final long DAPP = 10000000000L;
    }



    public class AccountFields{
        public static final String NAME = "name";

    }
}


<|start_filename|>src/so/asch/sdk/impl/PeerService.java<|end_filename|>
package so.asch.sdk.impl;

import so.asch.sdk.AschResult;
import so.asch.sdk.Peer;
import so.asch.sdk.dbc.Argument;
import so.asch.sdk.dto.query.PeerQueryParameters;

public class PeerService extends AschRESTService implements Peer {
    @Override
    public AschResult queryPeers(PeerQueryParameters parameters){
        try {
            Argument.require(Validation.isValidPeerQueryParameters(parameters), "invalid parameters");

            return get(AschServiceUrls.Peer.QUERY_PEERS, parametersFromObject(parameters));
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult getVersion() {
        return get(AschServiceUrls.Peer.GET_VERSION);
    }

    @Override
    public AschResult getPeer(String ip, int port) {
        try {
            Argument.require(Validation.isValidIP(ip), "invalid ip");
            Argument.require(Validation.isValidPort(port), "invalid port");

            ParameterMap parameters = new ParameterMap()
                    .put("ip", ip)
                    .put("port", port);

            return get(AschServiceUrls.Peer.GET_PEER, parameters);
        } catch (Exception ex) {
            return fail(ex);
        }
    }
}


<|start_filename|>test/so/asch/sdk/impl/BlockServiceTest.java<|end_filename|>
package so.asch.sdk.impl;

import org.testng.Assert;
import org.testng.annotations.Test;
import so.asch.sdk.AschResult;
import so.asch.sdk.AschSDK;
import so.asch.sdk.TestData;
import so.asch.sdk.dto.query.BlockQueryParameters;

/**
 * @author fisher
 * @version $Id: BlockServiceTest.java, v 0.1 2017/8/1 18:49 fisher Exp $
 */
public class BlockServiceTest {

    @Test
    public void testGetBlockById() throws Exception {
        AschResult result= AschSDK.Block.getBlockById(TestData.blockId,false);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testGetBlockByHeight()throws Exception{
        AschResult result= AschSDK.Block.getBlockByHeight(TestData.blockHeight,false);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testGetBlockByHash()throws Exception{
        AschResult result= AschSDK.Block.getBlockByHash(TestData.blockHash,false);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testQueryBlocks()throws Exception{
        BlockQueryParameters parameters = new BlockQueryParameters();
        //parameters.setGeneratorPublicKey(TestData.publicKey());
        //parameters.setHeight(6890);
        parameters.setLimit(2);
        //parameters.setOffset(0);
        AschResult result= AschSDK.Block.queryBlocks(parameters);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testGetHeight()throws Exception{
        AschResult result= AschSDK.Block.getHeight();
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testGetFree()throws Exception{
        AschResult result= AschSDK.Block.getFree();
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testGetMilestone()throws Exception{
        AschResult result= AschSDK.Block.getMilestone();
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testGetReward()throws Exception{
        AschResult result= AschSDK.Block.getReward();
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testGetSupply()throws Exception{
        AschResult result= AschSDK.Block.getSupply();
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testGetStauts()throws Exception{
        AschResult result= AschSDK.Block.getStauts();
        Assert.assertTrue(result.isSuccessful());
    }
}


<|start_filename|>src/so/asch/sdk/transaction/TransactionInfo.java<|end_filename|>
package so.asch.sdk.transaction;

import com.alibaba.fastjson.annotation.JSONField;
import so.asch.sdk.TransactionType;
import so.asch.sdk.codec.Decoding;
import so.asch.sdk.codec.Encoding;
import so.asch.sdk.transaction.asset.AssetInfo;

import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;

/**
 * Created by eagle on 17-7-16.
 */
public class TransactionInfo {
    private static final int MAX_BUFFER_SIZE = 1024 * 5;

    public Integer getType() {
        return transactionType == null ? null : transactionType.getCode();
    }

    public TransactionInfo setTransactionType(TransactionType type) {
        this.transactionType = type;
        return this;
    }

    public String getSenderPublicKey() {
        return senderPublicKey;
    }

    public TransactionInfo setSenderPublicKey(String senderPublicKey) {
        this.senderPublicKey = senderPublicKey;
        return this;
    }

    public String getRequesterPublicKey() {
        return requesterPublicKey;
    }

    public TransactionInfo setRequesterPublicKey(String requesterPublicKey) {
        this.requesterPublicKey = requesterPublicKey;
        return this;
    }

    public String getRecipientId() {
        return recipientId;
    }

    public TransactionInfo setRecipientId(String recipientId) {
        this.recipientId = recipientId;
        return this;
    }

    public String getMessage() { return message; }

    public TransactionInfo setMessage(String message) {
        this.message = message;
        return this;
    }

    public Long getAmount() {
        return amount;
    }

    public TransactionInfo setAmount(Long amount) {
        this.amount = amount;
        return this;
    }

    public Long getFee() {
        return fee;
    }

    public TransactionInfo setFee(Long fee) {
        this.fee = fee;
        return this;
    }

    public String getId() {
        return transactionId;
    }

    public TransactionInfo setTransactionId(String transactionId) {
        this.transactionId = transactionId;
        return this;
    }

    @JSONField(serialize = false)
    public TransactionType getTransactionType() {
        return transactionType;
    }

    public String getSignature() {
        return signature;
    }

    public TransactionInfo setSignature(String signature) {
        this.signature = signature;
        return this;
    }

    public String getSignSignature() {
        return signSignature;
    }

    public TransactionInfo setSignSignature(String signSignature) {
        this.signSignature = signSignature;
        return this;
    }

    public Integer getTimestamp() {
        return timestamp;
    }

    public TransactionInfo setTimestamp(Integer timestamp) {
        this.timestamp = timestamp;
        return this;
    }

    @JSONField
    public AssetInfo getAsset() {
        return assetInfo;
    }

    public TransactionInfo setAsset(AssetInfo assertInfo) {
        this.assetInfo = assertInfo;
        return this;
    }

    private String transactionId = null;
    private TransactionType transactionType = null;
    private String recipientId = null;

    private String requesterPublicKey = null;
    private String senderPublicKey = null;
    private String message = null;
    private Integer timestamp = null;
    private Long amount = null;
    private Long fee = null;

    private String signature = null;
    private String signSignature = null;
    private AssetInfo assetInfo = null;

    public byte[] getBytes(boolean skipSignature , boolean skipSignSignature){
        //1 + 4 + 32 + 32 + 8 + 8 + ? + ? + 64 + 64
        //type(1)|timestamp(4)|senderPublicKey(32)|requesterPublicKey(32)|recipientId(8)|amount(8)|
        //message(?)|asset(?)|setSignature(64)|signSignature(64)

        ByteBuffer buffer = ByteBuffer.allocate(MAX_BUFFER_SIZE).order(ByteOrder.LITTLE_ENDIAN)
                .put(getType().byteValue())
                .putInt(getTimestamp())
                .put(Decoding.unsafeDecodeHex(getSenderPublicKey()))
                .put(Decoding.unsafeDecodeHex(getRequesterPublicKey()))
                .put(getRecipientIdBuffer())
                .putLong(getAmount())
                .put(getMessageBuffer())
                .put(getAsset().assetBytes());

        if (!skipSignature){
            buffer.put(Decoding.unsafeDecodeHex(getSignature()));
        }

        if (!skipSignSignature){
            buffer.put(Decoding.unsafeDecodeHex(getSignSignature()));
        }

        buffer.flip();
        byte[] result = new byte[buffer.remaining()];
        buffer.get(result);

        return result;
    }

    private byte[] getRecipientIdBuffer(){
        if (null == recipientId)  return new byte[8];
        //数字地址
        if (recipientId.matches("^\\d+")){
            byte[] idBuffer = new BigInteger(recipientId).toByteArray();
            int length = Math.min(8 ,idBuffer.length);
            int fromIndex = idBuffer.length > 8 ? idBuffer.length - 8 : 0;
            byte[] result = new byte[8];
            System.arraycopy(idBuffer, fromIndex, result, 0, length);
            return result;
        }

        //A+Base58地址
        return Encoding.getUTF8Bytes(recipientId);
    }

    private byte[] getMessageBuffer(){
       return Encoding.getUTF8Bytes(message);
    }
}


<|start_filename|>src/so/asch/sdk/codec/DecodingException.java<|end_filename|>
package so.asch.sdk.codec;

/**
 * Created by eagle on 17-7-16.
 */
public class DecodingException extends Exception{
    private static final long serialVersionUID = 1L;

    public DecodingException(String message, Throwable parent) {
        super(message, parent);
    }

    public DecodingException(String message) {
        super(message);
    }

    public DecodingException(Throwable t) {
        super(t);
    }
}


<|start_filename|>src/so/asch/sdk/ContentEncoding.java<|end_filename|>
package so.asch.sdk;

public enum ContentEncoding {
    Raw("raw"),
    Hex("hex"),
    Base64("base64");

    ContentEncoding(String encoding) {
        this.encoding = encoding;
    }

    public String getEncoding() {
        return encoding;
    }

    private String encoding;
}


<|start_filename|>test/so/asch/sdk/impl/DappServiceTest.java<|end_filename|>
package so.asch.sdk.impl;

import org.testng.Assert;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.Test;
import so.asch.sdk.AschResult;
import so.asch.sdk.AschSDK;
import so.asch.sdk.TestData;
import so.asch.sdk.dto.query.DappQureyParameters;

/**
 * @author fisher
 * @version $Id: DappServiceTest.java, v 0.1 2017/12/1 18:19 fisher Exp $
 */
public class DappServiceTest {
    @BeforeSuite
    public void SetUp(){
        AschSDK.Config.setAschServer(TestData.root);
    }

    @Test
    public void testGetBlocksHeight() throws Exception {
        AschResult result= AschSDK.Dapp.getBlocksHeight(TestData.dappId);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testGetBlocks() throws Exception {
        DappQureyParameters parameters = new DappQureyParameters();
        parameters.setLimit(10);
        AschResult result= AschSDK.Dapp.getBlocks(TestData.dappId,parameters);
        Assert.assertTrue(result.isSuccessful());
    }

    @Test
    public void testGetAccount() throws Exception {
        AschResult result= AschSDK.Dapp.getAccount(TestData.dappId,TestData.dappAddress);
        Assert.assertTrue(result.isSuccessful());
    }


    @Test
    public void testDappDeposit() throws Exception {
        AschResult result= AschSDK.Dapp.dappDeposit(TestData.dappId,"XAS",2000000000,TestData.secret,null);
        Assert.assertTrue(result.isSuccessful());
    }



}


<|start_filename|>src/so/asch/sdk/Transaction.java<|end_filename|>
package so.asch.sdk;

import so.asch.sdk.dto.query.TransactionQueryParameters;

/**
 * Asch交易接口
 * @author eagle
 * 参见 https://github.com/AschPlatform/asch-docs/blob/master/asch_http_interface.md#22-%E4%BA%A4%E6%98%93transactions
 */
public interface Transaction extends AschInterface{

    //接口地址：/api/transactions
    //请求方式：get
    //支持格式：urlencoded
    //接口备注：如果请求不加参数则会获取全网所有交易
    //请求参数说明：
    //blockId	string	N	区块id
    //limit	integer	N	限制结果集个数，最小值：0,最大值：100
    //type	integer	N	交易类型,0:普通转账，1:设置二级密码，2:注册受托人，3:投票，4:多重签名，5:DAPP，6:IN_TRANSFER，7:OUT_TRANSFER
    //orderBy	string	N	根据表中字段排序，senderPublicKey:desc
    //offset	integer	N	偏移量，最小值0
    //senderPublicKey	string	N	发送者公钥
    //ownerPublicKey	string	N
    //ownerAddress	string	N
    //senderId	string	N	发送者地址
    //recipientId	string	N	接收者地址,最小长度：1
    //amount	integer	N	金额
    //fee	integer	N	手续费
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //transactions	列表	多个交易详情json构成的列表
    //count	int	获取到的交易总个数
    AschResult queryTransactions(TransactionQueryParameters parameters);

    //接口地址：/api/transactions/get
    //请求方式：get
    //支持格式：urlencoded
    //请求参数说明：
    //Id	string	Y	交易id
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //transactions	json	交易详情
    AschResult getTransaction(String transactionId);

    //接口地址：/api/transactions/unconfirmed/get
    //请求方式：get
    //支持格式：urlencoded
    //请求参数说明：
    //id	string	Y	未确认交易id
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //transaction	json	未确认交易详情
    AschResult getUnconfirmedTransaction(String unconfirmedTransactionId);


    //接口地址：/api/transactions/unconfirmed
    //请求方式：get
    //支持格式：urlencoded
    //接口说明：如果不加参数，则会获取全网所有未确认交易 请求参数说明：
    //senderPublicKey	string	N	发送者公钥
    //address	string	N	地址
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //transactions	Array	未确认交易列表
    AschResult getUnconfirmedTransactions(String senderPublicKey, String address);

    //接口地址：/api/transactions
    //请求方式：PUT
    //支持格式：json
    //接口备注：接收者账户需在web端钱包登陆过
    //请求参数说明：
    //secret	string	Y	asch账户密码
    //amount	integer	Y	金额，最小值：1，最大值：10000000000000000
    //recipientId	string	Y	接收者地址,最小长度：1
    //publicKey	string	N	发送者公钥
    //secondSecret	string	N	发送者二级密码，最小长度1，最大长度：100
    //multiSigAccountPublicKey	string	N	多重签名账户公钥
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //transactionId	string	交易id
    AschResult addTransaction(String secret, int amount, String recipientId,
                              String senderPublicKey, String secondSecret, String multiSignAccountPublicKey);




}


<|start_filename|>src/so/asch/sdk/impl/SignatureService.java<|end_filename|>
package so.asch.sdk.impl;

import so.asch.sdk.AschResult;
import so.asch.sdk.Signature;
import so.asch.sdk.dbc.Argument;
import so.asch.sdk.transaction.TransactionInfo;

public class SignatureService extends AschRESTService implements Signature {
    @Override
    public AschResult setSignature(String secret, String secondSecret, String publicKey, String multiSignAccountPublicKey) {
        try{
            Argument.require(Validation.isValidSecret(secret), "invalid secret");
            Argument.optional(publicKey, Validation::isValidPublicKey, "invalid publicKey");
            Argument.require(Validation.isValidSecondSecret(secondSecret), "invalid secondSecret");
            Argument.optional(multiSignAccountPublicKey, Validation::isValidPublicKey, "invalid multiSignAccountPublicKey");

//            AschResult parameters = new AschResult()
//                    .fluentPut("secret", secret)
//                    .fluentPut("publicKey", publicKey)
//                    .fluentPut("secondSecret", secondSecret)
//                    .fluentPut("multisigAccountPublicKey", multiSignAccountPublicKey); //注意名称要与asch源码一致!!!

            TransactionInfo transaction = getTransactionBuilder()
                    .buildSignature(secret, secondSecret);

            return broadcastTransaction(transaction);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult getSignatureFee() {
        return get(AschServiceUrls.Signature.GET_SIGNATURE_FEE);
    }

    //TODO:此接口实现有疑问
    @Override
    public AschResult setMultiSignature(int minAccount, int lifetime, String[] addKeys, String[] removeKeys,
                                        String secret, String secondSecret, String publicKey ) {
        try {
            Argument.require(Validation.isValidMultiSignatureMinAccount(minAccount), "invalid minAccount");
            Argument.require(Validation.isValidMultiSignatureKeys(addKeys, removeKeys), "invalid addKeys or removeKeys");
            Argument.require(Validation.isValidMultiSignatureLifetime(lifetime), "invalid lifetime");
            Argument.require(Validation.isValidSecret(secret), "invalid secret");
            Argument.optional(publicKey, Validation::isValidPublicKey, "invalid publicKey");
            Argument.optional(secondSecret, Validation::isValidSecondSecret, "invalid secondSecret");

//            List<String> keysGroup = new ArrayList<>();
//            if (addKeys != null)
//                Arrays.asList(addKeys).forEach(key-> keysGroup.add("+"+key));
//            if (removeKeys != null)
//                Arrays.asList(removeKeys).forEach(key-> keysGroup.add("-"+key));
//
//            AschResult parameters = new AschResult()
//                    .fluentPut("secret", secret)
//                    .fluentPut("publicKey", publicKey)
//                    .fluentPut("secondSecret", secondSecret)
//                    .fluentPut("min", minAccount)
//                    .fluentPut("lifetime", lifetime)
//                    .fluentPut("keysgroup", keysGroup);
//            return post(AschServiceUrls.Signature.SET_MULTI_SIGNATURE, parameters);
            TransactionInfo transaction = getTransactionBuilder()
                    .buildMultiSignature(minAccount, lifetime, addKeys, removeKeys, secret, secondSecret);

            return broadcastTransaction(transaction);
        }
        catch (Exception ex){
            return fail(ex);
        }

    }

    //TODO:此接口实现有疑问
    @Override
    public AschResult multiSignature(String transactionId, String secret, String secondSecret, String publicKey ) {
        try {
            Argument.require(Validation.isValidTransactionId(transactionId), "invalid transactionId");
            Argument.require(Validation.isValidSecret(secret), "invalid secret");
            Argument.optional(secondSecret, Validation::isValidSecondSecret, "invalid secondSecret");
            Argument.optional(publicKey, Validation::isValidPublicKey, "invalid publicKey");

            ParameterMap parameters = new ParameterMap()
                    .put("secret", secret)
                    .put("publicKey", publicKey)
                    .put("secondSecret", secondSecret)
                    .put("transactionId", transactionId);

            return post(AschServiceUrls.Signature.MULTI_SIGNATURE, parameters);
        }
        catch (Exception ex){
            return fail(ex);
        }
    }

    @Override
    public AschResult getPendingTransactions(String publicKey) {
        return getByPublicKey(AschServiceUrls.Signature.GET_PENDING_TRANSACTIONS, publicKey);
    }

    @Override
    public AschResult getMultiSignatureAccounts(String publicKey) {
        return getByPublicKey(AschServiceUrls.Signature.GET_MULTI_SIGNATURE_ACCOUNTS, publicKey);
    }
}


<|start_filename|>src/so/asch/sdk/dto/query/DelegateQueryParameters.java<|end_filename|>
package so.asch.sdk.dto.query;

public class DelegateQueryParameters extends QueryParameters {
    public String getAddress() {
        return address;
    }

    public DelegateQueryParameters setAddress(String address) {
        this.address = address;
        return this;
    }

    private String address;
}


<|start_filename|>src/so/asch/sdk/Delegate.java<|end_filename|>
package so.asch.sdk;

import so.asch.sdk.dto.query.DelegateQueryParameters;

/**
 * Asch受托人接口
 * @author eagle
 * 参见 https://github.com/AschPlatform/asch-docs/blob/master/asch_http_interface.md#24-%E5%8F%97%E6%89%98%E4%BA%BAdelegates
 */
public interface Delegate extends AschInterface {

    //接口地址：/api/delegates/count
    //请求方式：get
    //支持格式：无
    //请求参数说明：无
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //count	integer	受托人总个数
    AschResult getDelegatesCount();

    //接口地址：/api/delegates/voters
    //请求方式：get
    //支持格式：urlencoded
    //请求参数说明：
    //publicKey	string	Y	受托人公钥
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //accounts	Array	账户json串组成的数组
    AschResult getVoters(String publicKey);

    //接口地址： /api/delegates/get/
    //请求方式：get
    //支持格式：urlencoded
    //接口备注：通过公钥获取受托人信息
    //请求参数说明：
    //publickey	string	二选一	受托人公钥
    //username	string	二选一	受托人用户名
    //返回参数说明：
    //success	boolean	是否成功获得response数据
    //delegate	json	委托人详情
    AschResult getDelegateByPublicKey(String publicKey);

    // 接口地址： /api/delegates/get/
    // 请求方式：get
    // 支持格式: urlencoded
    // 接口备注：根据用户名获取受托人信息
    // 请求参数说明:
    // username string 受托人用户名
    // 返回参数说明：
    // success boolean 是否成功获取response数据
    // delegate json 委托人详情
    AschResult getDelegateByName(String userName);

    //接口地址：/api/delegatesupublicKey
    //请求方式：get
    //支持格式：urlencoded
    //接口说明：如果不加参数则会返回全网受托人列表
    //请求参数说明：
    //address	string	N	受托人地址
    //limit	int	N	限制返回结果数据集的个数
    //offset	integer	N	偏移量，最小值：0
    //orderBy	string	N	排序字段:排序规则，如:desc
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //delegates	Array	受托人详情列表
    AschResult queryDelegates(DelegateQueryParameters parameters);

    //接口地址：/api/delegates/fee
    //请求方式：get
    //支持格式：urlencoded
    //请求参数说明：
    //publicKey	string	Y	受托人公钥
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //fee	integer	转账费
    AschResult getDelegateFee(String publicKey);

    //接口地址：/api/delegates/forging/getForgedByAccount
    //请求方式：get
    //支持格式：urlencoded
    //请求参数说明：
    //generatorPublicKey	string	Y	区块生成者公钥
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //fees	integer	收取的手续费
    //rewards	integer	已获得奖励
    //forged	integer	锻造获得的总奖励
    AschResult getForging(String publicKey);

    //接口地址：/api/delegates
    //请求方式：put
    //支持格式：urlencoded
    //请求参数说明：
    //secret	string	Y	asch账户密码
    //secondSecret	string	N	asch账户二级密码，最小长度：1，最大长度：100
    //username	string	N	受托人名字
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //transaction	json	注册受托人交易详情
    AschResult registerDelegate(String userName, String secret, String secondSecret);

    //接口地址：/api/delegates/forging/enable
    //请求方式：post
    //支持格式：urlencoded //url必须是受托人所在服务器
    //请求参数说明：
    //secret	string	Y	asch账户密码
    //publicKey	string	N	公钥
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //address	string	受托人地址
    AschResult enableForge(String publicKey, String secret );

    //接口地址：/api/delegates/forging/disable
    //请求方式：post
    //支持格式：urlencoded //url必须是受托人所在服务器
    //请求参数说明：
    //secret	string	Y	asch账户密码
    //publicKey	string	N	公钥
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //address	string	受托人地址
    AschResult disableForge(String publicKey, String secret);

    //接口地址：/api/delegates/forging/status
    //请求方式：get
    //支持格式：urlencoded
    //请求参数说明：
    //publicKey	string	Y	公钥
    //返回参数说明：
    //success	boole	是否成功获得response数据
    //enabled	string	锻造是否开启
    AschResult getForgingStatus(String publicKey);

}
