Filecoin發(fā)送交易

一:前言

由于目前現(xiàn)在還沒(méi)有java的開(kāi)源filecoin交易的代碼,這面只做參考荐吵,目前是可以簽名并發(fā)送交易成功的错洁。
參考rust代碼。
https://github.com/Zondax/filecoin-signing-tools
大家可以先看下這個(gè)代碼疙剑。

代碼鏈接:
https://github.com/codeFarmL/FileCoin/tree/master

目前對(duì)于rust轉(zhuǎn)變java代碼只有一個(gè)細(xì)節(jié)是不確定的
給大家看下代碼:

 if (new BigInteger(unsignedMessageAPI.getValue()).toByteArray()[0] != 0) {
            byte[] byte1 = new byte[new BigInteger(unsignedMessageAPI.getValue()).toByteArray().length + 1];
            byte1[0] = 0;
            System.arraycopy(new BigInteger(unsignedMessageAPI.getValue()).toByteArray(), 0, byte1, 1, new BigInteger(unsignedMessageAPI.getValue()).toByteArray().length);
            valueByteString = new co.nstant.in.cbor.model
                    .ByteString(byte1);
        } else {
            valueByteString = new co.nstant.in.cbor.model
                    .ByteString(new BigInteger(unsignedMessageAPI.getValue()).toByteArray());
        }

        unsignedMessage.setValue(valueByteString);

也就是字節(jié)補(bǔ)0這氯迂,我一直看rust代碼沒(méi)看懂,這面我如果不做這個(gè)判斷言缤,形成的value字節(jié)總會(huì)少個(gè)0嚼蚀,這樣就和rust代碼的value字節(jié)對(duì)不上,所以這面我做了判斷管挟,如果轉(zhuǎn)換的value字節(jié)首位不是0則補(bǔ)0轿曙,是0則不補(bǔ)0,這面感覺(jué)會(huì)有問(wèn)題僻孝,
但是我試了20多筆都是可以發(fā)起交易的导帝。

大家先看交易。

二:交易流程:

用到的庫(kù):
ove.blake2b-alpha.0.jar (hash算法)
implementation 'co.nstant.in:cbor:0.9'(結(jié)構(gòu)體形成字節(jié))
implementation 'org.web3j:core:4.2.0'(簽名)

1穿铆,構(gòu)建交易結(jié)構(gòu)體:

生成業(yè)務(wù)的交易對(duì)象

 public static UnsignedMessageAPI createUnsignedMessageAPI(String json) {
        UnsignedMessageAPI unsignedMessageAPI = new UnsignedMessageAPI();
        unsignedMessageAPI.setFrom("f1b6esg2ynyuiwawowyzv3ioc7chboesp4ja6ewfi");
        unsignedMessageAPI.setTo("f1wlsdn2phpzczyalerizzrrhhpqjlsn67an54thq");
        unsignedMessageAPI.setNonce(12);
        unsignedMessageAPI.setValue("100000000000");
        unsignedMessageAPI.setGasFeeCap("101183");
        unsignedMessageAPI.setGasPremium("100129");
        unsignedMessageAPI.setGas_limit(1000000);
        unsignedMessageAPI.setMethod(0);
        unsignedMessageAPI.setParams("");
        return unsignedMessageAPI;
    }

value的值是乘以了10的18次方您单,原value是1個(gè)fil

交易的參數(shù):

public class UnsignedMessageAPI {
    private String to;
    private String from;
    private long nonce;
    private String value;
    private long gas_limit;
    private String gasFeeCap;
    private String gasPremium;
    private long method;
    private String params = "";
    public String getTo() {
        return to;
    }

    public void setTo(String to) {
        this.to = to;
    }

    public String getFrom() {
        return from;
    }

    public void setFrom(String from) {
        this.from = from;
    }

    public long getNonce() {
        return nonce;
    }

    public void setNonce(long nonce) {
        this.nonce = nonce;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public String getGasFeeCap() {
        return gasFeeCap;
    }

    public void setGasFeeCap(String gasFeeCap) {
        this.gasFeeCap = gasFeeCap;
    }

    public String getGasPremium() {
        return gasPremium;
    }

    public void setGasPremium(String gasPremium) {
        this.gasPremium = gasPremium;
    }

    public long getGas_limit() {
        return gas_limit;
    }

    public void setGas_limit(long gas_limit) {
        this.gas_limit = gas_limit;
    }

    public long getMethod() {
        return method;
    }

    public void setMethod(long method) {
        this.method = method;
    }

    public String getParams() {
        return params;
    }

    public void setParams(String params) {
        this.params = params;
    }

交易的序列化結(jié)構(gòu)體

public class UnsignedMessage {
   private UnsignedInteger version;
    private ByteString from;
    private ByteString to;
    private UnsignedInteger sequence;
    private ByteString value;
    private ByteString gasFeeCap;
    private ByteString gasPremium;
    private UnsignedInteger gas_limit;
    private UnsignedInteger method_num;
    private ByteString params; //空數(shù)組

    public UnsignedInteger getVersion() {
        return version;
    }

    public void setVersion(UnsignedInteger version) {
        this.version = version;
    }

    public ByteString getFrom() {
        return from;
    }

    public void setFrom(ByteString from) {
        this.from = from;
    }

    public ByteString getTo() {
        return to;
    }

    public void setTo(ByteString to) {
        this.to = to;
    }

    public UnsignedInteger getSequence() {
        return sequence;
    }

    public void setSequence(UnsignedInteger sequence) {
        this.sequence = sequence;
    }

    public ByteString getGasFeeCap() {
        return gasFeeCap;
    }

    public void setGasFeeCap(ByteString gasFeeCap) {
        this.gasFeeCap = gasFeeCap;
    }

    public ByteString getGasPremium() {
        return gasPremium;
    }

    public void setGasPremium(ByteString gasPremium) {
        this.gasPremium = gasPremium;
    }

    public ByteString getValue() {
        return value;
    }

    public void setValue(ByteString value) {
        this.value = value;
    }

    public UnsignedInteger getGas_limit() {
        return gas_limit;
    }

    public void setGas_limit(UnsignedInteger gas_limit) {
        this.gas_limit = gas_limit;
    }

    public UnsignedInteger getMethod_num() {
        return method_num;
    }

    public void setMethod_num(UnsignedInteger method_num) {
        this.method_num = method_num;
    }

    public ByteString getParams() {
        return params;
    }

    public void setParams(ByteString params) {
        this.params = params;
    }
}

通過(guò)交易參數(shù)構(gòu)建序列化結(jié)構(gòu)體

 public static UnsignedMessage try_from(UnsignedMessageAPI unsignedMessageAPI) {

       //構(gòu)建交易結(jié)構(gòu)體
        Address from = Address.from_str(unsignedMessageAPI.getFrom());
        Address to = Address.from_str(unsignedMessageAPI.getTo());
        UnsignedMessage unsignedMessage = new UnsignedMessage();
        unsignedMessage.setVersion(new UnsignedInteger(0));
        unsignedMessage.setTo(new co.nstant.in.cbor.model.ByteString(to.getPayload().getSecp256k1().getBytes()));

        unsignedMessage.setFrom(new co.nstant.in.cbor.model.ByteString(from.getPayload().getSecp256k1().getBytes()));

        unsignedMessage.setSequence(new UnsignedInteger(unsignedMessageAPI.getNonce()));
        co.nstant.in.cbor.model.ByteString valueByteString = null;
        if (new BigInteger(unsignedMessageAPI.getValue()).toByteArray()[0] != 0) {
            byte[] byte1 = new byte[new BigInteger(unsignedMessageAPI.getValue()).toByteArray().length + 1];
            byte1[0] = 0;
            System.arraycopy(new BigInteger(unsignedMessageAPI.getValue()).toByteArray(), 0, byte1, 1, new BigInteger(unsignedMessageAPI.getValue()).toByteArray().length);
            valueByteString = new co.nstant.in.cbor.model
                    .ByteString(byte1);
        } else {
            valueByteString = new co.nstant.in.cbor.model
                    .ByteString(new BigInteger(unsignedMessageAPI.getValue()).toByteArray());
        }

        unsignedMessage.setValue(valueByteString);
        unsignedMessage.setGas_limit(new UnsignedInteger(unsignedMessageAPI.getGas_limit()));

        co.nstant.in.cbor.model.ByteString gasFeeCapString = null;
        if (new BigInteger(unsignedMessageAPI.getGasFeeCap()).toByteArray()[0] != 0) {
            byte[] byte2 = new byte[new BigInteger(unsignedMessageAPI.getGasFeeCap()).toByteArray().length + 1];
            byte2[0] = 0;
            System.arraycopy(new BigInteger(unsignedMessageAPI.getGasFeeCap()).toByteArray(), 0, byte2, 1
                    , new BigInteger(unsignedMessageAPI.getGasFeeCap()).toByteArray().length);
            gasFeeCapString = new co.nstant.in.cbor.model
                    .ByteString(byte2);
        } else {
            gasFeeCapString = new co.nstant.in.cbor.model
                    .ByteString(new BigInteger(unsignedMessageAPI.getGasFeeCap()).toByteArray());
        }

        unsignedMessage.setGasFeeCap(gasFeeCapString);


        co.nstant.in.cbor.model.ByteString gasGasPremium = null;
        if (new BigInteger(unsignedMessageAPI.getGasPremium()).toByteArray()[0] != 0) {
            byte[] byte2 = new byte[new BigInteger(unsignedMessageAPI.getGasPremium()).toByteArray().length + 1];
            byte2[0] = 0;
            System.arraycopy(new BigInteger(unsignedMessageAPI.getGasPremium()).toByteArray(), 0, byte2, 1
                    , new BigInteger(unsignedMessageAPI.getGasPremium()).toByteArray().length);
            gasGasPremium = new co.nstant.in.cbor.model
                    .ByteString(byte2);
        } else {
            gasGasPremium = new co.nstant.in.cbor.model
                    .ByteString(new BigInteger(unsignedMessageAPI.getGasPremium()).toByteArray());
        }

        unsignedMessage.setGasPremium(gasGasPremium);


        unsignedMessage.setMethod_num(new UnsignedInteger(0));
        unsignedMessage.setParams(new co.nstant.in.cbor.model.ByteString(new byte[0]));
        return unsignedMessage;
    }

public class Address {
    private String network = "f";
    private Payload payload;  //應(yīng)該是字節(jié) 截取20位

    public String getNetwork() {
        return network;
    }

    public void setNetwork(String network) {
        this.network = network;
    }

    public Payload getPayload() {
        return payload;
    }

    public void setPayload(Payload payload) {
        this.payload = payload;
    }

    public static Address from_str(String addressStr) {
        Address address = new Address();
        //去掉前兩位
        String str = addressStr.substring(2);
        
        byte[] bytes12 = new byte[21];

        //為啥加1,因?yàn)槭荢ecp256k1的標(biāo)識(shí)就是1
        bytes12[0] = 1;
        System.arraycopy(Base32New.decode(str), 0, bytes12, 1, 20);
        Secp256k1 secp256k1 = new Secp256k1();
        secp256k1.setBytes(bytes12);
        Payload payload = new Payload();
        payload.setSecp256k1(secp256k1);
        address.setPayload(payload);
        return address;
    }
}

2荞雏,構(gòu)建完交易體之后生成交易字節(jié)

  /**
     * @param unsignedMessageAPI
     */
    public static void transaction_serialize(UnsignedMessageAPI unsignedMessageAPI) {
        /**
         * 拼接UnsignedMessage對(duì)象
         * 這面用的是CborEncoder
         * 問(wèn)題:什么是CborEncoder
         */
        UnsignedMessage unsignedMessage = try_from(unsignedMessageAPI);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            new CborEncoder(baos).encode(new CborBuilder()
                    .addArray()
                    .add(unsignedMessage.getVersion())
                    // add string
                    .add(unsignedMessage.getTo())
                    .add(unsignedMessage.getFrom())
                    .add(unsignedMessage.getSequence())
                    .add(unsignedMessage.getValue())
                    .add(unsignedMessage.getGas_limit())
                    .add(unsignedMessage.getGasFeeCap())
                    .add(unsignedMessage.getGasPremium())
                    .add(unsignedMessage.getMethod_num())
                    // add integer
                    .add(new co.nstant.in.cbor.model.ByteString(new byte[]{}))
                    .end()
                    .build());
            byte[] encodedBytes = baos.toByteArray();
            byte[] cidHashBytes = getCidHash(encodedBytes);
            sign(cidHashBytes);
        } catch (CborException e) {
            e.printStackTrace();
        }

    }

3,獲取CidHash

  /**
     * 形成摘要需要拼接的字符串
     */
    public static byte[] CID_PREFIX = new byte[]{0x01, 0x71, (byte) 0xa0, (byte) 0xe4, 0x02, 0x20};

    /**
     * @param message 交易結(jié)構(gòu)體的序列化字節(jié)
     *                通過(guò)交易結(jié)構(gòu)體字節(jié)獲取CidHash
     */
    public static byte[] getCidHash(byte[] message) {
        Blake2b.Param param = new Blake2b.Param();
        param.setDigestLength(32);

        //消息體字節(jié)
        byte[] messageByte = Blake2b.Digest.newInstance(param).digest(message);

        int xlen = CID_PREFIX.length;
        int ylen = messageByte.length;

        byte[] result = new byte[xlen + ylen];

        System.arraycopy(CID_PREFIX, 0, result, 0, xlen);
        System.arraycopy(messageByte, 0, result, xlen, ylen);

        byte[] prefixByte = Blake2b.Digest.newInstance(param).digest(result);
        String prefixByteHex = NumericUtil.bytesToHex(prefixByte);
        Log.d(TAG, prefixByteHex);

        return prefixByte;


    }

4,對(duì)cidHash進(jìn)行簽名(簽名用的是web3j的簽名庫(kù)):


    /**
     * @param cidHash 摘要
     *                對(duì)摘要進(jìn)行橢圓簽名橢圓簽名
     */
    public static void sign(byte[] cidHash) {
        ECKeyPair ecKeyPair = ECKeyPair.create(Numeric.toBigInt("私鑰"));
        org.web3j.crypto.Sign.SignatureData signatureData = org.web3j.crypto.Sign.signMessage(cidHash,
                ecKeyPair, false);
        byte[] sig = getSignature(signatureData);
        String stringHex = NumericUtil.bytesToHex(sig);
        Log.d(TAG, stringHex);
        String base64 = Base64.encodeToString(sig, Base64.DEFAULT);
        Log.d(TAG, "簽名字符串:" + base64);

    }

    /**
     * 獲取簽名
     *
     * @param signatureData
     * @return
     */
    private static byte[] getSignature(org.web3j.crypto.Sign.SignatureData signatureData) {
        byte[] sig = new byte[65];
        System.arraycopy(signatureData.getR(), 0, sig, 0, 32);
        System.arraycopy(signatureData.getS(), 0, sig, 32, 32);
        sig[64] = (byte) ((signatureData.getV() & 0xFF) - 27);//為啥減去27看signMessage()方法(內(nèi)部源碼)這面用的web3j的簽名庫(kù)虐秦,web3j的簽名對(duì)recId加了27,所以這面要減去拿到原v
        return sig;
    }

5讯檐,這樣就獲取到了簽名字符串羡疗。

三:總結(jié)

這樣就結(jié)束了。
本人也是看rust代碼翻譯過(guò)來(lái)的别洪,希望對(duì)大家有所幫助叨恨。

四:如何獲取gasLimit,gasFeeCap,gasPremium?

下篇文章介紹了FileCoin的Gas模型及獲取。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末挖垛,一起剝皮案震驚了整個(gè)濱河市痒钝,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌痢毒,老刑警劉巖送矩,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異哪替,居然都是意外死亡栋荸,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)晌块,“玉大人爱沟,你說(shuō)我怎么就攤上這事〈冶常” “怎么了呼伸?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)钝尸。 經(jīng)常有香客問(wèn)我括享,道長(zhǎng),這世上最難降的妖魔是什么珍促? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任铃辖,我火速辦了婚禮,結(jié)果婚禮上猪叙,老公的妹妹穿的比我還像新娘澳叉。我一直安慰自己,他們只是感情好沐悦,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布成洗。 她就那樣靜靜地躺著,像睡著了一般藏否。 火紅的嫁衣襯著肌膚如雪瓶殃。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,394評(píng)論 1 310
  • 那天副签,我揣著相機(jī)與錄音遥椿,去河邊找鬼。 笑死淆储,一個(gè)胖子當(dāng)著我的面吹牛冠场,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播本砰,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼碴裙,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了点额?” 一聲冷哼從身側(cè)響起舔株,我...
    開(kāi)封第一講書(shū)人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎还棱,沒(méi)想到半個(gè)月后载慈,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡珍手,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年办铡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了辞做。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡寡具,死狀恐怖凭豪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情晒杈,我是刑警寧澤,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布孔厉,位于F島的核電站拯钻,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏撰豺。R本人自食惡果不足惜粪般,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望污桦。 院中可真熱鬧亩歹,春花似錦、人聲如沸凡橱。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)稼钩。三九已至顾稀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間坝撑,已是汗流浹背静秆。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留巡李,地道東北人抚笔。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像侨拦,于是被迫代替她去往敵國(guó)和親殊橙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359