From 2e0f1590d72a4f84731d86dec0b3ea94ecf3e2de Mon Sep 17 00:00:00 2001 From: xizho10 Date: Mon, 16 Dec 2019 18:24:42 +0800 Subject: [PATCH 01/18] sdk update to v2.0.0 --- .classpath | 26 - .project | 23 - DNASDKJava.iml | 38 + README.md | 75 ++ README_CN.md | 498 ----------- docs/README.md | 68 ++ docs/Wallet_File_Specification_cn.md | 274 ++++++ docs/asset.md | 232 +++++ docs/attest.md | 254 ++++++ docs/auth.md | 339 ++++++++ docs/basic.md | 212 +++++ docs/errorcode.md | 89 ++ docs/governance.md | 347 ++++++++ docs/identity_claim.md | 465 ++++++++++ docs/interface.md | 296 +++++++ docs/sdk_get_start.md | 737 ++++++++++++++++ docs/smartcontract.md | 398 +++++++++ pom.xml | 203 ++++- src/main/java/DNA/Core/AssetType.java | 46 - src/main/java/DNA/Core/Block.java | 292 ------- src/main/java/DNA/Core/Blockchain.java | 310 ------- src/main/java/DNA/Core/BlockchainAbility.java | 40 - src/main/java/DNA/Core/BookKeeper.java | 37 - src/main/java/DNA/Core/BookKeeperAction.java | 23 - src/main/java/DNA/Core/BookKeeping.java | 28 - src/main/java/DNA/Core/Claimable.java | 13 - .../java/DNA/Core/DataFileTransaction.java | 38 - .../java/DNA/Core/DeployCodeTransaction.java | 36 - .../java/DNA/Core/DestroyTransaction.java | 14 - .../java/DNA/Core/EncryptedPayloadType.java | 25 - src/main/java/DNA/Core/FunctionCode.java | 81 -- src/main/java/DNA/Core/ICode.java | 9 - src/main/java/DNA/Core/IssueTransaction.java | 45 - .../java/DNA/Core/PayloadEncryptAttr.java | 8 - .../java/DNA/Core/PayloadEncryptType.java | 25 - .../DNA/Core/PrivacyPayloadTransaction.java | 34 - src/main/java/DNA/Core/RecordTransaction.java | 31 - src/main/java/DNA/Core/RecordType.java | 26 - .../java/DNA/Core/RegisterTransaction.java | 129 --- src/main/java/DNA/Core/Scripts/Program.java | 65 -- src/main/java/DNA/Core/Scripts/Script.java | 65 -- .../java/DNA/Core/Scripts/ScriptBuilder.java | 108 --- .../java/DNA/Core/Scripts/ScriptEngine.java | 6 - src/main/java/DNA/Core/Scripts/StackItem.java | 6 - src/main/java/DNA/Core/Signable.java | 65 -- src/main/java/DNA/Core/SignatureContext.java | 155 ---- .../java/DNA/Core/StateUpdateTransaction.java | 52 -- .../DNA/Core/StateUpdaterTransaction.java | 46 - src/main/java/DNA/Core/Transaction.java | 256 ------ .../java/DNA/Core/TransactionAttribute.java | 71 -- .../DNA/Core/TransactionAttributeUsage.java | 36 - src/main/java/DNA/Core/TransactionInput.java | 77 -- src/main/java/DNA/Core/TransactionOutput.java | 64 -- src/main/java/DNA/Core/TransactionResult.java | 22 - src/main/java/DNA/Core/TransactionType.java | 77 -- .../java/DNA/Core/TransferTransaction.java | 12 - src/main/java/DNA/Core/Vote.java | 17 - src/main/java/DNA/Cryptography/Base58.java | 58 -- src/main/java/DNA/Cryptography/Digest.java | 46 - src/main/java/DNA/Cryptography/ECC.java | 43 - src/main/java/DNA/Helper.java | 68 -- src/main/java/DNA/IO/BinaryReader.java | 163 ---- src/main/java/DNA/IO/Caching/ITrackable.java | 7 - src/main/java/DNA/IO/Caching/TrackState.java | 8 - .../DNA/IO/Caching/TrackableCollection.java | 79 -- src/main/java/DNA/IO/Json/JArray.java | 191 ---- src/main/java/DNA/IO/Json/JBigInt.java | 69 -- src/main/java/DNA/IO/Json/JBoolean.java | 62 -- src/main/java/DNA/IO/Json/JNumber.java | 68 -- src/main/java/DNA/IO/Json/JObject.java | 180 ---- src/main/java/DNA/IO/Json/JString.java | 85 -- src/main/java/DNA/IO/JsonReader.java | 36 - src/main/java/DNA/IO/JsonSerializable.java | 28 - src/main/java/DNA/IO/JsonWriter.java | 27 - src/main/java/DNA/IO/Serializable.java | 44 - src/main/java/DNA/IVersion.java | 20 - .../Blockchains/Rest/RestBlockchain.java | 159 ---- .../Wallets/AbstractWallet.java | 65 -- .../Wallets/AccountStoreType.java | 28 - .../Implementations/Wallets/IUserManager.java | 57 -- .../Wallets/SQLite/Account.java | 6 - .../Implementations/Wallets/SQLite/Coin.java | 10 - .../Wallets/SQLite/Contract.java | 7 - .../Implementations/Wallets/SQLite/Key.java | 6 - .../Wallets/SQLite/Transaction.java | 11 - .../Wallets/SQLite/TransactionInfo.java | 9 - .../Wallets/SQLite/UserWallet.java | 321 ------- .../Wallets/SQLite/WalletDataContext.java | 302 ------- .../Wallets/UserManagerFactory.java | 7 - src/main/java/DNA/Network/Inventory.java | 21 - src/main/java/DNA/Network/InventoryType.java | 38 - .../java/DNA/Network/Rest/RestClient.java | 253 ------ .../java/DNA/Network/Rest/RestException.java | 9 - src/main/java/DNA/Network/Rest/RestHttp.java | 215 ----- src/main/java/DNA/Network/Rest/RestNode.java | 255 ------ .../Network/Rest/RestRuntimeException.java | 17 - src/main/java/DNA/Out.java | 16 - src/main/java/DNA/UInt160.java | 58 -- src/main/java/DNA/UInt256.java | 58 -- src/main/java/DNA/Wallets/Account.java | 78 -- src/main/java/DNA/Wallets/Coin.java | 78 -- src/main/java/DNA/Wallets/CoinException.java | 13 - .../DNA/Wallets/CoinRuntimeException.java | 13 - src/main/java/DNA/Wallets/CoinState.java | 9 - src/main/java/DNA/Wallets/Contract.java | 161 ---- .../DNA/Wallets/ContractParameterType.java | 31 - src/main/java/DNA/Wallets/Wallet.java | 707 --------------- .../Utils/GetBlockTransactionUtils.java | 29 - .../java/DNA/Websocket/WebSocketClient.java | 6 - .../DNA/sdk/dbpool/ConnectionManager.java | 78 -- src/main/java/DNA/sdk/dbpool/DBConsts.java | 9 - .../java/DNA/sdk/dbpool/DBParamInitailer.java | 71 -- src/main/java/DNA/sdk/dbpool/DBPool.java | 116 --- src/main/java/DNA/sdk/dbpool/DBResource.java | 31 - .../java/DNA/sdk/dbpool/DBSQLException.java | 22 - src/main/java/DNA/sdk/dbpool/PrintHelper.java | 35 - src/main/java/DNA/sdk/helper/DataFormat.java | 112 --- .../java/DNA/sdk/helper/OnChainSDKHelper.java | 382 -------- .../DNA/sdk/info/account/AccountAsset.java | 22 - .../DNA/sdk/info/account/AccountInfo.java | 23 - src/main/java/DNA/sdk/info/account/Asset.java | 18 - .../java/DNA/sdk/info/asset/AssetInfo.java | 28 - .../java/DNA/sdk/info/asset/UTXO2Info.java | 15 - .../java/DNA/sdk/info/asset/UTXOInfo.java | 13 - .../java/DNA/sdk/info/mutil/TxJoiner.java | 14 - .../sdk/info/transaction/TransactionInfo.java | 24 - .../DNA/sdk/info/transaction/TxInputInfo.java | 19 - .../sdk/info/transaction/TxOutputInfo.java | 19 - .../java/DNA/sdk/wallet/AccountManager.java | 812 ------------------ src/main/java/TestMain4CLI.java | 257 ------ .../github/DNAProject/account/Account.java | 606 +++++++++++++ .../com/github/DNAProject/common/Address.java | 143 +++ .../com/github/DNAProject/common/Common.java | 45 + .../github/DNAProject/common/ErrorCode.java | 148 ++++ .../github/DNAProject/common}/Fixed8.java | 169 ++-- .../com/github/DNAProject/common/Helper.java | 153 ++++ .../DNAProject/common/NotifyEventInfo.java | 36 + .../DNAProject/common/SmartCodeEvent.java | 43 + .../com/github/DNAProject/common/UInt256.java | 77 ++ .../github/DNAProject/common}/UIntBase.java | 53 +- .../github/DNAProject/common/WalletQR.java | 93 ++ .../github/DNAProject/core/DataSignature.java | 99 +++ .../com/github/DNAProject/core/Inventory.java | 39 + .../github/DNAProject/core/InventoryType.java | 45 + .../com/github/DNAProject/core/Signable.java | 60 ++ .../com/github/DNAProject/core/VmType.java | 46 + .../DNAProject/core/asset/Contract.java | 80 ++ .../com/github/DNAProject/core/asset/Sig.java | 82 ++ .../github/DNAProject/core/asset/State.java | 79 ++ .../DNAProject/core/asset/TransferFrom.java | 79 ++ .../DNAProject/core/asset/Transfers.java | 84 ++ .../github/DNAProject/core/block/Block.java | 255 ++++++ .../DNAProject/core/dnaid/Attribute.java | 51 ++ .../DNAProject/core/globalparams/Param.java | 11 + .../DNAProject/core/globalparams/Params.java | 33 + .../core/governance/AuthorizeInfo.java | 79 ++ .../core/governance/Configuration.java | 50 ++ .../core/governance/GlobalParam.java | 35 + .../core/governance/GlobalParam1.java | 43 + .../core/governance/GlobalParam2.java | 51 ++ .../core/governance/GovernanceView.java | 40 + .../governance/InputPeerPoolMapParam.java | 14 + .../governance/NodeToSideChainParams.java | 28 + .../core/governance/PeerPoolItem.java | 83 ++ .../core/governance/SplitCurve.java | 35 + .../DNAProject/core/payload/Bookkeeper.java | 67 ++ .../core/payload/BookkeeperAction.java | 44 + .../DNAProject/core/payload/Bookkeeping.java | 62 ++ .../DNAProject/core/payload/DeployCode.java | 74 ++ .../core/payload/DeployWasmCode.java | 94 ++ .../DNAProject/core/payload/Enrollment.java | 64 ++ .../DNAProject/core/payload/InvokeCode.java | 68 ++ .../core/payload/InvokeWasmCode.java | 32 + .../github/DNAProject/core/payload/Vote.java | 73 ++ .../DNAProject/core/program/Program.java | 234 +++++ .../DNAProject/core/program/ProgramInfo.java | 26 + .../core/scripts/ScriptBuilder.java | 132 +++ .../DNAProject/core/scripts}/ScriptOp.java | 116 ++- .../core/scripts/WasmScriptBuilder.java | 186 ++++ .../sidechaingovernance/InflationParam.java | 17 + .../NodeToSideChainParams.java | 33 + .../QuitSideChainParam.java | 14 + .../RegisterSideChainParam.java | 23 + .../core/sidechaingovernance/SideChain.java | 55 ++ .../SideChainNodeInfo.java | 36 + .../core/sidechaingovernance/SwapParam.java | 26 + .../core/transaction/Attribute.java | 84 ++ .../core/transaction/AttributeUsage.java | 49 ++ .../core/transaction/Transaction.java | 193 +++++ .../core/transaction/TransactionType.java | 52 ++ .../github/DNAProject/crypto}/AES.java | 24 +- .../com/github/DNAProject/crypto/Base58.java | 104 +++ .../com/github/DNAProject/crypto/Curve.java | 51 ++ .../com/github/DNAProject/crypto/Digest.java | 90 ++ .../com/github/DNAProject/crypto/ECC.java | 62 ++ .../com/github/DNAProject/crypto/KeyType.java | 43 + .../github/DNAProject/crypto}/MerkleTree.java | 31 +- .../DNAProject/crypto/MnemonicCode.java | 141 +++ .../github/DNAProject/crypto/Signature.java | 74 ++ .../DNAProject/crypto/SignatureHandler.java | 115 +++ .../DNAProject/crypto/SignatureScheme.java | 36 + .../DNAProject/crypto/bip32/Bitcoin.java | 34 + .../crypto/bip32/ByteArrayReader.java | 58 ++ .../crypto/bip32/ByteArrayWriter.java | 69 ++ .../DNAProject/crypto/bip32/CKDpriv.java | 31 + .../DNAProject/crypto/bip32/CKDpub.java | 24 + .../DNAProject/crypto/bip32/Derivation.java | 36 + .../DNAProject/crypto/bip32/Deserializer.java | 41 + .../github/DNAProject/crypto/bip32/HdKey.java | 202 +++++ .../DNAProject/crypto/bip32/HdPrivateKey.java | 258 ++++++ .../bip32/HdPrivateKeyDeserializer.java | 77 ++ .../DNAProject/crypto/bip32/HdPublicKey.java | 168 ++++ .../crypto/bip32/HdPublicKeyDeserializer.java | 70 ++ .../DNAProject/crypto/bip32/Network.java | 32 + .../DNAProject/crypto/bip32/Secp256r1SC.java | 58 ++ .../DNAProject/crypto/bip32/Serializer.java | 121 +++ .../derivation/CharSequenceDerivation.java | 61 ++ .../crypto/bip32/derivation/CkdFunction.java | 34 + .../bip32/derivation/CkdFunctionDerive.java | 43 + .../CkdFunctionResultCacheDecorator.java | 63 ++ .../crypto/bip32/derivation/Derivation.java | 36 + .../crypto/bip32/derivation/Derive.java | 43 + .../github/DNAProject/io/BinaryReader.java | 231 +++++ .../github/DNAProject/io}/BinaryWriter.java | 23 +- .../github/DNAProject/io/Serializable.java | 69 ++ .../java/com/github/DNAProject/io/utils.java | 20 + .../DNAProject/merkle/MerkleVerifier.java | 127 +++ .../DNAProject/network/rest/Result.java | 34 + .../DNAProject/network/rest/UrlConsts.java | 48 ++ .../github/DNAProject/network/rest/X509.java | 42 + .../DNAProject/network/rpc/Interfaces.java | 103 +++ .../DNAProject/network/rpc/RpcClient.java | 293 +++++++ .../github/DNAProject/sdk/claim/Claim.java | 194 +++++ .../sdk/exception/SDKException.java | 45 + .../sdk/exception/SDKRuntimeException.java | 39 + .../DNAProject/sdk/info/AccountInfo.java | 54 ++ .../DNAProject/sdk/info/IdentityInfo.java | 54 ++ .../DNAProject/sdk/manager/ConnectMgr.java | 305 +++++++ .../github/DNAProject/sdk/manager/ECIES.java | 158 ++++ .../DNAProject/sdk/manager/SignServer.java | 121 +++ .../DNAProject/sdk/manager/WalletMgr.java | 422 +++++++++ .../github/DNAProject/sdk/wallet/Account.java | 108 +++ .../github/DNAProject/sdk/wallet/Control.java | 78 ++ .../DNAProject/sdk/wallet/Identity.java | 49 ++ .../github/DNAProject/sdk/wallet/Scrypt.java | 89 ++ .../github/DNAProject/sdk/wallet/Wallet.java | 274 ++++++ src/main/java/example/ECIESDemo.java | 76 ++ src/main/java/example/MnemonicDemo.java | 50 ++ src/main/java/example/api/ApiDemo.java | 38 + src/main/java/example/api/Demo.java | 132 +++ src/main/java/example/api/WebsocketDemo.java | 200 +++++ src/main/java/example/dnaid/AuthDemo.java | 154 ++++ src/main/java/example/dnaid/ClaimDemo.java | 86 ++ .../java/example/dnaid/ClaimRecordTxDemo.java | 136 +++ src/main/java/example/dnaid/DnaIdDemo.java | 171 ++++ .../java/example/dnaid/merkleProofDemo.java | 65 ++ src/main/java/example/gas/ExchangeDemo.java | 430 ++++++++++ src/main/java/example/gas/GasDemo.java | 181 ++++ src/main/java/example/gas/GasDemo2.java | 156 ++++ src/main/java/example/gas/PayForUserDemo.java | 83 ++ .../example/governance/GlobalParamDemo.java | 131 +++ .../example/governance/GovernanceDemo.java | 232 +++++ .../example/governance/GovernanceDemo2.java | 204 +++++ src/main/java/example/oep/Oep4Demo.java | 192 +++++ src/main/java/example/oep/Oep4Demo2.java | 170 ++++ .../java/example/oep/Oep4MultiTheadDemo.java | 103 +++ src/main/java/example/oep/Oep5Demo.java | 125 +++ src/main/java/example/oep/Oep8Demo.java | 206 +++++ .../java/example/signature/MutiSignDemo.java | 92 ++ .../example/signature/SignServerDemo.java | 40 + .../java/example/signature/SignatureDemo.java | 50 ++ .../signature/VerifyTxSignatureDemo.java | 72 ++ .../example/smartcontract/DeployCodeDemo.java | 107 +++ .../java/example/smartcontract/NeoVmDemo.java | 137 +++ .../example/smartcontract/NeoVmDemo3.java | 733 ++++++++++++++++ .../example/smartcontract/PunicaInitDemo.java | 387 +++++++++ .../example/smartcontract/RecordTxDemo.java | 54 ++ .../example/transaction/CreateManyTx.java | 80 ++ .../transaction/MakeTxWithJsonDemo.java | 123 +++ .../transaction/MakeTxWithoutWalletDemo.java | 181 ++++ src/main/java/example/wallet/AccountDemo.java | 106 +++ src/main/java/example/wallet/QrCodeDemo.java | 19 + src/main/java/example/wallet/WalletDemo.java | 69 ++ 283 files changed, 19633 insertions(+), 9688 deletions(-) delete mode 100644 .classpath delete mode 100644 .project create mode 100644 DNASDKJava.iml create mode 100644 README.md delete mode 100644 README_CN.md create mode 100644 docs/README.md create mode 100644 docs/Wallet_File_Specification_cn.md create mode 100644 docs/asset.md create mode 100644 docs/attest.md create mode 100644 docs/auth.md create mode 100644 docs/basic.md create mode 100644 docs/errorcode.md create mode 100644 docs/governance.md create mode 100644 docs/identity_claim.md create mode 100644 docs/interface.md create mode 100644 docs/sdk_get_start.md create mode 100644 docs/smartcontract.md delete mode 100644 src/main/java/DNA/Core/AssetType.java delete mode 100644 src/main/java/DNA/Core/Block.java delete mode 100644 src/main/java/DNA/Core/Blockchain.java delete mode 100644 src/main/java/DNA/Core/BlockchainAbility.java delete mode 100644 src/main/java/DNA/Core/BookKeeper.java delete mode 100644 src/main/java/DNA/Core/BookKeeperAction.java delete mode 100644 src/main/java/DNA/Core/BookKeeping.java delete mode 100644 src/main/java/DNA/Core/Claimable.java delete mode 100644 src/main/java/DNA/Core/DataFileTransaction.java delete mode 100644 src/main/java/DNA/Core/DeployCodeTransaction.java delete mode 100644 src/main/java/DNA/Core/DestroyTransaction.java delete mode 100644 src/main/java/DNA/Core/EncryptedPayloadType.java delete mode 100644 src/main/java/DNA/Core/FunctionCode.java delete mode 100644 src/main/java/DNA/Core/ICode.java delete mode 100644 src/main/java/DNA/Core/IssueTransaction.java delete mode 100644 src/main/java/DNA/Core/PayloadEncryptAttr.java delete mode 100644 src/main/java/DNA/Core/PayloadEncryptType.java delete mode 100644 src/main/java/DNA/Core/PrivacyPayloadTransaction.java delete mode 100644 src/main/java/DNA/Core/RecordTransaction.java delete mode 100644 src/main/java/DNA/Core/RecordType.java delete mode 100644 src/main/java/DNA/Core/RegisterTransaction.java delete mode 100644 src/main/java/DNA/Core/Scripts/Program.java delete mode 100644 src/main/java/DNA/Core/Scripts/Script.java delete mode 100644 src/main/java/DNA/Core/Scripts/ScriptBuilder.java delete mode 100644 src/main/java/DNA/Core/Scripts/ScriptEngine.java delete mode 100644 src/main/java/DNA/Core/Scripts/StackItem.java delete mode 100644 src/main/java/DNA/Core/Signable.java delete mode 100644 src/main/java/DNA/Core/SignatureContext.java delete mode 100644 src/main/java/DNA/Core/StateUpdateTransaction.java delete mode 100644 src/main/java/DNA/Core/StateUpdaterTransaction.java delete mode 100644 src/main/java/DNA/Core/Transaction.java delete mode 100644 src/main/java/DNA/Core/TransactionAttribute.java delete mode 100644 src/main/java/DNA/Core/TransactionAttributeUsage.java delete mode 100644 src/main/java/DNA/Core/TransactionInput.java delete mode 100644 src/main/java/DNA/Core/TransactionOutput.java delete mode 100644 src/main/java/DNA/Core/TransactionResult.java delete mode 100644 src/main/java/DNA/Core/TransactionType.java delete mode 100644 src/main/java/DNA/Core/TransferTransaction.java delete mode 100644 src/main/java/DNA/Core/Vote.java delete mode 100644 src/main/java/DNA/Cryptography/Base58.java delete mode 100644 src/main/java/DNA/Cryptography/Digest.java delete mode 100644 src/main/java/DNA/Cryptography/ECC.java delete mode 100644 src/main/java/DNA/Helper.java delete mode 100644 src/main/java/DNA/IO/BinaryReader.java delete mode 100644 src/main/java/DNA/IO/Caching/ITrackable.java delete mode 100644 src/main/java/DNA/IO/Caching/TrackState.java delete mode 100644 src/main/java/DNA/IO/Caching/TrackableCollection.java delete mode 100644 src/main/java/DNA/IO/Json/JArray.java delete mode 100644 src/main/java/DNA/IO/Json/JBigInt.java delete mode 100644 src/main/java/DNA/IO/Json/JBoolean.java delete mode 100644 src/main/java/DNA/IO/Json/JNumber.java delete mode 100644 src/main/java/DNA/IO/Json/JObject.java delete mode 100644 src/main/java/DNA/IO/Json/JString.java delete mode 100644 src/main/java/DNA/IO/JsonReader.java delete mode 100644 src/main/java/DNA/IO/JsonSerializable.java delete mode 100644 src/main/java/DNA/IO/JsonWriter.java delete mode 100644 src/main/java/DNA/IO/Serializable.java delete mode 100644 src/main/java/DNA/IVersion.java delete mode 100644 src/main/java/DNA/Implementations/Blockchains/Rest/RestBlockchain.java delete mode 100644 src/main/java/DNA/Implementations/Wallets/AbstractWallet.java delete mode 100644 src/main/java/DNA/Implementations/Wallets/AccountStoreType.java delete mode 100644 src/main/java/DNA/Implementations/Wallets/IUserManager.java delete mode 100644 src/main/java/DNA/Implementations/Wallets/SQLite/Account.java delete mode 100644 src/main/java/DNA/Implementations/Wallets/SQLite/Coin.java delete mode 100644 src/main/java/DNA/Implementations/Wallets/SQLite/Contract.java delete mode 100644 src/main/java/DNA/Implementations/Wallets/SQLite/Key.java delete mode 100644 src/main/java/DNA/Implementations/Wallets/SQLite/Transaction.java delete mode 100644 src/main/java/DNA/Implementations/Wallets/SQLite/TransactionInfo.java delete mode 100644 src/main/java/DNA/Implementations/Wallets/SQLite/UserWallet.java delete mode 100644 src/main/java/DNA/Implementations/Wallets/SQLite/WalletDataContext.java delete mode 100644 src/main/java/DNA/Implementations/Wallets/UserManagerFactory.java delete mode 100644 src/main/java/DNA/Network/Inventory.java delete mode 100644 src/main/java/DNA/Network/InventoryType.java delete mode 100644 src/main/java/DNA/Network/Rest/RestClient.java delete mode 100644 src/main/java/DNA/Network/Rest/RestException.java delete mode 100644 src/main/java/DNA/Network/Rest/RestHttp.java delete mode 100644 src/main/java/DNA/Network/Rest/RestNode.java delete mode 100644 src/main/java/DNA/Network/Rest/RestRuntimeException.java delete mode 100644 src/main/java/DNA/Out.java delete mode 100644 src/main/java/DNA/UInt160.java delete mode 100644 src/main/java/DNA/UInt256.java delete mode 100644 src/main/java/DNA/Wallets/Account.java delete mode 100644 src/main/java/DNA/Wallets/Coin.java delete mode 100644 src/main/java/DNA/Wallets/CoinException.java delete mode 100644 src/main/java/DNA/Wallets/CoinRuntimeException.java delete mode 100644 src/main/java/DNA/Wallets/CoinState.java delete mode 100644 src/main/java/DNA/Wallets/Contract.java delete mode 100644 src/main/java/DNA/Wallets/ContractParameterType.java delete mode 100644 src/main/java/DNA/Wallets/Wallet.java delete mode 100644 src/main/java/DNA/Websocket/Utils/GetBlockTransactionUtils.java delete mode 100644 src/main/java/DNA/Websocket/WebSocketClient.java delete mode 100644 src/main/java/DNA/sdk/dbpool/ConnectionManager.java delete mode 100644 src/main/java/DNA/sdk/dbpool/DBConsts.java delete mode 100644 src/main/java/DNA/sdk/dbpool/DBParamInitailer.java delete mode 100644 src/main/java/DNA/sdk/dbpool/DBPool.java delete mode 100644 src/main/java/DNA/sdk/dbpool/DBResource.java delete mode 100644 src/main/java/DNA/sdk/dbpool/DBSQLException.java delete mode 100644 src/main/java/DNA/sdk/dbpool/PrintHelper.java delete mode 100644 src/main/java/DNA/sdk/helper/DataFormat.java delete mode 100644 src/main/java/DNA/sdk/helper/OnChainSDKHelper.java delete mode 100644 src/main/java/DNA/sdk/info/account/AccountAsset.java delete mode 100644 src/main/java/DNA/sdk/info/account/AccountInfo.java delete mode 100644 src/main/java/DNA/sdk/info/account/Asset.java delete mode 100644 src/main/java/DNA/sdk/info/asset/AssetInfo.java delete mode 100644 src/main/java/DNA/sdk/info/asset/UTXO2Info.java delete mode 100644 src/main/java/DNA/sdk/info/asset/UTXOInfo.java delete mode 100644 src/main/java/DNA/sdk/info/mutil/TxJoiner.java delete mode 100644 src/main/java/DNA/sdk/info/transaction/TransactionInfo.java delete mode 100644 src/main/java/DNA/sdk/info/transaction/TxInputInfo.java delete mode 100644 src/main/java/DNA/sdk/info/transaction/TxOutputInfo.java delete mode 100644 src/main/java/DNA/sdk/wallet/AccountManager.java delete mode 100644 src/main/java/TestMain4CLI.java create mode 100644 src/main/java/com/github/DNAProject/account/Account.java create mode 100644 src/main/java/com/github/DNAProject/common/Address.java create mode 100644 src/main/java/com/github/DNAProject/common/Common.java create mode 100644 src/main/java/com/github/DNAProject/common/ErrorCode.java rename src/main/java/{DNA => com/github/DNAProject/common}/Fixed8.java (55%) create mode 100644 src/main/java/com/github/DNAProject/common/Helper.java create mode 100644 src/main/java/com/github/DNAProject/common/NotifyEventInfo.java create mode 100644 src/main/java/com/github/DNAProject/common/SmartCodeEvent.java create mode 100644 src/main/java/com/github/DNAProject/common/UInt256.java rename src/main/java/{DNA => com/github/DNAProject/common}/UIntBase.java (51%) create mode 100644 src/main/java/com/github/DNAProject/common/WalletQR.java create mode 100644 src/main/java/com/github/DNAProject/core/DataSignature.java create mode 100644 src/main/java/com/github/DNAProject/core/Inventory.java create mode 100644 src/main/java/com/github/DNAProject/core/InventoryType.java create mode 100644 src/main/java/com/github/DNAProject/core/Signable.java create mode 100644 src/main/java/com/github/DNAProject/core/VmType.java create mode 100644 src/main/java/com/github/DNAProject/core/asset/Contract.java create mode 100644 src/main/java/com/github/DNAProject/core/asset/Sig.java create mode 100644 src/main/java/com/github/DNAProject/core/asset/State.java create mode 100644 src/main/java/com/github/DNAProject/core/asset/TransferFrom.java create mode 100644 src/main/java/com/github/DNAProject/core/asset/Transfers.java create mode 100644 src/main/java/com/github/DNAProject/core/block/Block.java create mode 100644 src/main/java/com/github/DNAProject/core/dnaid/Attribute.java create mode 100644 src/main/java/com/github/DNAProject/core/globalparams/Param.java create mode 100644 src/main/java/com/github/DNAProject/core/globalparams/Params.java create mode 100644 src/main/java/com/github/DNAProject/core/governance/AuthorizeInfo.java create mode 100644 src/main/java/com/github/DNAProject/core/governance/Configuration.java create mode 100644 src/main/java/com/github/DNAProject/core/governance/GlobalParam.java create mode 100644 src/main/java/com/github/DNAProject/core/governance/GlobalParam1.java create mode 100644 src/main/java/com/github/DNAProject/core/governance/GlobalParam2.java create mode 100644 src/main/java/com/github/DNAProject/core/governance/GovernanceView.java create mode 100644 src/main/java/com/github/DNAProject/core/governance/InputPeerPoolMapParam.java create mode 100644 src/main/java/com/github/DNAProject/core/governance/NodeToSideChainParams.java create mode 100644 src/main/java/com/github/DNAProject/core/governance/PeerPoolItem.java create mode 100644 src/main/java/com/github/DNAProject/core/governance/SplitCurve.java create mode 100644 src/main/java/com/github/DNAProject/core/payload/Bookkeeper.java create mode 100644 src/main/java/com/github/DNAProject/core/payload/BookkeeperAction.java create mode 100644 src/main/java/com/github/DNAProject/core/payload/Bookkeeping.java create mode 100644 src/main/java/com/github/DNAProject/core/payload/DeployCode.java create mode 100644 src/main/java/com/github/DNAProject/core/payload/DeployWasmCode.java create mode 100644 src/main/java/com/github/DNAProject/core/payload/Enrollment.java create mode 100644 src/main/java/com/github/DNAProject/core/payload/InvokeCode.java create mode 100644 src/main/java/com/github/DNAProject/core/payload/InvokeWasmCode.java create mode 100644 src/main/java/com/github/DNAProject/core/payload/Vote.java create mode 100644 src/main/java/com/github/DNAProject/core/program/Program.java create mode 100644 src/main/java/com/github/DNAProject/core/program/ProgramInfo.java create mode 100644 src/main/java/com/github/DNAProject/core/scripts/ScriptBuilder.java rename src/main/java/{DNA/Core/Scripts => com/github/DNAProject/core/scripts}/ScriptOp.java (65%) create mode 100644 src/main/java/com/github/DNAProject/core/scripts/WasmScriptBuilder.java create mode 100644 src/main/java/com/github/DNAProject/core/sidechaingovernance/InflationParam.java create mode 100644 src/main/java/com/github/DNAProject/core/sidechaingovernance/NodeToSideChainParams.java create mode 100644 src/main/java/com/github/DNAProject/core/sidechaingovernance/QuitSideChainParam.java create mode 100644 src/main/java/com/github/DNAProject/core/sidechaingovernance/RegisterSideChainParam.java create mode 100644 src/main/java/com/github/DNAProject/core/sidechaingovernance/SideChain.java create mode 100644 src/main/java/com/github/DNAProject/core/sidechaingovernance/SideChainNodeInfo.java create mode 100644 src/main/java/com/github/DNAProject/core/sidechaingovernance/SwapParam.java create mode 100644 src/main/java/com/github/DNAProject/core/transaction/Attribute.java create mode 100644 src/main/java/com/github/DNAProject/core/transaction/AttributeUsage.java create mode 100644 src/main/java/com/github/DNAProject/core/transaction/Transaction.java create mode 100644 src/main/java/com/github/DNAProject/core/transaction/TransactionType.java rename src/main/java/{DNA/Cryptography => com/github/DNAProject/crypto}/AES.java (78%) create mode 100644 src/main/java/com/github/DNAProject/crypto/Base58.java create mode 100644 src/main/java/com/github/DNAProject/crypto/Curve.java create mode 100644 src/main/java/com/github/DNAProject/crypto/Digest.java create mode 100644 src/main/java/com/github/DNAProject/crypto/ECC.java create mode 100644 src/main/java/com/github/DNAProject/crypto/KeyType.java rename src/main/java/{DNA/Cryptography => com/github/DNAProject/crypto}/MerkleTree.java (60%) create mode 100644 src/main/java/com/github/DNAProject/crypto/MnemonicCode.java create mode 100644 src/main/java/com/github/DNAProject/crypto/Signature.java create mode 100644 src/main/java/com/github/DNAProject/crypto/SignatureHandler.java create mode 100644 src/main/java/com/github/DNAProject/crypto/SignatureScheme.java create mode 100644 src/main/java/com/github/DNAProject/crypto/bip32/Bitcoin.java create mode 100644 src/main/java/com/github/DNAProject/crypto/bip32/ByteArrayReader.java create mode 100644 src/main/java/com/github/DNAProject/crypto/bip32/ByteArrayWriter.java create mode 100644 src/main/java/com/github/DNAProject/crypto/bip32/CKDpriv.java create mode 100644 src/main/java/com/github/DNAProject/crypto/bip32/CKDpub.java create mode 100644 src/main/java/com/github/DNAProject/crypto/bip32/Derivation.java create mode 100644 src/main/java/com/github/DNAProject/crypto/bip32/Deserializer.java create mode 100644 src/main/java/com/github/DNAProject/crypto/bip32/HdKey.java create mode 100644 src/main/java/com/github/DNAProject/crypto/bip32/HdPrivateKey.java create mode 100644 src/main/java/com/github/DNAProject/crypto/bip32/HdPrivateKeyDeserializer.java create mode 100644 src/main/java/com/github/DNAProject/crypto/bip32/HdPublicKey.java create mode 100644 src/main/java/com/github/DNAProject/crypto/bip32/HdPublicKeyDeserializer.java create mode 100644 src/main/java/com/github/DNAProject/crypto/bip32/Network.java create mode 100644 src/main/java/com/github/DNAProject/crypto/bip32/Secp256r1SC.java create mode 100644 src/main/java/com/github/DNAProject/crypto/bip32/Serializer.java create mode 100644 src/main/java/com/github/DNAProject/crypto/bip32/derivation/CharSequenceDerivation.java create mode 100644 src/main/java/com/github/DNAProject/crypto/bip32/derivation/CkdFunction.java create mode 100644 src/main/java/com/github/DNAProject/crypto/bip32/derivation/CkdFunctionDerive.java create mode 100644 src/main/java/com/github/DNAProject/crypto/bip32/derivation/CkdFunctionResultCacheDecorator.java create mode 100644 src/main/java/com/github/DNAProject/crypto/bip32/derivation/Derivation.java create mode 100644 src/main/java/com/github/DNAProject/crypto/bip32/derivation/Derive.java create mode 100644 src/main/java/com/github/DNAProject/io/BinaryReader.java rename src/main/java/{DNA/IO => com/github/DNAProject/io}/BinaryWriter.java (78%) create mode 100644 src/main/java/com/github/DNAProject/io/Serializable.java create mode 100644 src/main/java/com/github/DNAProject/io/utils.java create mode 100644 src/main/java/com/github/DNAProject/merkle/MerkleVerifier.java create mode 100644 src/main/java/com/github/DNAProject/network/rest/Result.java create mode 100644 src/main/java/com/github/DNAProject/network/rest/UrlConsts.java create mode 100644 src/main/java/com/github/DNAProject/network/rest/X509.java create mode 100644 src/main/java/com/github/DNAProject/network/rpc/Interfaces.java create mode 100644 src/main/java/com/github/DNAProject/network/rpc/RpcClient.java create mode 100644 src/main/java/com/github/DNAProject/sdk/claim/Claim.java create mode 100644 src/main/java/com/github/DNAProject/sdk/exception/SDKException.java create mode 100644 src/main/java/com/github/DNAProject/sdk/exception/SDKRuntimeException.java create mode 100644 src/main/java/com/github/DNAProject/sdk/info/AccountInfo.java create mode 100644 src/main/java/com/github/DNAProject/sdk/info/IdentityInfo.java create mode 100644 src/main/java/com/github/DNAProject/sdk/manager/ConnectMgr.java create mode 100644 src/main/java/com/github/DNAProject/sdk/manager/ECIES.java create mode 100644 src/main/java/com/github/DNAProject/sdk/manager/SignServer.java create mode 100644 src/main/java/com/github/DNAProject/sdk/manager/WalletMgr.java create mode 100644 src/main/java/com/github/DNAProject/sdk/wallet/Account.java create mode 100644 src/main/java/com/github/DNAProject/sdk/wallet/Control.java create mode 100644 src/main/java/com/github/DNAProject/sdk/wallet/Identity.java create mode 100644 src/main/java/com/github/DNAProject/sdk/wallet/Scrypt.java create mode 100644 src/main/java/com/github/DNAProject/sdk/wallet/Wallet.java create mode 100644 src/main/java/example/ECIESDemo.java create mode 100644 src/main/java/example/MnemonicDemo.java create mode 100644 src/main/java/example/api/ApiDemo.java create mode 100644 src/main/java/example/api/Demo.java create mode 100644 src/main/java/example/api/WebsocketDemo.java create mode 100644 src/main/java/example/dnaid/AuthDemo.java create mode 100644 src/main/java/example/dnaid/ClaimDemo.java create mode 100644 src/main/java/example/dnaid/ClaimRecordTxDemo.java create mode 100644 src/main/java/example/dnaid/DnaIdDemo.java create mode 100644 src/main/java/example/dnaid/merkleProofDemo.java create mode 100644 src/main/java/example/gas/ExchangeDemo.java create mode 100644 src/main/java/example/gas/GasDemo.java create mode 100644 src/main/java/example/gas/GasDemo2.java create mode 100644 src/main/java/example/gas/PayForUserDemo.java create mode 100644 src/main/java/example/governance/GlobalParamDemo.java create mode 100644 src/main/java/example/governance/GovernanceDemo.java create mode 100644 src/main/java/example/governance/GovernanceDemo2.java create mode 100644 src/main/java/example/oep/Oep4Demo.java create mode 100644 src/main/java/example/oep/Oep4Demo2.java create mode 100644 src/main/java/example/oep/Oep4MultiTheadDemo.java create mode 100644 src/main/java/example/oep/Oep5Demo.java create mode 100644 src/main/java/example/oep/Oep8Demo.java create mode 100644 src/main/java/example/signature/MutiSignDemo.java create mode 100644 src/main/java/example/signature/SignServerDemo.java create mode 100644 src/main/java/example/signature/SignatureDemo.java create mode 100644 src/main/java/example/signature/VerifyTxSignatureDemo.java create mode 100644 src/main/java/example/smartcontract/DeployCodeDemo.java create mode 100644 src/main/java/example/smartcontract/NeoVmDemo.java create mode 100644 src/main/java/example/smartcontract/NeoVmDemo3.java create mode 100644 src/main/java/example/smartcontract/PunicaInitDemo.java create mode 100644 src/main/java/example/smartcontract/RecordTxDemo.java create mode 100644 src/main/java/example/transaction/CreateManyTx.java create mode 100644 src/main/java/example/transaction/MakeTxWithJsonDemo.java create mode 100644 src/main/java/example/transaction/MakeTxWithoutWalletDemo.java create mode 100644 src/main/java/example/wallet/AccountDemo.java create mode 100644 src/main/java/example/wallet/QrCodeDemo.java create mode 100644 src/main/java/example/wallet/WalletDemo.java diff --git a/.classpath b/.classpath deleted file mode 100644 index 7cfb3a1..0000000 --- a/.classpath +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/.project b/.project deleted file mode 100644 index c6bfe49..0000000 --- a/.project +++ /dev/null @@ -1,23 +0,0 @@ - - - DNA-SDK - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - org.eclipse.jdt.core.javanature - org.eclipse.m2e.core.maven2Nature - - diff --git a/DNASDKJava.iml b/DNASDKJava.iml new file mode 100644 index 0000000..7c55cc4 --- /dev/null +++ b/DNASDKJava.iml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..4eda7da --- /dev/null +++ b/README.md @@ -0,0 +1,75 @@ + +

JAVA SDK For DNA

+

Version 2.0.0

+ +## Overview + +This is a comprehensive Java library for the DNA blockchain. Currently, it supports local wallet management, digital identity management, digital asset management, deployment and invoke for Smart Contract , and communication with DNA Blockchain. The future will also support more rich functions and applications . + +## Getting started + +* 进入 [中文版](docs/README.md) . + + +## Installation Environment + +Please configure JDK 8 and above. + +> **Note:** As the length of key used in SDK is greater than 128, due to the restriction of JAVA security policy files, it is necessary to download local_policy.jar and US_export_policy.jar from the official website , to replace the two jar of ${java_home}/jre/lib/security in JRE directory. + +Download URL: + +>http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html + + +## Build + +``` +mvn clean install +``` + +## Preparations + +* Make sure DNA Blockchain has deployed well, RPC port has been opened, and SDK will connect the RPC server to initialize. + + +# Contributing + +Can I contribute patches to DNA project? + +Yes! Please open a pull request with signed-off commits. We appreciate your help! + +You can also send your patches as emails to the developer mailing list. +Please join the DNA mailing list or forum and talk to us about it. + +Either way, if you don't sign off your patches, we will not accept them. +This means adding a line that says "Signed-off-by: Name " at the +end of each commit, indicating that you wrote the code and have the right +to pass it on as an open source patch. + +Also, please write good git commit messages. A good commit message +looks like this: + + Header line: explain the commit in one line (use the imperative) + + Body of commit message is a few lines of text, explaining things + in more detail, possibly giving some background about the issue + being fixed, etc etc. + + The body of the commit message can be several paragraphs, and + please do proper word-wrap and keep columns shorter than about + 74 characters or so. That way "git log" will show things + nicely even when it's indented. + + Make sure you explain your solution and why you're doing what you're + doing, as opposed to describing what you're doing. Reviewers and your + future self can read the patch, but might not understand why a + particular solution was implemented. + + Reported-by: whoever-reported-it + Signed-off-by: Your Name + + +## License + +The DNA library (i.e. all code outside of the cmd directory) is licensed under the GNU Lesser General Public License v3.0, also included in our repository in the License file. diff --git a/README_CN.md b/README_CN.md deleted file mode 100644 index fb9292c..0000000 --- a/README_CN.md +++ /dev/null @@ -1,498 +0,0 @@ -# DNA SDK 手册 - - - -## 1 准备工作 - -*** 下载DNA SKD(java版本), 配置JAVA8运行环境 - -> > 注意: 配置java运行环境后运行程序时如出现如下错误: -> > -> > java.security.InvalidKeyException: Illegal key size -> > -> > 则这是秘钥长度大于128,安全策略文件受限的原因。可以去官网下载local_policy.jar和US_export_policy.jar,替换jre目录中${java_home}/jre/lib/security原有的与安全策略这两个jar即可。下载地址: -> > -> > [http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html](http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html) - - - - - -## 2 接入步骤 - -### 2.1 OAuth认证 - -DNA默认关闭认证选项,使用SDK可以直接访问DNA。在联盟链或私有链有认证要求的场景下,您需要首先完成用户注册,并获取授权accessToken才能访问应用。用户注册和获取Token请参考: [https://forum.dnaproject.org/t/dna/112](https://forum.dnaproject.org/t/dna/112)。 - - - -### 2.2 SDK调用 - -调用sdk时,将该访问令牌(非联盟链可任意)作为其中一个初始化参数传递进来,实现数字资产的注册、分发、转移、存证、取证等操作。 - - - - - -## 3 接口说明## - -调用每一个接口方法之前必须实例化账户管理器,后续的接口都是基于账户管理来调用的。实例化账户管理器所需参数包括:连接地址url,账户存储位置路径path,访问令牌accessToken。 - -``` -String dnaUrl = "http://127.0.0.1:20334"; -String dnaToken = ""; -String path = "./dat/3.db3"; -AccountManager wm = AccountManager.getWallet(path, dnaUrl, dnaToken); -``` - - - - - -### 3.1 创建账户 - -通过传递一个int类型的数值,可以创建多个账户合约,以合约地址列表形式返回。 - -| 参数 | 字段 | 类型 | 描述 | 说明 | -| ---- | -------- | ------------ | -------- | ---------------- | -| 输入参数 | numCount | int | 单次创建账户个数 | int类型占4字节 | -| 输出参数 | list | List | 账户合约地址列表 | 合约地址是以A开头的34位字符串 | - -eg: - -List list = wm.createAccount(numCount); - - - -### 3.2 导入私钥 - -根据导入可视化私钥(字节数组转换成十六进制的字符串)方式来创建账户 - -| 参数 | 字段 | 类型 | 描述 | 说明 | -| ---- | ---------- | ------ | ---- | ------------------------ | -| 输入参数 | privateKey | String | 私钥信息 | 32位字节数组转成十六进制的64位字符串类型数据 | -| 输出参数 | address | String | 账户地址 | 合约地址是以A开头的34位字符串 | - -eg: - -String address = wm.createAccountsFromPrivateKey(String privateKey); - - - -### 3.3 注册资产 - -通过传递资产的基本信息来产生一笔区块链上合法的资产,返回资产编号。后续的资产类操作就可以使用该资产编号。 - -| 参数 | 字段 | 类型 | 描述 | 说明 | -| ---- | ---------- | ------ | ------------- | -------------- | -| 输入参数 | issuer | String | 发行者地址 | 地址是以A开头的34位字符串 | -| | name | String | 资产名称 | 长度可任意 | -| | amount | long | 资产数量 | long类型占8字节 | -| | desc | String | 描述 | 长度可任意 | -| | controller | String | 控制者地址 | 地址是以A开头的34位字符串 | -| 输出参数 | txid | String | 交易编号,这里代表资产编号 | 交易编号是64位字符串 | - -eg: - -String assetid = wm.reg(issuer, name, amount , desc, controller); - - - -### 3.4 分发资产 - -通过传递分发资产的基本信息来完成一笔资产的分发操作,返回交易编号。 - -| 参数 | 字段 | 类型 | 描述 | 说明 | -| ---- | ---------- | ------ | ------- | ------------------------- | -| 输入参数 | controller | String | 资产控制者地址 | 地址是以A开头的34位字符串 | -| | assetid | String | 资产编号 | 资产编号对应注册资产的交易编号,长度为64位字符串 | -| | amount | long | 分发数量 | long类型占8字节 | -| | recver | String | 接收者地址 | 地址是以A开头的34位字符串 | -| | desc | String | 描述 | 长度可任意 | -| 输出参数 | txid | String | 交易编号 | 交易编号是64位字符串 | - -eg: - -String txid = wm.iss(controller, assetid, amount , recver , desc ); - - - -### 3.5 转移资产 - -通过传递分发资产的基本信息来完成一笔资产的分发操作,返回交易编号。 - -| 参数 | 字段 | 类型 | 描述 | 说明 | -| ---- | ---------- | ------ | ------- | ------------------------- | -| 输入参数 | controller | String | 资产控制者地址 | 地址是以A开头的34位字符串 | -| | assetid | String | 资产编号 | 资产编号对应注册资产的交易编号,长度为64位字符串 | -| | amount | long | 转移数量 | long类型占8字节 | -| | recver | String | 接收者地址 | 地址是以A开头的34位字符串 | -| | desc | String | 描述 | 长度可任意 | -| 输出参数 | txid | String | 交易编号 | 交易编号是64位字符串 | - -eg: - -String txid = wm.trf(controller, assetid, amount , recver , desc ); - - - -### 3.6 存证 - -通过传递存证交易的基本信息来完成一笔资产的分发操作,返回交易编号。 - -| 参数 | 字段 | 类型 | 描述 | 说明 | -| ---- | ------- | ------ | ---- | ----------- | -| 输入参数 | content | String | 存证信息 | 长度任意的字符串 | -| | desc | String | 描述 | 长度任意的字符串 | -| 输出参数 | txid | String | 交易编号 | 交易编号是64位字符串 | - -eg: - -String txid = wm.storeCert(content, desc); - - - -### 3.7 取证 - -查询类操作,传递存证时的交易编号,输出具体存证内容 - -| 参数 | 字段 | 类型 | 描述 | 说明 | -| ---- | ------ | ------ | ---- | ----------- | -| 输入参数 | txid | String | 交易编号 | 交易编号是64位字符串 | -| 输出参数 | cotent | String | 存证内容 | 长度任意的字符串 | - -eg: - -String content= wm.queryCert(txid); - - - -### 3.8 账户信息 - -查询类操作,传递账户地址,输出账户具体信息 - -| 参数 | 字段 | 类型 | 描述 | 说明 | -| ---- | ------- | ----------- | ---- | ------------------------------- | -| 输入参数 | address | String | 合约地址 | 地址是以A开头的34位字符串 | -| 输出参数 | info | AccountInfo | 账户信息 | 自定义类型,包括合约地址/公钥/私钥/公钥hash/私钥wif | - -| 自定义类型 | 子字段 | 子类型 | 描述 | 说明 | -| ----------- | ------- | ------ | ----- | --------------------- | -| AccountInfo | address | String | 合约地址 | 地址是以A开头的34位字符串 | -| | pubkey | String | 公钥 | 压缩模式下公钥的十六进制字符串表示 | -| | prikey | String | 私钥 | 私钥的十六进制字符串表示 | -| | priwif | String | 私钥WIF | 私钥Base58算法之后的字符串表示 | -| | pkhash | String | 公钥哈希 | 压缩模式下公钥哈希之后的十六进制字符串表示 | - -eg: - -AccountInfo info = wm.getAccountInfo(address); - - - -### 3.9 账户资产 - -查询类操作。传递账户地址,输出账户资产详情 - -| 参数 | 字段 | 类型 | 描述 | 说明 | -| ---- | ------- | ------------ | ------ | ---------------------- | -| 输入参数 | address | String | 合约地址 | 合约地址是以A开头的34位字符串 | -| 输出参数 | info | AccountAsset | 账户资产信息 | 账户资产信息包括合约地址、可用资产/冻结资产 | - -| 自定义类型 | 子字段 | 子类型 | 描述 | 说明 | -| ------------ | ------------ | ----------- | ------ | ---------------------- | -| AccountAsset | address | String | 合约地址 | 合约地址是以A开头的34位字符串 | -| | canUseAssets | List | 可用资产列表 | 可用资产列表,资产类型包括资产编号和资产数量 | -| | freezeAssets | List | 冻结资产列表 | 不可用资产列表,资产包括资产编号和资产数量 | -| Asset | assetid | String | 资产编号 | 64位字符串 | -| | amount | long | 资产数量 | 8字节的long类型 | - -eg: - -AccountAsset info = wm.getAccountAsset(userAddr); - - - -### 3.10 资产信息 - -查询类操作。传递资产编号,输出资产详情。 - -| 参数 | 字段 | 类型 | 描述 | 说明 | -| ---- | ------- | --------- | ---- | -------------------------- | -| 输入参数 | assetid | String | 资产编号 | 64位字符串 | -| 输出参数 | info | AssetInfo | 资产信息 | 资产信息包括资产编号、名称、注册数量、注册者、控制者 | - -| 自定义类型 | 子字段 | 子类型 | 描述 | 说明 | -| --------- | ---------- | ------ | ---- | ------------------------------- | -| AssetInfo | name | String | 资产名称 | 长度任意的字符串 | -| | precision | int | 精度 | 4字节的int类型 | -| | assetType | int | 资产类型 | 4字节的int类型,取值:17代表代币,1代表股权,0代表法币 | -| | recordType | int | 记账模式 | 4字节的int类型,取值:0代表utxo模式,1代表余额模式 | - -eg: - -AssetInfo info = wm.getAssetInfo(assetid); - - - -### 3.11 交易信息 - -查询类操作。传递交易编号,返回交易具体信息。 - -| 参数 | 字段 | 类型 | 描述 | 说明 | -| ---- | ---- | --------------- | ---- | -------------------- | -| 输入参数 | txid | String | 交易编号 | 64位字符串 | -| 输出参数 | info | TransactionInfo | 交易信息 | 交易信息包括交易编号、交易输入、交易输出 | - -| 自定义类型 | 子字段 | 子类型 | 描述 | 说明 | -| --------------- | ------- | ------------------ | ---- | ---------------------- | -| TransactionInfo | txid | String | 交易编号 | 64位字符串 | -| | type | String | 交易类型 | 取值:注册交易/分发交易/转账交易/存证交易 | -| | inputs | List | 交易输入 | 交易资产的来源 | -| | outputs | List | 交易输出 | 交易资产的去向 | -| | attrs | String | 描述 | 任意长度的字符串 | -| TxInputInfo | address | String | 合约地址 | 合约地址是以A开头的34位字符串 | -| | assetid | String | 资产编号 | 64位字符串 | -| | amount | long | 资产数量 | 8字节的long类型 | -| TxOutputInfo | address | String | 合约地址 | 合约地址是以A开头的34位字符串 | -| | assetid | String | 资产编号 | 64位字符串 | -| | amount | long | 资产数量 | 8字节的long类型 | - -eg: - -TransactionInfo info = wm.getTransactionInfo(txid); - - - -### 3.12 所有账户 - -通过账户管理器实例可以查询当前管理器中所有账户地址。 - -| 参数 | 字段 | 类型 | 描述 | 说明 | -| ---- | ---- | ------------ | ------ | ------ | -| 输入参数 | 空 | 空 | 参数为空 | 参数为空 | -| 输出参数 | list | List | 账户地址列表 | 账户地址列表 | - -eg: - -List list = wm.listAccount(); - - - -## 4 调用示例 - -``` -//实例化账户管理器 -String dnaUrl = "http://127.0.0.1:20334"; // DNA节点地址 -String dnaToken = ""; // 访问令牌,非必需项,如开启OAuth认证,则需要填写 -String path = "./dat/3.db3"; // 钱包路径 -AccountManager wm = AccountManager.getWallet(path, dnaUrl, dnaToken); -``` - - - - - -### 4.1 创建账户 - -``` -// 打开账户管理器(参考实例化账户管理器) -AccountManager wm = getAccountManager(); - -// 创建账户 -String user01 = wm.createAccount(); // 创建单个账户 -List list = wm.createAccount(10); // 批量创建10个账户 -``` - - - -### 4.2 导入私钥 - -``` -// 打开账户管理器(参考实例化账户管理器) -AccountManager wm = getAccountManager(); - -// 创建账户 -String privatekey = ""; -String address = wm.loadPrivateKey(privatekey); -``` - - - -### 4.3 注册资产 - -``` -// 打开账户管理器(参考实例化账户管理器) -AccountManager wm = getAccountManager(); - -// 注册资产 -String issuer= ""; // 资产发行者地址 -String name = ""; // 资产名称 -long amount = 10000; // 资产数量 -String desc = ""; // 描述 -String controller = ""; // 资产控制者地址 -String assetid = wm.reg(issuer, name, amount , desc, controller); -System.out.println("rs:"+assetid); -``` - - - -### 4.4 发行资产 - -``` -// 打开账户管理器(参考实例化账户管理器) -AccountManager wm = getAccountManager(); - -// 分发资产 -String controller= ""; // 资产控制者地址 -String assetid = ""; // 资产编号(由注册资产产生) -long amount = 100; // 分发数量 -String recver = ""; // 分发资产接收者地址 -String desc = ""; // 描述 -String txid = wm.iss(controller, assetid, amount , recver , desc ); -System.out.println("rs:"+txid); -``` - - - -### 4.5 转移资产 - -``` -// 打开账户管理器(参考实例化账户管理器) -AccountManager wm = getAccountManager(); - -// 转移资产 -String controller= ""; // 资产控制者地址 -String assetid = ""; // 资产编号(由注册资产产生) -long amount = 100; // 转移数量 -String recver = ""; // 转移资产接收者地址 -String desc = ""; // 描述 -String txid = wm.trf(controller, assetid, amount , recver , desc ); -System.out.println("rs:"+txid); -``` - - - -### 4.6 存证 - -``` -// 打开账户管理器(参考实例化账户管理器) -AccountManager wm = getAccountManager(); - -// 方式1:存证 -String content = ""; // 待存储的信息 -String desc = ""; // 描述 -String txid = wm.storeCert(content, desc); -System.out.println("rs:"+txid); -``` - - - -### 4.7 取证 - -``` -// 打开账户管理器(参考实例化账户管理器) -AccountManager wm = getAccountManager(); - -// 取证 -String txid = ""; // 存证编号 -String content= wm.queryCert(txid); -System.out.println("rs:"+content); -``` - - - -### 4.8 账户信息 - -``` -// 打开账户管理器(参考实例化账户管理器) -AccountManager wm = getAccountManager(); - -// 查询账户信息 -String userAddr = ""; // 账户地址 -AccountInfo info = wm.getAccountInfo(userAddr); -``` - - - -### 4.9 账户资产 - -``` -// 打开账户管理器(参考实例化账户管理器) -AccountManager wm = getAccountManager(); - -// 查询账户资产 -String userAddr = ""; // 账户地址 -AccountAsset info = wm.getAccountAsset(userAddr); -``` - - - -### 4.10 资产信息 - -``` -// 打开账户管理器(参考实例化账户管理器) -AccountManager wm = getAccountManager(); - -// 查询账户资产 -String assetid = ""; -AssetInfo info = wm.getAssetInfo(assetid); -``` - - - -### 4.11 交易信息 - -``` -// 打开账户管理器(参考实例化账户管理器) -AccountManager wm = getAccountManager(); - -// 查询账户资产 -String txid = ""; -TransactionInfo info = wm.getTransactionInfo(txid); -``` - - - -### 4.12 所有账户 - -``` -// 打开账户管理器(参考实例化账户管理器) -AccountManager wm = getAccountManager(); - -// 查询管理器中所有账户 -List list = wm.listAccount(); -``` - - - - - -## 5 开发说明 - -​ 该SDK供客户端使用,其中含有账户信息的管理,比如合约地址、公钥、私钥,这些信息保存至客户端数据库中。具体的数据库可根据需求自由选择,目前实现的数据库有sqlite、mysql,sqlite是一个文件数据库,初始化时需要传递路径,上面的示例是根据该sqlite保存账户信息的数据库实现给出的,mysql使用时还需要创建对应的表,以及实现具体的数据库连接。通过SDK接入DNA区块链时,可以直接使用当前Sqlite数据库保存账户的公私钥信息的UserWalletManager,也可自定义一个账户管理器来管理账户私密信息。自己实现账户管理器可参考DNA.Implementations.Wallets.SQLite.UserWallet 类。 - - - - - -## 6 错误代码 - -| 返回代码 | 描述信息 | 说明 | -| :---- | ------------------- | ----------------- | -| 0 | SUCCESS | 成功 | -| 41001 | SESSION_EXPIRED | 会话无效或已过期( 需要重新登录) | -| 41002 | SERVICE_CEILING | 达到服务上限 | -| 41003 | ILLEGAL_DATAFORMAT | 不合法数据格式 | -| 42001 | INVALID_METHOD | 无效的方法 | -| 42002 | INVALID_PARAMS | 无效的参数 | -| 42003 | INVALID_TOKEN | 无效的令牌 | -| 43001 | INVALID_TRANSACTION | 无效的交易 | -| 43002 | INVALID_ASSET | 无效的资产 | -| 43003 | INVALID_BLOCK | 无效的块 | -| 44001 | UNKNOWN_TRANSACTION | 找不到交易 | -| 44002 | UNKNOWN_ASSET | 找不到资产 | -| 44003 | UNKNOWN_BLOCK | 找不到块 | -| 45001 | INVALID_VERSION | 协议版本错误 | -| 45002 | INTERNAL_ERROR | 内部错误 | - diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..5248aed --- /dev/null +++ b/docs/README.md @@ -0,0 +1,68 @@ +

DNA Java SDK 介绍

+ +

Version 1.0.0

+ + +# 总体介绍 + +该项目是本体官方Java SDK,它是一个综合性SDK,目前支持:本地钱包管理、数字身份管理、数字资产管理、智能合约部署和调用、与节点通信等。未来还将支持更丰富的功能和应用。 + +## 主要功能 + +- [介绍](sdk_get_start.md) +- [接口基本信息](interface.md) +- [区块链节点基本操作](basic.md) +- [钱包文件及规范](Wallet_File_Specification_cn.md) +- [数字身份及可信声明管理](identity_claim.md) +- [数字资产](asset.md) +- [数字存证](attest.md) +- [权限管理](auth.md) +- [智能合约部署和调用](smartcontract.md) +- [错误码](errorcode.md) +- [API 文档](https://apidoc.ont.io/javasdk/) + +## 代码结构说明: + +* acount:账号相关操作,如生成公私钥 +* common:通用基础接口 +* core:核心层,包括合约、交易、签名等 +* crypto:加密相关,如ECC/SM +* io:io操作 +* network:restful\rpc\websocket与链通信接口 +* sdk:对SDK底层做封装、Info信息、通信管理、Claim管理、钱包管理、异常类。 +* dnaSdk类:提供管理器和交易实例,管理器包括:walletMgr、connManager。 + * walletMgr钱包管理器主要管理数字身份及数字资产账户,用户向链上发送交易需要私钥做签名。 + * connManager与链上通信管理。任何发送交易和查询都需要通过连接管理器。 + +## 安装说明 + +### 请配置JDK 8的开发环境 + +> **注意:** SDK用的key的长度超过128位,由于java的安全策略文件对key的长度的限制,需要下载local_policy.jar和US_export_policy.jar这两个jar包,替换JRE库${java_home}/jre/lib/security目录下对应的jar包。 + +jar包下载地址: + +>http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html + + +### Build + +``` +$ mvn clean install +``` + +### 引入依赖 + + +``` + + + com.github.DNAProject + DNASDKJava/artifactId> + 2.0.0 + +``` + +### 预准备 + +* 启动[DNA节点](https://github.com/DNAProject/DNA),无论是主网、测试网、私网都可以。确保rpc端口可以访问,并且确保SDK可以连接RPC服务器。 diff --git a/docs/Wallet_File_Specification_cn.md b/docs/Wallet_File_Specification_cn.md new file mode 100644 index 0000000..c782ecc --- /dev/null +++ b/docs/Wallet_File_Specification_cn.md @@ -0,0 +1,274 @@ + +

钱包规范

+ +

Version 1.0.0

+ + + +钱包规范描述了钱包数据结构及导出数字身份或资产账号二维码的数据结构。 + +## 1. 钱包文件结构 + +钱包文件数据以json格式存储,文件名后缀并无要求,钱包文件数据结构如下: + +``` +{ + "name": "MyWallet", + "version": "1.0", + "scrypt": {}, + "defaultDnaid": "did:ont:TJNxJe2Ty8eSCjCDxDPwiS78NRAn8XPTFL", + "defaultAccountAddress": "TJNxJe2Ty8eSCjCDxDPwiS78NRAn8XPTFL", + "createTime": "2018-03-14T03:12:30.862Z", + "identities": [], + "accounts": [], + "extra": null +} +``` +参数描述: + +```name``` 钱包名. + +```version``` 钱包版本号. + +```scrypt``` SCrypt算法参数. + +```defaultDnaid``` 钱包中的默认Dnaid. + +```defaultAccountAddress``` 钱包中默认账户地址. + +```createTime``` 钱包创建时间. + +```identities``` 身份列表. + +```accounts``` 账户列表. + +```extra``` 备用参数. + +一个真实的钱包数据如下: + +```json +{ + "name": "mickey", + "defaultDnaid": "", + "defaultAccountAddress": "", + "createTime": "2018-06-30T08:52:01.519Z", + "version": "1.0", + "scrypt": { + "n": 4096, + "r": 8, + "p": 8, + "dkLen": 64 + }, + "identities": [{ + "dnaid": "did:ont:ATcHA9eYKyve8M74CB4p6Ssx7kwXjmREUa", + "label": "mickey", + "lock": false, + "controls": [{ + "id": "1", + "algorithm": "ECDSA", + "parameters": { + "curve": "P-256" + }, + "key": "M+PnrYLVDrU0gkSzj0FAsvqCYv+HWEEUMDSyKSJACzJhZVglFU9tkfQKlLby5UCY", + "address": "ATcHA9eYKyve8M74CB4p6Ssx7kwXjmREUa", + "salt": "wwa12j4K0SyDP23+UDJNtA==", + "enc-alg": "aes-256-gcm" + }] + }], + "accounts": [{ + "address": "AJQLNWy9X6qdeEFrSH6UzgEjadSsRiYDCS", + "label": "mickey", + "lock": false, + "algorithm": "ECDSA", + "parameters": { + "curve": "P-256" + }, + "key": "qFbemAbu7fEjOJzAZZhGkmzp2YNxdSCuK7xyvhBAnUBX/FmAj2Ns84Y7frh6hfQv", + "enc-alg": "aes-256-gcm", + "salt": "u+SiqpRk17b0vIPesh4xXA==", + "isDefault": false, + "publicKey": "037fb6dfc9420e1d8275d9133d6d69fe64e8e3567241e7583234b9efa8b2ce7ae1", + "signatureScheme": "SHA256withECDSA" + }], + "extra": null +} +``` + +### 1.1 Scrypt参数 + +SCrypt算法参数,Scrypt数据结构: + +```json +{ + "n": 16384, + "r": 8, + "p": 8, + "dkLen" : 64 +} +``` + +参数描述: + +```n``` 内存消耗,必须是 2^N. + +```r``` 参数. + +```p``` SCrypt算法的并行参数. + +```dkLen``` 派生key的长度. + +### 1.2 数字身份 + +数字身份数据结构: +```json +{ + "dnaid": "did:ont:TQLASLtT6pWbThcSCYU1biVqhMnzhTgLFq", + "label": "MyIdentity", + "lock": false, + "isDefault" : false, + "controls": [] +} +``` +参数描述: + +```dnaid``` 身份id. + +```label``` 昵称. + +```lock``` 是否锁住该身份. + +```isDefault``` 是否是默认使用的身份. + +```controls``` 控制人. + +#### Control数据结构 + +Control是数字身份的控制人,里面包含控制人的加密后算法名,私钥,公钥,地址,salt等。 + +```json +{ + "algorithm": "ECDSA", + "parameters": {}, + "id": "1", + "key": "6PYWB8m1bCnu5bQkRUKAwbZp2BHNvQ3BQRLbpLdTuizpyLkQPSZbtZfoxx", + "address": "AQkGLumU1tnyJBGV1ZUmD229iQf9KRTTDL", + "salt": "Rv4v3a4U1zFEq28/" +} +``` +参数描述: + +```algorithm``` 签名算法名称. + +```parameters``` 曲线参数. + +```id``` 控制人id. + +```key``` 加密后私钥. + +```address``` base58地址. + +```salt``` 16字节的盐,以base64格式存储. + + +#### Parameter数据结构 + +签名算法参数数据结构 +```json +{ + "curve":"P-256" +} +``` +参数描述: + +```curve``` is the name of the elliptic curve. + +### 1.3 Account + + +资产账户信息```Account``` 数据结构: + + +```json +{ + "address": "AadQ5xRwrSsFTGzKfLHc1brzykdnf7phhD", + "label": "a6575fd9", + "lock": false, + "algorithm": "ECDSA", + "parameters": { + "curve": "P-256" + }, + "key": "NyfxXX+xKDG2agrDy3espqX7N0k3MysTgqx5FxJGI8bkklZQO6+6BSluyBRvEsOx", + "enc-alg": "aes-256-gcm", + "salt": "MHct5XIedi86rQILJFi9lA==", + "isDefault": false, + "publicKey": "03e897f5a1ea306270e3e1e539c9065b6905e2430aae7f4802e1114f01634d7235", + "signatureScheme": "SHA256withECDSA" +} +``` +参数描述: + +```address``` base58 地址. + +```enc-alg``` 私钥加密算法名称. + +```salt``` 16字节的盐,以base64格式存储. + +```publicKey``` 公钥 + +```signatureScheme``` 签名算法体系. + +```isDefault``` 是否是默认账户. + +```label``` 昵称. + +```lock``` 是否加锁. + +```algorithm``` 签名算法名称. + +```parameters``` 签名算法参数. + +```key``` 加密后私钥. + + + +## 2. 二维码规范 + +身份和账号二维码的作用是方便通过扫描导入身份或账号,二维码同时支持数字身份和资产账号规范. + +```json +{ + "type":"I", + "label": "MyIdentity", + "algorithm": "ECDSA", + "scrypt": { + "n": 4096, + "p": 8, + "r": 8, + "dkLen": 64 + }, + "key":"x0U3gy7mQMpzCYXwlt/oWZerSGaCUimSMN2UiSd2aKs=", + "address" : "AQkGLumU1tnyJBGV1ZUmD229iQf9KRTTDL", + "salt" : "Rv4v3a4U1zFEq28/", + "parameters": { + "curve": "P-256" + } +} +``` +参数描述: + +```type``` 类型, **I** 代表身份 , **A** 代表账号. + +```label``` 昵称. + +```algorithm``` 签名算法名. + +```parameters``` 签名算法参数. + +```scrypt``` scrypt参数. + +```key``` 加密后私钥. + +```address``` 地址. + +```salt``` 16字节的盐,以base64格式存储. + diff --git a/docs/asset.md b/docs/asset.md new file mode 100644 index 0000000..db330f5 --- /dev/null +++ b/docs/asset.md @@ -0,0 +1,232 @@ +

数字资产

+ +

Version 1.0.0

+ + +## 钱包文件及规范 + +钱包文件是一个Json格式的数据存储文件,可同时存储多个数字身份和多个数字资产账户。具体参考[钱包文件规范](../en/Wallet_File_Specification.md)。 + +为了管理数字资产,您首先需要创建/打开一个钱包文件。 + +```java +//如果不存在钱包文件,会自动创建钱包文件。 +DnaSdk dnaSdk = DnaSdk.getInstance(); +dnaSdk.openWalletFile("Demo.json"); +``` +> 注:目前仅支持文件形式钱包文件,也可以扩展支持数据库或其他存储方式。 + +## 资产账户数据结构说明 +`address` 是base58编码的账户地址。 +`label` 是账户的名称。 +`isDefault`表明账户是否是默认的账户。默认值为false。 +`lock` 表明账户是否是被用户锁住的。客户端不能消费掉被锁的账户中的资金。 +`algorithm` 是秘钥算法名称。 +`parameters` 是加密算法所需参数。 +`curve` 是椭圆曲线的名称。 +`key` 是NEP-2格式的私钥。该字段可以为null(对于只读地址或非标准地址)。 +`encAlg` 私钥加密的算法名称,固定为aes-256-ctr。 +`salt` 私钥解密参数。 +`extra` 是客户端存储额外信息的字段。该字段可以为null。 +`signatureScheme` 是签名方案,用于交易签名。 +`hash` hash算法,用于派生秘钥。 + + +```java +public class Account { + public String label = ""; + public String address = ""; + public boolean isDefault = false; + public boolean lock = false; + public String algorithm = ""; + public Map parameters = new HashMap() ; + public String key = ""; + @JSONField(name = "enc-alg") + public String encAlg = "aes-256-gcm"; + public String salt = ""; + public String hash = "sha256"; + public String signatureScheme = "SHA256withECDSA"; + public Object extra = null; +} +``` + +## 数字资产账户管理 + +以下举例说明如何管理钱包中的资产账户。 + +* 创建数字资产账号 + +```java +DnaSdk dnaSdk = DnaSdk.getInstance(); +Account acct = dnaSdk.getWalletMgr().createAccount("password"); +//创建的账号或身份只在内存中,如果要写入钱包文件,需调用写入接口 +dnaSdk.getWalletMgr().writeWallet(); +``` + + +* 移除数字资产账号 + +```java +dnaSdk.getWalletMgr().getWallet().removeAccount(address); +//写入钱包 +dnaSdk.getWalletMgr().writeWallet(); +``` + +* 设置默认数字资产账号 + +```java +dnaSdk.getWalletMgr().getWallet().setDefaultAccount(index); +dnaSdk.getWalletMgr().getWallet().setDefaultAccount("address"); +``` +> Note: index表示设置第index个account为默认账户,address表示设置该address对应的account为默认账户 + +## 原生数字资产接口 + + +原生数字资产是Gas。封装了构造交易、交易签名、发送交易。 + +#### 1. 转账 +```java +String sendTransfer(Account sendAcct, String recvAddr, long amount, Account payerAcct, long gaslimit, long gasprice) +``` +功能说明: 从发送方转移一定数量的资产到接收方账户 + +参数说明: + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | sendAcct| Account | 发送方账户 | 必选 | +| | recvAddr | Account | 接收方地址 | 必选 | +| | amount | long | 转移的资产数量|必选| +| | payerAcct| Account |支付交易费用的账户 | 必选| +| | gaslimit | long | 声明发行者和申请者dnaid | 必选 | +| | gasprice | long | gas价格 | 必选 | +| 输出参数 | 交易hash | String | 交易hash | | + +#### 2. 授权转移资产 +```java +String sendApprove(Account sendAcct, String recvAddr, long amount, Account payerAcct, long gaslimit, long gasprice) +``` +功能说明: sendAddr账户允许recvAddr转移amount数量的资产 + +参数说明: + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | sendAcct| Account | 发送方账户 | 必选 | +| | recvAddr | Account | 接收方地址 | 必选 | +| | amount | long | 授权的资产数量|必选| +| | payerAcct| Account |支付交易费用的账户 | 必选| +| | gaslimit | long | 声明发行者和申请者dnaid | 必选 | +| | gasprice | long | gas价格 | 必选 | +| 输出参数 | 交易hash | String | 交易hash | | + +#### 3. TransferFrom + +```java +String sendTransferFrom(Account sendAcct, String fromAddr, String toAddr, long amount, Account payerAcct, long gaslimit, long gasprice) +``` +功能说明: sendAcct账户从fromAddr账户转移amount数量的资产到toAddr账户 + +参数说明: + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | sendAcct| Account | 发送方账户 | 必选 | +| | fromAddr | Account | 资产转出方地址 | 必选 | +| | toAddr | Account | 资产转入方地址 | 必选 | +| | amount | long | 转移的资产数量|必选| +| | payerAcct| Account |支付交易费用的账户 | 必选| +| | gaslimit | long | 声明发行者和申请者dnaid | 必选 | +| | gasprice | long | gas价格 | 必选 | +| 输出参数 | 交易hash | String | 交易hash | | + +#### 4. 查询余额 + +```java +long queryBalanceOf(String address) +``` +功能说明: 查询账户address资产余额 + +参数说明: + +```address```: 账户地址 + +返回值:账户余额 + +5. 查询Allowance +```java +long queryAllowance(String fromAddr,String toAddr) +``` +功能说明: 查询fromAddr授权toAddr转移的数量 + +参数说明: + +```fromAddr```: 授权转出方的账户地址 + +```toAddr```: 允许转入方的账户地址 + +返回值:授权转移的数量 + +#### 6. 查询资产名 + +```java +String queryName() +``` +功能说明: 查询资产名信息 + +参数说明: + +返回值:资产名称 + +#### 7. 查询资产Symbol + +```java +String querySymbol() +``` +功能说明: 查询资产Symbol信息 + +参数说明: + +返回值:Symbol信息 + +#### 8. 查询资产的精确度 + +```java +long queryDecimals() +``` +功能说明: 查询资产的精确度 + +参数说明: + +返回值:精确度 + +#### 9. 查询资产的总供应量 +```java +long queryTotalSupply() +``` +功能说明: 查询资产的总供应量 + +参数说明: + +返回值:总供应量 + + +资产转移示例代码: + +```java +//step1:获得dnaSdk实例 +DnaSdk sdk = DnaSdk.getInstance(); +sdk.setRpc(url); +sdk.openWalletFile("OntAssetDemo.json"); +//step2:获得gas实例 +gas = sdk.nativevm().gas() +//step3:调用转账方法 +com.github.DNAProject.account.Account account1 = new com.github.DNAProject.account.Account(privateKey,SignatureScheme.SHA256WITHECDSA); +dnaSdk.nativevm().gas().sendTransfer(account1,"TA4pCAb4zUifHyxSx32dZRjTrnXtxEWKZr",10000,account1,dnaSdk.DEFAULT_GAS_LIMIT,0); +``` + + + + +查看如何部署和调用智能合约,详见[smartcontract](smartcontract.md)。 diff --git a/docs/attest.md b/docs/attest.md new file mode 100644 index 0000000..90ae86e --- /dev/null +++ b/docs/attest.md @@ -0,0 +1,254 @@ +

可信声明及存证

+ +

Version 1.0.0

+ + + +## 1. 可信声明 + +可验证声明用来证明实体的某些属性。 + +可信声明存证合约提供了可信声明的存证服务。即存证可信声明Id,签发者ONT身份,属主ONT身份等信息,以及记录可用性信息即是否被吊销等信息。 + +可信声明规范说明文档请参考:[可信声明规范](https://github.com/ontio/ontology-DID/blob/master/docs/cn/claim_spec_cn.md) + + +### 1.1 数据结构和规范 + + + +java-sdk采用JSON Web Token的格式表示claim以便于在声明发行者和申请者之间进行传递,jwt格式包含三部分header,payload,signature. + +* Claim 具有以下数据结构 + +```java +class Claim{ + header : Header + payload : Payload + signature : byte[] +} +``` + + +```java +class Header { + public String Alg = "ONT-ES256"; + public String Typ = "JWT-X"; + public String Kid; + } +``` + +字段说明 +`alg` 使用的签名框架 +`typ` 可以是下面两个值中的一个 + JWT: 表示区块链证明不包含在claim中 + JWT-X: 表示区块链证明是claim中的一部分 +`kid` 用于签名的公钥 + +```java +class Payload { + public String Ver; + public String Iss; + public String Sub; + public long Iat; + public long Exp; + public String Jti; + @JSONField(name = "@context") + public String Context; + public Map ClmMap = new HashMap(); + public Map ClmRevMap = new HashMap(); + } +``` + +`ver` Claim版本号 +`iss` 发行方的dnaid +`sub` 申请方的dnaid +`iat` 创建时间 +`exp` 超期时间 +`jti` claim的唯一标志 +`@context` 指定声明内容定义文档URI,其定义了每个字段的含义和值得类型 +`clm` 包含claim内容的对象 +`clm-rev` 定义个claim 的撤销机制, + +### 1.2 创建可信声明 + +根据用户输入内容构造声明对象,该声明对象里包含了签名后的数据。 +创建claim: +* 1.查询链上是否存在Issuer的DDO +* 2.签名者的公钥必须在DDO的Owners中存在 +* 3.claimId 是对claim中删除Signature、Id、Proof的数据转byte数组,做一次sha256,再转hexstring +* 4.对要签名的json数据转成Map对key做排序。 +* 5.Signature中Value值:claim 删除Signature、Proof后转byte数组, 做两次sha256得到的byte数组。 + +```java +Map map = new HashMap(); +map.put("Issuer", dids.get(0).dnaid); +map.put("Subject", dids.get(1).dnaid); +Map clmRevMap = new HashMap(); +clmRevMap.put("typ","AttestContract"); +clmRevMap.put("addr",dids.get(1).dnaid.replace(Common.diddna,"")); +String claim = dnaSdk.nativevm().dnaId().createDnaIdClaim(dids.get(0).dnaid,password,salt, "claim:context", map, map,clmRevMap,System.currentTimeMillis()/1000 +100000); +``` + +**createDnaIdClaim** + +```java +String createDnaIdClaim(String signerDnaid, String password,byte[] salt, String context, Map claimMap, Map metaData,Map clmRevMap,long expire) +``` + + + 功能说明: 创建可信声明 + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | signerDnaid| String | 签名者dnaid | 必选 | +| | password | String | 签名者密码 | 必选 | +| | salt | byte[] | 解密需要的参数|必选| +| | context| String |指定声明内容定义文档URI,其定义了每个字段的含义和值得类型 | 必选| +| | claimMap| Map |声明的内容 | 必选| +| | metaData | Map | 声明发行者和申请者dnaid | 必选 | +| | clmRevMap | Map | claim的撤回机制 | 必选 | +| | expire | long | 声明过期时间 | 必选 | +| 输出参数 | claim | String | 可信声明 | | + + + +### 1.3 验证可信声明 + +验证claim步骤: +* 1.查询链上是否存在Metadata中Issuer的DDO +* 2.Owner是否存在Sgnature中的PublicKeyId +* 3.对要验签的json数据转成Map对key做排序。 +* 4.删除Signature做验签(根据PublicKeyId的id值查找到公钥,签名是Signature中Value做base64解码) +```java +boolean b = dnaSdk.nativevm().dnaId().verifyDnaIdClaim(claim); +``` + +**verifyDnaIdClaim** + +```java +boolean verifyDnaIdClaim(String claim) +``` + +功能说明: 验证可信声明 + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | claim| String | 可信声明 | 必选 | +| 输出参数 | true或false | boolean | | | + + + + +## 2. 可信声明存证合约使用步骤 + +该合约提供存储、吊销、查询状态等功能。 + +### 2.1. 初始化SDK + +使用存证合约之前先初始化,并设置合约地址。 + +```java +String ip = "http://127.0.0.1"; +String restUrl = ip + ":" + "20334"; +String rpcUrl = ip + ":" + "20336"; +String wsUrl = ip + ":" + "20335"; +DnaSdk wm = DnaSdk.getInstance(); +wm.setRpc(rpcUrl); +wm.setRestful(restUrl); +wm.setDefaultConnect(wm.getRestful()); +wm.openWalletFile("RecordTxDemo.json"); +wm.setCodeAddress("803ca638069742da4b6871fe3d7f78718eeee78a"); +``` + +> Note: codeAddress是存证合约地址。 + + + +### 2.2 将可信申明保存到链上 + +**sendCommit** + +```java +String sendCommit(String issuerDnaid, String password,byte[] salt, String subjectDnaid, String claimId, Account payerAcct, long gaslimit, long gasprice) +``` + +功能说明: 将数据保存到链上,声明存证,当且仅当该声明没有被存证过,且Commit函数是由committer调用,才能存证成功;否则,存证失败。存证成功后,该声明的状态就是已存证(committed)。 + +参数说明: + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | issuerDnaid| String | 可信申明签发者数字身份dnaid | 必选 | +| 输入参数 | password| String | 数字身份密码 | 必选 | +| 输入参数 | subjectDnaid| String | 可信申明申请者dnaid | 必选 | +| 输入参数 | claimId| String | 可信申明claim唯一性标志,即Claim里面的Jti字段 | 必选 | +| 输入参数 | payerAcct| String | 交易费用支付者账号 | 必选 | +| 输入参数 | gaslimit| String | gaslimit | 必选 | +| 输入参数 | gasprice| String | gasprice | 必选 | +| 输出参数 | 交易hash | boolean | | | + + + +示例代码 + +```java +String[] claims = claim.split("\\."); +JSONObject payload = JSONObject.parseObject(new String(Base64.getDecoder().decode(claims[1].getBytes()))); +String commitHash = dnaSdk.neovm().claimRecord().sendCommit(dids.get(0).dnaid,password,dids.get(1).dnaid,payload.getString("jti"),account1,dnaSdk.DEFAULT_GAS_LIMIT,0) +``` + +### 2.3. 查询可信申明的状态 + +**sendGetStatus** + +``` +String sendGetStatus(String claimId) +``` + +功能说明:查询可信申明的状态 + + +参数说明: + +```claimId```: 可信申明claim唯一性标志,即Claim里面的Jti字段 + +返回值:有两部分: 第一部分,claim的状态:"Not attested", "Attested", "Attest has been revoked";第二部分是存证者的dnaid + + +示例代码 + +```java +String getstatusRes2 = dnaSdk.neovm().claimRecord().sendGetStatus(payload.getString("jti")); +``` + + +### 2.4. 撤销可信申明 + + +**sendRevoke** + +```java +String sendRevoke(String issuerDnaid,String password,byte[] salt,String claimId,Account payerAcct,long gaslimit,long gas) +``` + +功能说明:撤销可信申明 + + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | issuerDnaid| String | 可信申明签发者数字身份dnaid | 必选 | +| 输入参数 | password| String | 数字身份密码 | 必选 | +| 输入参数 | salt| String | issuer的salt | 必选 | +| 输入参数 | claimId| String | 可信申明claim唯一性标志,即Claim里面的Jti字段 | 必选 | +| 输入参数 | payerAcct| String | 交易费用支付者账号 | 必选 | +| 输入参数 | gaslimit| String | gaslimit | 必选 | +| 输入参数 | gasprice| String | gasprice | 必选 | +| 输出参数 | 交易hash | boolean | | | + + +示例代码 + +```java +String revokeHash = dnaSdk.neovm().claimRecord().sendRevoke(dids.get(0).dnaid,password,salt,payload.getString("jti"),account1,dnaSdk.DEFAULT_GAS_LIMIT,0); +``` diff --git a/docs/auth.md b/docs/auth.md new file mode 100644 index 0000000..82fc4d9 --- /dev/null +++ b/docs/auth.md @@ -0,0 +1,339 @@ +

权限管理

+ +

Version 1.0.0

+ +[English](../en/auth.md) / 中文 + + +当前,智能合约的函数可以被任何人调用,这显然不符合现实要求。基于角色的权限管理的基本思想是,每个角色可以调用部分函数,每个实体可以被赋予多种角色(实体是由其DNA ID来标识)。 + +如果智能合约需要增加权限管理功能,那就必须记录合约中分配的角色,以及角色可调用的函数,哪些实体具有该角色等等信息。这个工作比较繁琐,可交由一个系统合约来管理。 + +具体请参考[权限合约](https://github.com/ontio/ontology-smartcontract/blob/master/smartcontract/native/auth/auth.md) + + +* 权限合约管理 + +* 用法示例 + +* 接口列表 + + +### 权限合约管理 + +Auth合约负责管理应用合约的函数调用权限,功能有合约管理员可以转让合约管理权限,合约管理员为角色分配函数,合约管理员绑定角色到实体身份,有合约函数调用权的实体将合约调用权代理给其他人,合约管理员收回合约调用权,实体验证合约调用token的有效性。 + +Auth合约实现了一套基于角色的权限管理方案,每个角色对应一些可调用的函数,管理员通过将角色分配给DNA ID,使之可以调用该角色下的函数。与此同时,角色是可以传递的,即A可以将某个角色代理给B,并指定代理时间,这样的话B就可以一段时间内也可以调用对应的函数。 + +### 用法示例 + +DNA智能合约不支持在部署的时候执行初始化,所以合约管理员需要硬编码在合约代码中,即将合约管理员DNA ID在合约中定义成一个常量,具体请看下面的合约样例。DNA智能合约可以调用verifyToken函数进行权限验证,同时为了方便开发者验证某个DnaID是否有某个角色,Java-SDK也提供了verifyToken接口,可以实时查询角色的分配情况。 + +使用流程: + +``` +1. 将智能合约部署到链上。 +2. 调用智能合约中的init方法,在合约代码中通过调用initContractAdmin方法,将合约中预先定义的管理员DNA ID,设置为该合约的管理员(注意:需先将管理员DNA ID注册到链上)。 +3. 合约管理员设计需要用到的角色,并将角色和智能合约中的函数进行绑定,该步骤可以调用Java-SDK中的assignFuncsToRole接口进行设置。 +4. 合约管理员将角色分配给DNA ID,拥有该角色的DNA ID将有权限调用该角色对应的函数,该步骤可以调用Java-SDK中的assignDnaIDsToRole接口进行设置。 +5. 拥有某个角色的DNA ID在调用该角色对应的函数之前,可以通过Java-SDK中的verifyToken接口验证该dnaid是否有调用相应函数的权利。 +``` + +结合下面的示例讲解使用流程: + +A. 将智能合约部署到链上。 +B. 调用该合约中init方法。 + +```java +AbiInfo abiInfo = JSON.parseObject(abi,AbiInfo.class); +String name = "init"; +AbiFunction function = abiInfo.getFunction(name); +function.setParamsValue(); +String txhash = (String) sdk.neovm().sendTransaction(Helper.reverse(codeAddress),account,account,sdk.DEFAULT_GAS_LIMIT,0,function,false); +``` + +C. 合约管理员设计角色role1和role2,并将角色role1和函数foo1绑定,将角色role2和函数foo2、foo3绑定。 + +```java +String txhash = sdk.nativevm().auth().assignFuncsToRole(adminIdentity.dnaid, password, adminIdentity.controls.get(0).getSalt(), +1, Helper.reverse(codeAddress), "role1", new String[]{"foo1"}, account, sdk.DEFAULT_GAS_LIMIT, 0); + +String txhash = sdk.nativevm().auth().assignFuncsToRole(adminIdentity.dnaid, password, adminIdentity.controls.get(0).getSalt(), 1, +Helper.reverse(codeAddress), "role2", new String[]{"foo2","foo3"}, account, sdk.DEFAULT_GAS_LIMIT, 0); + +``` + +D. 合约管理员将角色"role1"分配给dnaId1,将角色"role2"分配给dnaId2,则dnaId1拥有调用函数foo1的权限,dnaId2拥有调用函数foo2和函数foo3的权限。 + +```java +String txhash = sdk.nativevm().auth().assignDnaIdsToRole(adminIdentity.dnaid, password, adminIdentity.controls.get(0).getSalt(), 1, +Helper.reverse(codeAddress), "role1", new String[]{identity1.dnaid}, account, sdk.DEFAULT_GAS_LIMIT, 0); + +String txhash = sdk.nativevm().auth().assignDnaIdsToRole(adminIdentity.dnaid, password, adminIdentity.controls.get(0).getSalt(), 1, +Helper.reverse(codeAddress), "role2", new String[]{identity2.dnaid}, account, sdk.DEFAULT_GAS_LIMIT, 0); + + +``` + +E. 由于dnaId1的角色是合约管理员分配的,其权限level默认是2,即dnaId1可以将权限代理给其他dnaidX,代理的Java-SDK接口是delegate,具体接口信息请参考下面的接口信息。 +在代理权限的时候需要指定被代理人权限的级别以及代理时间,如果代理人的level是2,则被代理人的level只能是1。 + +```java +sdk.nativevm().auth().delegate(identity1.dnaid,password,identity1.controls.get(0).getSalt(),1,Helper.reverse(codeAddress), +identityX.dnaid,"role1",60*5,1,account,sdk.DEFAULT_GAS_LIMIT,0); +``` + +F. 验证某个dnaId是否有调用某个函数的权限,可以通过verifyToken接口查询。 + +```java +String result = sdk.nativevm().auth().verifyToken(identityX.dnaid, password, identityX.controls.get(0).getSalt(), 1, Helper.reverse(codeAddress), "foo1"); + +返回值: "01"表示有权限,"00"表示没有权限。 +``` + +G. 如果被代理人的权限时间没有结束,代理人可以提前收回代理给别人的权限。 + +```java +sdk.nativevm().auth().withdraw(identity1.dnaid,password,identity1.controls.get(0).getSalt(),1,Helper.reverse(codeAddress),identityX.dnaid,"role1",account,sdk.DEFAULT_GAS_LIMIT,500); +``` + +H. 合约管理员可以将自己的管理权限转移给其他的dnaid + +```java +String txhash = sdk.nativevm().auth().sendTransfer(adminIdentity.dnaid,password,adminIdentity.controls.get(0).getSalt(),1,Helper.reverse(codeAddress),adminIdentity.dnaid, +account,sdk.DEFAULT_GAS_LIMIT,0); +``` + + + +DNA合约示例: +```c# +using Neo.SmartContract.Framework; +using Neo.SmartContract.Framework.Services.Neo; +using Neo.SmartContract.Framework.Services.System; +using System; +using System.ComponentModel; +using System.Numerics; + +namespace Example +{ + public class AppContract : SmartContract + { + public struct initContractAdminParam + { + public byte[] adminDnaID; + } + + public struct verifyTokenParam + { + public byte[] contractAddr; //合约地址 + public byte[] calllerDnaID; //调用者dnaid + public string funcName; //调用的函数名 + public int keyNo; //使用调用者dnaid的第几把公钥 + } + + //the admin DNA ID of this contract must be hardcoded. + public static readonly byte[] adminDnaID = "did:ont:AazEvfQPcQ2GEFFPLF1ZLwQ7K5jDn81hve".AsByteArray(); + + public static Object Main(string operation,object[] args) + { + if (operation == "init") return init(); + + if (operation == "foo") + { + //we need to check if the caller is authorized to invoke foo + if (!verifyToken(operation, args)) return "no auth"; + + return foo(); + } + if (operation == "foo2") + { + //we need to check if the caller is authorized to invoke foo + if (!verifyToken(operation, args)) return "no auth"; + + return foo2(); + } + if (operation == "foo3") + { + //we need to check if the caller is authorized to invoke foo + if (!verifyToken(operation, args)) return "no auth"; + + return foo3(); + } + + return "over"; + } + + public static string foo() + { + return "A"; + } + public static string foo2() + { + return "B"; + } + public static string foo3() + { + return "C"; + } + + //this method is a must-defined method if you want to use native auth contract. + public static bool init() + { + byte[] authContractAddr = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06 }; + byte[] ret = Native.Invoke(0, authContractAddr, "initContractAdmin", adminDnaID); + return ret[0] == 1; + } + + internal static bool verifyToken(string operation, object[] args) + { + verifyTokenParam param = new verifyTokenParam{}; + param.contractAddr = ExecutionEngine.ExecutingScriptHash; + param.funcName = operation; + param.calllerDnaID = (byte[])args[0]; + param.keyNo = (int)args[1]; + + byte[] authContractAddr = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x06 }; + byte[] ret = Native.Invoke(0, authContractAddr, "verifyToken", param); + return ret[0] == 1; + } + } +} +``` + + +### 权限合约接口 + +Java-SDK已经封装好权限合约的调用接口,可以通过Java-SDK进行权限管理。 + +#### 1. 合约管理员转让合约管理权限 + +```java +String sendTransfer(String adminDnaId, String password, byte[] salt, String contractAddr, String newAdminDnaID, long keyNo, Account payerAcct, long gaslimit, long gasprice) +``` +|说明||描述| +|:--|:--|:--| +|功能说明|合约管理员转让合约管理权限|此函数必须由合约管理员调用,即将会以adminDnaID名下编号为keyNo的公钥来验证交易签名是否合法。| +|参数说明|字段|描述| +||adminDnaId|合约管理员dnaid| +||password|合约管理员密码| +||salt |私钥解密参数| +||contractAddr|合约地址| +||newAdminDnaID|新的管理员| +||keyNo|合约管理员的公钥编号| +||payerAcct|付费账户| +||gaslimit|gas价格| +||gasprice|gas价格| +|返回值说明|交易hash|| + +#### 2. 为角色分配函数 +```java +String assignFuncsToRole(String adminDnaID,String password,byte[] salt,String contractAddr,String role,String[] funcName,long keyNo,Account payerAcct,long gaslimit,long gasprice) +``` +|说明||描述| +|:--|:--|:--| +|功能说明|为角色分配函数|必须由合约管理者调用,将所有函数自动绑定到role,若已经绑定,自动跳过,最后返回true。| +|参数说明|字段|描述| +||adminDnaId|合约管理员dnaid| +||password|合约管理员密码| +||salt|私钥解密参数| +||contractAddr|合约地址| +||role|角色| +||funcName|函数名数组| +||keyNo|合约管理员的公钥编号| +||payerAcct|付费账户| +||gaslimit|gas价格| +||gasprice|gas价格| +|返回值说明|交易hash|| + +#### 3. 绑定角色到实体身份 +```java +String assignDnaIDsToRole(String adminDnaId,String password,byte[] salt, String contractAddr,String role,String[] dnaIDs,long keyNo,Account payerAcct,long gaslimit,long gasprice) +``` + |说明||描述| + |:--|:--|:--| + |功能说明|绑定角色到实体身份|必须由合约管理者调用,dnaIDs数组中的DNA ID被分配role角色,最后返回true。 在当前实现中,权限token的级别level默认等于2。| + |参数说明|字段|描述| + ||adminDnaId|合约管理员dnaid| + ||password|合约管理员密码| + ||salt|私钥解密参数| + ||contractAddr|合约地址| + ||role|角色| + ||dnaIDs|dnaid数组| + ||keyNo|合约管理员的公钥编号| + ||payerAcct|付费账户| + ||gaslimit|gas价格| + ||gasprice|gas价格| + |返回值说明|交易hash|| + +#### 4. 将合约调用权代理给其他人 +```java +String delegate(String dnaid,String password,byte[] salt,String contractAddr,String toDnaId,String role,long period,long level,long keyNo,Account payerAcct,long gaslimit,long gasprice) +``` + 角色拥有者可以将角色代理给其他人,from是转让者的DNA ID,to是代理人的DNA ID,role表示要代理的角色,period参数指定委托任期时间(以second为单位)。 + + 代理人可以再次将其角色代理给更多的人,level参数指定委托层次深度。例如, + + level = 1: 此时代理人就无法将其角色再次代理出去;当前实现只支持此情况。 + + |说明||描述| + |:--|:--|:--| + |功能说明|将合约调用权代理给其他人|| + |参数说明|字段|描述| + ||dnaid|拥有合约中某个函数调用权的dnaid| + ||password|dnaid密码| + ||salt|私钥解密参数| + ||contractAddr|合约地址| + ||toDnaId|接收合约调用权的dnaid| + ||role|角色| + ||period|以秒为单位的时间| + ||keyNo|dnaid的公钥编号| + ||payerAcct|付费账户| + ||gaslimit|gas价格| + ||gasprice|gas价格| + |返回值说明|交易hash|| + +#### 5. 收回合约调用权 +```java +String withdraw(String initiatorDnaid,String password,byte[] salt,String contractAddr,String delegate, String role,long keyNo,Account payerAcct,long gaslimit,long gasprice) +``` + 角色拥有者可以提前将角色代理提前撤回,initiatorDnaid是发起者,delegate是角色代理人,initiator将代理给delegate的角色提前撤回。 + + |说明||描述| + |:--|:--|:--| + |功能说明|收回合约调用权(配合delegate使用)|| + |参数说明|字段|描述| + ||initiatorDnaid|将合约调用权转让给其他人的dnaid| + ||password|dnaid密码| + ||salt|私钥解密参数| + ||contractAddr|合约地址| + ||delegate|代理人dnaid| + ||role|角色| + ||keyNo|dnaid的公钥编号| + ||payerAcct|付费账户| + ||gaslimit|gas价格| + ||gasprice|gas价格| + |返回值说明|交易hash|| + +#### 6. 验证合约调用token的有效性 +```java +String verifyToken(String dnaid,String password,byte[] salt,String contractAddr,String funcName,long keyNo) +``` +|说明||描述| +|:--|:--|:--| +|功能说明|验证合约调用token的有效性|| +|参数说明|字段|描述| +||dnaid|验证的dnaid| +||password|dnaid密码| +||salt|私钥解密参数| +||contractAddr|合约地址| +||funcName|函数名| +||keyNo|dnaid的公钥编号| +|返回值说明|交易hash|| + diff --git a/docs/basic.md b/docs/basic.md new file mode 100644 index 0000000..d1e5f61 --- /dev/null +++ b/docs/basic.md @@ -0,0 +1,212 @@ +

区块链交互基本操作

+ +

Version 1.0.0

+ + + +以下针对使用SDK和区块交互的基本操作,以及相关数据结构定义。 + +用Java SDK之前,请使用以下方式初始化DnaSDK实例。 + +```java +DnaSdk dnaSdk = DnaSdk.getInstance(); +dnaSdk.setRpc(rpcUrl); +dnaSdk.setRestful(restUrl); +dnaSdk.setDefaultConnect(wm.getRestful()); +dnaSdk.openWalletFile("assetDemo.json"); +``` +> Note: setRestful表示采用restful接口建立连接,setRpc表示采用rpc接口建立连接,setDefaultConnect表示设置默认的链接方式。 + + +## 与链交互接口 + + +* 获取当前区块高度 +```java +int height = dnaSdk.getConnect().getBlockHeight(); +``` + +* 获取区块 + +根据高度获取区块 +```java +Block block = dnaSdk.getConnect().getBlock(9757); +``` + +根据区块hash获得区块 + +```java +Block block = dnaSdk.getConnect().getBlock(blockhash); +``` + +* 获得block json数据 + +根据高度获取区块json +```java +Object block = dnaSdk.getConnect().getBlockJson(9757); +``` + +根据区块hash获得区块json + +```java +Object block = dnaSdk.getConnect().getBlockJson(blockhash); +``` +* 获得合约代码 + +根据合约hash获得合约代码 + +```java +Object contract = dnaSdk.getConnect().getContract(contractHash) +``` + +根据合约hash获得合约代码json数据 + +```java +Object contractJson = dnaSdk.getConnect().getContractJson(hash) +``` + +* 查询余额 + +根据账户地址查询余额 + +```java +Object balance = dnaSdk.getConnect().getBalance(address) +``` + +* 获取区块链节点数 + +```java +int count = dnaSdk.getConnect().getNodeCount(); +``` + +* 获得区块高度 + +```java +int blockheight = dnaSdk.getConnect().getBlockHeight() +``` + +* 获得智能合约事件 + +根据高度获得智能合约事件 + +```java +Object event = dnaSdk.getConnect().getSmartCodeEvent(height) +``` + +根据交易hash获得智能合约事件 + +```java +Object event = dnaSdk.getConnect().getSmartCodeEvent(hash) +``` + +* 根据交易hash获得区块高度 + +```java +int blockheight = dnaSdk.getConnect().getBlockHeightByTxHash(txhash) +``` + +* 获得智能合约存储的数据 + +```java +String value = dnaSdk.getConnect().getStorage(codehash,key) +``` + +* 获得merkle证明 + +根据交易hash获得merkle证明 + +```java +Object proof = dnaSdk.getConnect().getMerkleProof(String hash) +``` + +* 从区块链中获取交易 + +根据交易hash获得交易对象 +```java +Transaction info = dnaSdk.getConnect().getTransaction(txhash); +``` + +根据交易hash获得交易json数据 + +```java +Object info = dnaSdk.getConnect().getTransactionJson(txhash); +``` + +* 从区块链中获取InvokeCodeTransaction + +```java +InvokeCodeTransaction t = (InvokeCodeTransaction) dnaSdk.getConnect().getTransaction(txhash); +``` +## 数据结构说明 + +* Block区块 + +| Field | Type | Description | +| :--------------: | :--------:| :------: | +| version| int| 版本号 | +| prevBlockHash| UInt256| 前一个区块的散列值| +| transactionsRoot| UInt256| 该区块中所有交易的Merkle树的根| +| blockRoot| UInt256| 区块根| +| timestamp| int| 区块时间戳,unix时间戳 | +| height| int| 区块高度 | +| consensusData| long | 共识数据 | +| consensusPayload| byte[] | 共识payload | +| nextBookKeeper| UInt160 | 下一个区块的记账合约的散列值 | +| sigData| array| 签名 | +| bookKeepers| array| 验签者 | +| hash| UInt256 | 该区块的hash值 | +| transactions| Transaction[] | 该区块的交易列表 | + + +* Transaction交易 + +| Field | Type | Description | +| :--------------: | :--------:| :------: | +| version| int| 版本号 | +| txType| TransactionType| 交易类型| +| nonce| int | 随机数| +| gasPrice| long | gas价格| +| gasLimit| long | gas上限| +| payer| Address | 支付交易费用账户| +| attributes| Attribute[]| 交易属性列表 | +| sigs| Sign[]| 签名数组 | +| payload| Payload | payload | + + +* TransactionType交易类型 + +| Value | Type | Description | +| :--------------: | :--------:| :------: | +| 208| int | 部署智能合约交易| +| 209| int | 调用智能合约交易 | +| 0| int | Bookkeeping | +| 4| int | 注册 | +| 5| int | 投票 | + + +* 签名字段 + +| Field | Type | Description | +| :--------------: | :--------:| :------: | +| pubKeys| array | 公钥数组| +| M| int | M | +| sigData| array | 签名值数组 | + + + +* Attribute交易属性 + +| Field | Type | Description | +| :--------------: | :--------:| :------: | +| usage | AttributeUsage | 用途| +| data| byte[] | 属性值 | + + +* TransactionAttributeUsage属性用途 + +| Value | Type | Description | +| :--------------: | :--------:| :------: | +| 0| int| Nonce| +| 32| int | Script | +| 129| int | DescriptionUrl | +| 144| int | Description | diff --git a/docs/errorcode.md b/docs/errorcode.md new file mode 100644 index 0000000..6117cf8 --- /dev/null +++ b/docs/errorcode.md @@ -0,0 +1,89 @@ +

错误码

+ +

Version 1.0.0

+ + + +| 返回代码 | 描述信息 | 说明 | +| :---- | ----------------------------- | ----------------- | +| 0 | SUCCESS | 成功 | +| 41001 | SESSION_EXPIRED | 会话无效或已过期( 需要重新登录) | +| 41002 | SERVICE_CEILING | 达到服务上限 | +| 41003 | ILLEGAL_DATAFORMAT | 不合法数据格式 | +| 41004 | INVALID_VERSION| 不合法的版本 | +| 42001 | INVALID_METHOD | 无效的方法 | +| 42002 | INVALID_PARAMS | 无效的参数 | +| 43001 | INVALID_TRANSACTION | 无效的交易 | +| 43002 | INVALID_ASSET | 无效的资产 | +| 43003 | INVALID_BLOCK | 无效的块 | +| 44001 | UNKNOWN_TRANSACTION | 找不到交易 | +| 44002 | UNKNOWN_ASSET | 找不到资产 | +| 44003 | UNKNOWN_BLOCK | 找不到块 | +| 44004 | UNKNWN_CONTRACT | 找不到合约 | +| 45001 | INTERNAL_ERROR | 内部错误 | +| 47001 | SMARTCODE_ERROR| 智能合约错误 | +|51001 | InvalidParams |Account Error,invalid params| +|51002 | UnsupportedKeyType |Account Error,unsupported key type| +|51003 | InvalidMessage |Account Error,invalid message| +|51004 | WithoutPrivate |Account Error,account without private key cannot generate signature| +|51005 | InvalidSM2Signature |Account Error,invalid SM2 signature parameter, ID (String) excepted| +|51006 | AccountInvalidInput |Account Error,account without public key cannot verify signature| +|51007 | AccountWithoutPublicKey |Account Error,unknown key type| +|51008 | UnknownKeyType |Account Error,null input| +|51009 | NullInput |Account Error,invalid data| +|51010 | InvalidData |Account Error,invalid params| +|51011 | Decoded3bytesError |Account Error,decoded 3 bytes error| +|51012 | DecodePrikeyPassphraseError |Account Error,decode prikey passphrase error| +|51013 | PrikeyLengthError |Account Error,Prikey length error| +|51014 | EncryptedPriKeyError |Account Error,null prikey error| +|51015 | encryptedPriKeyAddressPasswordErr |Account Error,encryptedPriKey address password not match.| +|51016 | EncriptPrivateKeyError |Account Error, encript privatekey error,| +|52001 | InputError |Uint256 Error,input error| +|52002 | ChecksumNotValidate |Base58 Error,Checksum does not validate| +|52003 | InputTooShort |Base58 Error,Input too short| +|52004 | UnknownCurve |Curve Error,unknown curve| +|52005 | UnknownCurveLabel |Curve Error,unknown curve label| +|52006 | UnknownAsymmetricKeyType |keyType Error,unknown asymmetric key type| +|52007 | InvalidSignatureData |Signature Error,invalid signature data: missing the ID parameter for SM3withSM2| +|52008 | InvalidSignatureDataLen |Signature Error,invalid signature data length| +|52009 | MalformedSignature |Signature Error,malformed signature| +|52010 | UnsupportedSignatureScheme |Signature Error,unsupported signature scheme:| +|52011 | DataSignatureErr |Signature Error,Data signature error.| +|52012 | UnSupportOperation |Address Error, UnsupportedOperationException| +|53001 | TxDeserializeError |Core Error,Transaction deserialize failed| +|53002 | BlockDeserializeError |Core Error,Block deserialize failed| +|54001 | MerkleVerifierErr |Wrong params: the tree size is smaller than the leaf index| +|54002 | TargetHashesErr |targetHashes error| +|54003 | ConstructedRootHashErr || +|54004 | AsserFailedHashFullTree |assert failed in hash full tree| +|54005 | LeftTreeFull | left tree always full | +|58001 | SendRawTxError |SmartCodeTx Error,sendRawTransaction error| +|58002 | TypeError |SmartCodeTx Error,type error| +|58003 | NullCodeHash |DnaIdTx Error,null codeHash| +|58004 | ParamError |DnaIdTx Error,param error| +|58005 | ParamErr |DnaIdTx Error,param error...| +|58006 | DidNull |DnaIdTx Error,SendDid or receiverDid is null in metaData| +|58007 | NotExistCliamIssuer |DnaIdTx Error,Not exist cliam issuer| +|58007 | NotFoundPublicKeyId |DnaIdTx Error,not found PublicKeyId| +|58008 | PublicKeyIdErr |DnaIdTx Error,PublicKeyId err| +|58009 | BlockHeightNotMatch |DnaIdTx Error,BlockHeight not match| +|58010 | NodesNotMatch |DnaIdTx Error,nodes not match| +|58011 | ResultIsNull |DnaIdTx Error,result is null| +|58012 | CreateDnaIdClaimErr |DnaIdTx Error, createDnaIdClaim error| +|58013 | VerifyDnaIdClaimErr |DnaIdTx Error, verifyDnaIdClaim error| +|58014 | WriteVarBytesError |DnaIdTx Error, writeVarBytes error| +|58101 | AssetNameError |DnaAsset Error,asset name error| +|58102 | DidError |OntAsset Error,Did error| +|58103 | NullPkId |OntAsset Error,null pkId| +|58104 | NullClaimId |OntAsset Error,null claimId| +|58105 | DnaAsset Error,amount is less than or equal to zero| +|58106 | ParamLengthNotSame |OntAsset Error,param length is not the same| +|58201 | NullKeyOrValue |RecordTx Error,null key or value| +|58202 | NullKey |RecordTx Error,null key| +|58301 | WebsocketNotInit |DnaSdk Error,websocket not init| +|58302 | ConnRestfulNotInit |DnaSdk Error,connRestful not init| +|58401 | SetParamsValueValueNumError |AbiFunction Error,setParamsValue value num error| +|58402 | InvalidUrlErr |Interfaces Error,Invalid url:| +|58403 | InvalidUrl |Interfaces Error,Invalid url:| +|58501 | GetAccountByAddressErr |WalletManager Error,getAccountByAddress err| +|59000 | OtherError| other error| diff --git a/docs/governance.md b/docs/governance.md new file mode 100644 index 0000000..6f50f98 --- /dev/null +++ b/docs/governance.md @@ -0,0 +1,347 @@ +

治理合约

+ +

Version 1.0.0

+ + + +## 治理合约接口 + +治理合约用于管理节点。目前提供了以下接口。 + +### 1. 申请成为候选节点 + +* 申请成为候选节点 + +```java +String registerCandidate(Account account, String peerPubkey, long initPos, String dnaid,String dnaidpwd,byte[] salt, long keyNo, Account payerAcct, long gaslimit, long gasprice) +``` + +参数说明: + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | account | Account | 节点钱包账户 | 必选 | +| | peerPubkey | String | 节点公钥 | 必选 | +| | initPos | long | 初始化权益 |必选| +| | dnaid | String |已授权的dnaid | 必选| +| | dnaidpwd | String | dnaid密码 |必选| +| | salt | byte[] | dnaid对应的salt |必选| +| | keyNo | long | 公钥索引 |必选| +| | payerAcct | Account | 支付交易费用的账户 |必选| +| | gaslimit | long | gaslimit | 必选 | +| | gasprice | long | gas价格 | 必选| +| 输出参数 | 交易hash | String | 交易hash | | + + + +### 2. 取消申请成为候选节点 + +* 取消申请成为候选节点,解冻抵押的ONT + +```java +String unRegisterCandidate(Account account, String peerPubkey,Account payerAcct, long gaslimit, long gasprice) +``` + + +参数说明: + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | account | Account | 节点钱包账户 | 必选 | +| | peerPubkey | String | 节点公钥 | 必选 | +| | payerAcct | Account | 支付交易费用的账户 |必选| +| | gaslimit | long | gaslimit | 必选 | +| | gasprice | long | gas价格 | 必选| +| 输出参数 | 交易hash | String | 交易hash | | + + + +### 3. 查询节点信息 + +* 查询节点信息 + +```java +String getPeerInfo(String peerPubkey) +``` + +参数说明: + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | peerPubkey | String | 节点公钥| 必选 | +| 输出参数 | 节点信息 | String | 节点信息 | | + +### 4. 查询所有节点信息 + +* 查询节点信息 + +```java +String getPeerInfoAll() +``` + +参数说明: + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | | | | | +| 输出参数 | 节点信息 | String | 节点信息 | | + + +### 5. 查询某个地址对某个节点的授权信息 + +* 查询某个地址对某个节点的授权信息 + +```java +String getAuthorizeInfo(String peerPubkey,Address addr) +``` + +参数说明: + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | peerPubkey | String | 节点公钥|需要 | +| 输入参数 | addr | String | 地址|需要 | +| 输出参数 | 节点授权信息 | String | 节点授权信息 | | + + +### 6. 取出处于未冻结状态的抵押 + +* 取出处于未冻结状态的抵押 + +```java +String withdraw(Account account,String peerPubkey[],long[] withdrawList,Account payerAcct,long gaslimit,long gasprice) +``` + +参数说明: + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | account | Account | 节点钱包账户 | 必选 | +| | peerPubkey | String[]| 节点公钥 | 必选 | +| | withdrawList | long[] | 初始化权益 |必选| +| | payerAcct | Account | 支付交易费用的账户 |必选| +| | gaslimit | long | gaslimit | 必选 | +| | gasprice | long | gas价格 | 必选| +| 输出参数 | 交易hash | String | 交易hash | | + + +### 7. 提取解绑gas + +* 提取解绑gas + +```java +String withdrawGas(Account account,Account payerAcct,long gaslimit,long gasprice) +``` + +参数说明: + + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | account | Account | 节点钱包账户 | 必选 | +| | payerAcct | Account | 支付交易费用的账户 |必选| +| | gaslimit | long | gaslimit | 必选 | +| | gasprice | long | gas价格 | 必选| +| 输出参数 | 交易hash | String | 交易hash | | + + +### 8. 赎回抵押权益获得收益 + +* 赎回抵押权益获得收益 + +```java +String withdrawFee(Account account,Account payerAcct,long gaslimit,long gasprice) +``` + +参数说明: + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | account | Account | 节点钱包账户 | 必选 | +| | payerAcct | Account | 支付交易费用的账户 |必选| +| | gaslimit | long | gaslimit | 必选 | +| | gasprice | long | gas价格 | 必选| +| 输出参数 | 交易hash | String | 交易hash | | + + +### 9. 退出节点 + +* 退出节点 + +```java +String quitNode(Account account,String peerPubkey,Account payerAcct,long gaslimit,long gasprice) +``` + +参数说明: + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | account | Account | 节点钱包账户 | 必选 | +| | peerPubkey | String | 节点公钥 | 必选 | +| | payerAcct | Account | 支付交易费用的账户 |必选| +| | gaslimit | long | gaslimit| 必选 | +| | gasprice | long | gas价格 | 必选| +| 输出参数 | 交易hash | String | 交易hash | | + + +返回值 +``` +交易hash +``` +### 10. 节点增加initPos + +* 节点增加initPos接口,只能由节点所有者调用 + +```java +String addInitPos(Account account,String peerPubkey,int pos,Account payerAcct,long gaslimit,long gasprice) +``` + +参数说明: + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | account | Account | 节点钱包账户 | 必选 | +| | peerPubkey | String | 节点公钥 | 必选 | +| | pos | int | 增加抵押的ont数量 | 必选 | +| | payerAcct | Account | 支付交易费用的账户 |必选| +| | gaslimit | long | gaslimit| 必选 | +| | gasprice | long | gas价格 | 必选| +| 输出参数 | 交易hash | String | 交易hash | | + + +### 11. 节点减少initPos +* 节点减少initPos接口,只能由节点所有者调用,initPos不能低于承诺值,不能低于已接受授权数量的1/10 + +```java +String reduceInitPos(Account account,String peerPubkey,int pos,Account payerAcct,long gaslimit,long gasprice) +``` + +参数说明: + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | account | Account | 节点钱包账户 | 必选 | +| | peerPubkey | String | 节点公钥 | 必选 | +| | pos | int | 减少抵押的ont数量 | 必选 | +| | payerAcct | Account | 支付交易费用的账户 |必选| +| | gaslimit | long | gaslimit| 必选 | +| | gasprice | long | gas价格 | 必选| +| 输出参数 | 交易hash | String | 交易hash | | + + +### 12. 节点设置自己独占激励的比例 + +* 节点设置自己独占激励的比例 + +```java +String setPeerCost(Account account,String peerPubkey,int peerCost,Account payerAcct,long gaslimit,long gasprice) +``` + +参数说明: + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | account | Account | 节点钱包账户 | 必选 | +| | peerPubkey | String | 节点公钥 | 必选 | +| | peerCost | int | 节点自己独占的比例 | 必选 | +| | payerAcct | Account | 支付交易费用的账户 |必选| +| | gaslimit | long | gaslimit| 必选 | +| | gasprice | long | gas价格 | 必选| +| 输出参数 | 交易hash | String | 交易hash | | + + +### 13. 节点修改自己接受的最大授权ONT数量 +* 节点修改自己接受的最大授权ONT数量 + +```java +String changeMaxAuthorization(Account account,String peerPubkey,int maxAuthorize,Account payerAcct,long gaslimit,long gasprice) +``` + +参数说明: + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | account | Account | 节点钱包账户 | 必选 | +| | peerPubkey | String | 节点公钥 | 必选 | +| | maxAuthorize | int | 节点自己接受的最大授权ont数量 | 必选 | +| | payerAcct | Account | 支付交易费用的账户 |必选| +| | gaslimit | long | gaslimit| 必选 | +| | gasprice | long | gas价格 | 必选| +| 输出参数 | 交易hash | String | 交易hash | | + + +### 14. 查询节点属性信息 + +* 查询节点属性信息 + +```java +String getPeerAttributes(String peerPubkey) +``` + +参数说明: + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | peerPubkey | String | 节点公钥 | 必选 | +| 输出参数 | | String | 节点属性信息 | | + + +### 15. 查询某地址得到的激励 + +* 查询某地址得到的激励 + +```java +String getSplitFeeAddress(String address) +``` + + +参数说明: + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | address | String | 地址 | 必选 | +| 输出参数 | | String | 查询某地址得到的激励 | | + +### 16. 给节点投票 + +* 给候选节点或者共识节点投票 + +```java +String authorizeForPeer(Account account,String peerPubkey[],long[] posList,Account payerAcct,long gaslimit,long gasprice) +``` + + +参数说明: + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | account | Account | 投票的账户 | 必选 | +| 输入参数 | peerPubkey | String[] | 接受投票的节点公钥数组 | 必选 | +| 输入参数 | posList | long[] | 抵押的权益 | 必选 | +| 输入参数 | payerAcct | Account | 支付交易费用的账户 | 必选 | +| 输入参数 | gaslimit | long | gaslimit | 必选 | +| 输入参数 | gasprice | long | gasprice | 必选 | +| 输出参数 | | String | 交易hash | | + +### 17. 取消给节点投票 + +* 取消给候选节点或者共识节点投票 + +```java +String unAuthorizeForPeer(Account account,String peerPubkey[],long[] posList,Account payerAcct,long gaslimit,long gasprice) +``` + + +参数说明: + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | account | Account | 投票的账户 | 必选 | +| 输入参数 | peerPubkey | String[] | 接受投票的节点公钥数组 | 必选 | +| 输入参数 | posList | long[] | 抵押的权益 | 必选 | +| 输入参数 | payerAcct | Account | 支付交易费用的账户 | 必选 | +| 输入参数 | gaslimit | long | gaslimit | 必选 | +| 输入参数 | gasprice | long | gasprice | 必选 | +| 输出参数 | | String | 交易hash | | + + diff --git a/docs/identity_claim.md b/docs/identity_claim.md new file mode 100644 index 0000000..0e9e7b5 --- /dev/null +++ b/docs/identity_claim.md @@ -0,0 +1,465 @@ +

数字身份

+ +

Version 1.0.0

+ + + +## 介绍 + +数字身份相关介绍可参考[DNA ID 身份标识协议及信任框架](https://github.com/ontio/ontology-DID)。 + +## 钱包文件及规范 + +钱包文件是一个Json格式的数据存储文件,可同时存储多个数字身份和多个数字资产账户。具体参考[钱包文件规范](../en/Wallet_File_Specification.md)。 + +为了创建数字身份,您首先需要创建/打开一个钱包文件。 + + +```java +//如果不存在钱包文件,会自动创建钱包文件。 +DnaSdk dnaSdk = DnaSdk.getInstance(); +dnaSdk.openWalletFile("Demo3.json"); +``` +> 注:目前仅支持文件形式钱包文件,也可以扩展支持数据库或其他存储方式。 + + + +## 数字身份数据结构 + +**Identity数据结构说明** + +`dnaid` 是代表身份的唯一的id +`label` 是用户给身份所取的名称。 +`lock` 表明身份是否被用户锁定了。客户端不能更新被锁定的身份信息。默认值为false。 +`controls` 是身份的所有控制对象ControlData的数组。 +`extra` 是客户端开发者存储额外信息的字段。可以为null。 + +``` +//Identity数据结构 +public class Identity { + public String label = ""; + public String dnaid = ""; + public boolean isDefault = false; + public boolean lock = false; + public List controls = new ArrayList(); + public Object extra = null; +} +``` + +`algorithm`是用来加密的算法名称。 +`parameters` 是加密算法所需参数。 +`curve` 是椭圆曲线的名称。 +`id` 是control的唯一标识。 +`key` 是NEP-2格式的私钥。 + +``` +public class Control { + public String algorithm = "ECDSA"; + public Map parameters = new HashMap() ; + public String id = ""; + public String key = ""; + public String salt = ""; + public String hash = "sha256"; + @JSONField(name = "enc-alg") + public String encAlg = "aes-256-gcm"; + public String address = ""; +} +``` + +## 数字身份接口 + + +### 1. 注册身份 + +创建数字身份指的是产生一个Identity数据结构的身份信息,并写入到到钱包文件中。 + +``` +Identity identity = dnaSdk.getConnect().createIdentity("passwordtest"); +//创建的账号或身份只在内存中,如果要写入钱包文件,需调用写入接口 +dnaSdk.getWalletMgr().writeWallet(); +``` + +**向链上注册身份** + +只有向区块链链成功注册身份之后,该身份才可以真正使用。 + +有两种方法实现向链上注册身份 + +方法一,注册者指定支付交易费用的账户地址 + +``` +Identity identity = dnaSdk.getWalletMgr().createIdentity(password); +dnaSdk.nativevm().dnaId().sendRegister(identity2,password,payerAcct,gaslimit,gasprice); +``` + + +方法二,将构造好的交易发送给服务器,让服务器进行交易费用账号的签名操作。 + + +``` +Identity identity = dnaSdk.getWalletMgr().createIdentity(password); +Transaction tx = dnaSdk.nativevm().dnaId().makeRegister(identity.dnaid,password,payerAcc.address,dnaSdk.DEFAULT_GAS_LIMIT,0); +dnaSdk.signTx(tx,identity.dnaid,password); +dnaSdk.getConnect().sendRawTransaction(tx); +``` + +链上注册成功后,对应此DNA ID的身份描述对象DDO将被存储在本体区块链上。 + +关于DDO的信息可以从[DNA ID 身份标识协议](https://github.com/ontio/ontology-DID/blob/master/README_cn.md) + +DDO 的数据格式。 +``` +{ + "DnaId": "did:dna:AQmUnTXbAjvMKfcRJappBp1mhFn2oRV2Rd", + "Attributes": [{ + "Type": "String", + "Value": "value1", + "Key": "key1" + }], + "Recovery": "AQmTJnojgMJXTWDE8rL5R5SRKLHr9TZmPR", + "Owners": [{ + "Type": "ECDSA", + "Curve": "P256", + "Value": "022af1c75dc0719e13f59cefcdebcb01c46e33c59ebfe3f63c81938df85f067903", + "PubKeyId": "did:dna:AQmUnTXbAjvMKfcRJappBp1mhFn2oRV2Rd#keys-1" + }, { + "Type": "ECDSA", + "Curve": "P256", + "Value": "03a47fff0443645d41140976cd4ce060a29ea084332174b2b2572a1589709e52f2", + "PubKeyId": "did:dna:AQmUnTXbAjvMKfcRJappBp1mhFn2oRV2Rd#keys-2" + }] +} +``` + +### 2. 身份管理 + +**导入身份** + +当用户已经拥有了一个数字身份或者数字账户,SDK支持将其导入到钱包文件中。 + +> Note: 建议导入一个数字身份之前,建议查询链上身份,如果链上身份DDO不存在,表示此数字身份未在链上注册,请使用上面注册数字身份的方法把身份注册到链上。 + + +```java +Identity identity = dnaSdk.getWalletMgr().importIdentity(encriptPrivateKey,password,salt,address); +//写入钱包 +dnaSdk.getWalletMgr().writeWallet(); +``` + + +参数说明: +encriptPrivateKey: 加密后的私钥 +password: 加密私钥使用的密码 +salt: 解密私钥用的参数 +address: 账户地址base58编码 + +**移除身份** + +```java +dnaSdk.getWalletMgr().getWallet().removeIdentity(dnaid); +//写入钱包 +dnaSdk.getWalletMgr().writeWallet(); +``` + +**设置默认账号或身份** + +```java +//根据账户地址设置默认账户 +dnaSdk.getWalletMgr().getWallet().setDefaultAccount(address); +//根据identity索引设置默认identity +dnaSdk.getWalletMgr().getWallet().setDefaultIdentity(index); +dnaSdk.getWalletMgr().getWallet().setDefaultIdentity(dnaid); +``` + +### 3. 查询链上身份信息 + +链上身份DDO信息,可以通过DNA ID进行查询。 + +```json +//通过DNA ID获取DDO +String ddo = dnaSdk.nativevm().dnaId().sendGetDDO(dnaid); + +//返回DDO格式 +{ + "Attributes": [{ + "Type": "String", + "Value": "value1", + "Key": "key1" + }], + "DnaId": "did:ont:TA5UqF8iPqecMdBzTdzzANVeY8HW1krrgy", + "Recovery": "TA6AhqudP1dcLknEXmFinHPugDdudDnMJZ", + "Owners": [{ + "Type": "ECDSA", + "Curve": "P256", + "Value": "12020346f8c238c9e4deaf6110e8f5967cf973f53b778ed183f4a6e7571acd51ddf80e", + "PubKeyId": "did:ont:TA5UqF8iPqecMdBzTdzzANVeY8HW1krrgy#keys-1" + }, { + "Type": "ECDSA", + "Curve": "P256", + "Value": "1202022fabd733d7d7d7009125bfde3cb0afe274769c78fd653079ecd5954ae9f52644", + "PubKeyId": "did:ont:TA5UqF8iPqecMdBzTdzzANVeY8HW1krrgy#keys-2" + }] +} + +``` + + + +### 4. 身份属性 + +#### 4.1 更新链上DDO属性 +方法一,指定支付交易费用的账户 + +```java +//添加或者更新属性 +String sendAddAttributes(String dnaid, String password,byte[] salt, Attribute[] attributes,Account payerAcct,long gaslimit,long gasprice) +``` + + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | password| String | 数字身份密码 | 必选,私钥解密的密码 | +| |salt | byte[] | | 必选 | +| | dnaid | String | 数字身份id | 必选,身份Id | +| | attributes | Attribute[]| 属性数组 | 必选 | +| | payerAcct | Account | 交易费用支付者账户 | 必选, | +| | gaslimit | long | gaslimit | 必选 | +| | gasprice | long | gas价格 | 必选 | +| 输出参数 | txhash | String | 交易hash | 交易hash是64位字符串 | + + + +方法二,将构造好的交易发送给服务器,让服务器进行交易费用账号的签名操作。 +```java +Transaction makeAddAttributes(String dnaid, String password, byte[] salt,Attribute[] attributes,String payer, + long gaslimit,long gasprice) +``` + +示例代码 +```java +Transaction tx = dnaSdk.nativevm().dnaId().makeAddAttributes(dnaid,password,salt,attributes,payer,gaslimit,0); +dnaSdk.signTx(tx,identity.dnaid,password); +dnaSdk.getConnect().sendRawTransaction(tx); +``` + +#### 4.2 移除链上DDO属性 + +方法一 + +``` +String sendRemoveAttribute(String dnaid,String password,byte[] salt,String path,Account payerAcct,long gaslimit,long gasprice) +``` + + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | password| String | 数字身份密码 | 必选 | +| | salt| byte[] | | required | +| | dnaid | String | 数字身份ID | 必选,身份Id | +| | path | byte[] | path | 必选,path | +| | payer | String | payer | 必选,payer | +| | payerpassword | String | 支付交易费用的账户地址 | 必选 | +| | gas | long | 支付的交易费用 | 必选 | +| 输出参数 | txhash | String | 交易hash | 交易hash是64位字符串 | + + +方法二,将构造好的交易发送给服务器,让服务器进行交易费用账号的签名操作。 +``` +Transaction makeRemoveAttribute(String dnaid,String password,salt,String path,String payer,long gaslimit,long gasprice) +``` + +示例代码: +``` +Transaction tx = dnaSdk.nativevm().dnaId().makeRemoveAttribute(dnaid,password,salt,path,payer,gaslimit,0); +dnaSdk.signTx(tx,identity.dnaid,password); +dnaSdk.getConnect().sendRawTransaction(tx); +``` + +### 5. 身份公钥 + +一个身份可以有多个控制人,身份中的公钥是控制人的公钥列表。 +#### 5.1 添加公钥 + +方法一 + +```java +String sendAddPubKey(String dnaid, String password,byte[] salt, String newpubkey,Account payerAcct,long gaslimit,long gasprice) +``` + + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | password| String | 数字身份密码 | 必选 | +| | salt| byte[] | | required | +| | dnaid | String | 数字身份ID | 必选,身份Id | +| | newpubkey| String |公钥 | 必选, newpubkey| +| | payerAcct | Account | Payment transaction account | 必选,payer | +| | gaslimit | long | gaslimit | 必选 | +| | gasprice | long | gas价格 | 必选 | +| 输出参数 | txhash | String | 交易hash | 交易hash是64位字符串 | + + +方法二,将构造好的交易发送给服务器,让服务器进行交易费用账号的签名操作。 + +```java +Transaction makeAddPubKey(String dnaid,String password,byte[] salt,String newpubkey,String payer,long gaslimit,long gasprice) +``` +参数说明请参考方法一sendAddPubKey + +示例代码 +```java +Transaction tx = dnaSdk.nativevm().dnaId().makeAddPubKey(dnaid,password,byte[] salt,newpubkey,payer,gaslimit,gasprice); +dnaSdk.signTx(tx,identity.dnaid,password); +dnaSdk.getConnect().sendRawTransaction(tx); +``` + +方法三,recovery机制 +recovery可以为dnaid添加公钥 +```java +String sendAddPubKey(String dnaid,String recoveryAddr, String password, byte[] salt,String newpubkey,Account payerAcct,long gaslimit,long gasprice) +``` + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | dnaid | String | 数字身份ID | 必选,身份Id | +| | recoveryAddr| String | recovery地址 | 必选 | +| | password| String | recovery密码 | 必选 | +| | salt| byte[] | | required | +| | newpubkey| String |公钥 | 必选, newpubkey| +| | payer | String | payer | 必选,payer | +| | payerpwd | String | 支付交易费用的账户地址 | 必选 | +| | gaslimit | long | gaslimit | 必选 | +| | gasprice | long | gas价格 | 必选 | +| 输出参数 | txhash | String | 交易hash | 交易hash是64位字符串 | + + +方法四(recovery机制) + +```java +Transaction makeAddPubKey(String dnaid,String recoveryAddr,String password,byte[] salt,String newpubkey, + String payer,long gaslimit,long gasprice) +``` + +参数说明请参考方法三 + + +#### 5.2 删除公钥 + +方法一,删除公钥 + +```java +String sendRemovePubKey(String dnaid, String password,byte[] salt, String removePubkey,Account payerAcct,long gaslimit,long gasprice) +``` + + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | password| String | 数字身份密码 | 必选 | +| | salt| byte[] | | required | +| | dnaid | String | 数字身份ID | 必选,身份Id | +| | removePubkey| String |公钥 | 必选, removePubkey| +| | payer | String | payer | 必选,payer | +| | payerpassword | String | 支付交易费用的账户地址 | 必选 | +| | gas | long | 支付的交易费用 | 必选 | +| 输出参数 | txhash | String | 交易hash | 交易hash是64位字符串 | + + +方法二,将构造好的交易发送给服务器,让服务器进行交易费用账号的签名操作。 + +```java +Transaction tx = dnaSdk.nativevm().dnaId().makeRemovePubKey(dnaid,password,salt,removePubkey,payer,gas); +dnaSdk.signTx(tx,identity.dnaid.replace(Common.diddna,""),password,salt); +dnaSdk.getConnect().sendRawTransaction(tx); +``` + +方法三,恢复人机制 +```java +String sendRemovePubKey(String dnaid, String recoveryAddr,String password, byte[] salt,String removePubkey,Account payerAcct,long gaslimit,long gasprice) +``` + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | dnaid | String | 数字身份ID | 必选,身份Id | +| | recoveryAddr| String | recovery地址 | 必选 | +| | password| String | recovery密码 | 必选 | +| | salt| byte[] | | required | +| | newpubkey| String |公钥 | 必选, newpubkey| +| | payerAcct | Account | Payment transaction account | 必选,payer | +| | gaslimit | long | gaslimit | 必选 | +| | gasprice | long | gas价格 | 必选 | +| 输出参数 | txhash | String | 交易hash | 交易hash是64位字符串 | + + +方法四(recovery机制) +```java +Transaction makeRemovePubKey(String dnaid,String recoveryAddr, String password,byte[] salt, String removePubkey,String payer, + long gaslimit,long gasprice) +``` + +参数说明请参考方法三 + +### 6. 身份恢复人 + +当dnaid中控制人私钥丢失时,身份恢复人可以设置新的控制人。 +#### 6.1 添加恢复人 + +方法一 + +```java +String sendAddRecovery(String dnaid, String password,byte[] salt, String recoveryAddr,Account payerAcct,long gaslimit,long gasprice) +``` + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | password| String | 数字身份密码 | 必选 | +| | salt| byte[] | | required | +| | dnaid | String | 数字身份ID | 必选,身份Id | +| | recoveryAddr| String |recovery账户地址 | 必选,recovery| +| | payerAcct | Account | payerAcct | 必选,payer | +| | gaslimit | long | gaslimit | 必选 | +| | gasprice | long | gas价格 | 必选 | +| 输出参数 | txhash | String | 交易hash | 交易hash是64位字符串 | + + +方法二,将构造好的交易发送给服务器,让服务器进行交易费用账号的签名操作。 +``` +Transaction makeAddRecovery(String dnaid, String password,byte[] salt, String recoveryAddr,String payer,long gaslimit,long gasprice) +``` + +示例 +``` +Transaction tx = dnaSdk.nativevm().dnaId().makeAddRecovery(dnaid,password,salt,recovery,payer,gas); +dnaSdk.signTx(tx,identity.dnaid.replace(Common.diddna,""),password,salt); +dnaSdk.getConnect().sendRawTransaction(tx); +``` + +#### 6.2 修改recovery + +方法一 +``` +String sendChangeRecovery(String dnaid, String newRecovery, String oldRecovery, String password,,byte[] salt,long gaslimit,long gasprice) +``` + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 |dnaid | String | 数字身份ID | 必选,身份Id | +| | newRecovery| String |newRecovery账户地址 | 必选,newRecovery| +| | oldRecovery| String |oldRecovery账户地址 | 必选,oldRecovery| +| | oldRecovery password | String | oldRecovery password | 必选 | +| | password| String | 数字身份密码 | 必选 | +| | salt| byte[] | | required | +| | gaslimit | long | gaslimit | 必选 | +| | gasprice | long | gasprice | 必选 | +| 输出参数 | txhash | String | 交易hash | 交易hash是64位字符串 | + + +方法二 +``` +Transaction makeChangeRecovery(String dnaid, String newRecovery, String oldRecovery, String password,byte[] salt,long gaslimit,long gasprice) +``` + +参数说明请参考上面的方法一 + + + + diff --git a/docs/interface.md b/docs/interface.md new file mode 100644 index 0000000..e7b9dc9 --- /dev/null +++ b/docs/interface.md @@ -0,0 +1,296 @@ +

DNA Java SDK 接口

+ +

Version 1.0.0

+ + +## 介绍: + +本章节列出了Java SDK中关键的,SDK接口按如下几类区分: + +* 初始化接口 +* 与链交互接口 +* 钱包管理接口 +* 数字资产接口 +* 数字身份接口 +* NEO智能合约部署与调用接口 +* Native合约调用 +* 签名验签 + + +### 初始化接口: + +包括打开钱包文件和设置与链交互方式 + ``` + | Function | Description + ----|-----------------------------------------------|------------------------ + 1 | sdk.setRpc(rpcUrl) | 设置rpc + 2 | sdk.setRestful(restUrl) | 设置restful + 3 | sdk.setWesocket(wsUrl, lock) | 设置websocket + 4 | wm.setDefaultConnect(wm.getWebSocket()); | 设置默认与链交互方式 + 5 | wm.openWalletFile("OntAssetDemo.json"); | 打开钱包 + ``` + +### 与链交互接口: + +* 交互接口列表: +``` + + | Main Function | Description + -----|----------------------------------------------------------|--------------------------------------------- + 1 | dnaSdk.getConnect().getNodeCount() | 查询节点数量 + 2 | dnaSdk.getConnect().getBlock(15) | 查询块 + 3 | dnaSdk.getConnect().getBlockJson(15) | 查询块 + 4 | dnaSdk.getConnect().getBlockJson("txhash") | 查询块 + 5 | dnaSdk.getConnect().getBlock("txhash") | 查询块 + 6 | dnaSdk.getConnect().getBlockHeight() | 查询当前块高 + 7 | dnaSdk.getConnect().getTransaction("txhash") | 查询交易 + 8 | dnaSdk.getConnect().getStorage("contractaddress", key) | 查询智能合约存储 + 9 | dnaSdk.getConnect().getBalance("address") | 查询余额 + 10 | dnaSdk.getConnect().getContractJson("contractaddress") | 查询智能合约 + 11 | dnaSdk.getConnect().getSmartCodeEvent(59) | 查询智能合约事件 + 12 | dnaSdk.getConnect().getSmartCodeEvent("txhash") | 查询智能合约事件 + 13 | dnaSdk.getConnect().getBlockHeightByTxHash("txhash") | 查询交易所在高度 + 14 | dnaSdk.getConnect().getMerkleProof("txhash") | 获取merkle证明 + 15 | dnaSdk.getConnect().sendRawTransaction("txhexString") | 发送交易 + 16 | dnaSdk.getConnect().sendRawTransaction(Transaction) | 发送交易 + 17 | dnaSdk.getConnect().sendRawTransactionPreExec() | 发送预执行交易 + 18 | dnaSdk.getConnect().getAllowance("ont","from","to") | 查询允许使用值 + 19 | dnaSdk.getConnect().getMemPoolTxCount() | 查询交易池中交易总量 + 20 | dnaSdk.getConnect().getMemPoolTxState() | 查询交易池中交易状态 + 21 | dnaSdk.getConnect().syncSendRawTransaction("data") | 同步发送交易 +``` + +### 钱包管理接口: + +包括数字资产和数字身份管理 + +* 数字资产账户: + +``` + | Main Function | Description + ----|----------------------------------------------------------------------------|------------------------ + 1 | Account importAccount(String encryptedPrikey, String pwd,byte[] salt,String address) | 导入资产账户 + 2 | Account createAccount(String password) | 创建资产账户 + 3 | Account createAccountFromPriKey(String password, String prikey) | 根据私钥创建 + 4 | AccountInfo createAccountInfo(String password) | 根据私钥创建 + 5 | AccountInfo createAccountInfoFromPriKey(String password, String prikey) | 根据私钥创建 + 6 | AccountInfo getAccountInfo(String address, String password,byte[] salt) | 获取账号信息 + 7 | List getAccounts() | 查询所有账号 + 8 | Account getAccount(String address) | 获取账户 + 9 | Account getDefaultAccount() | 获取默认账户 +``` + +* 数字身份: +``` + | Main Function | Description + ----|----------------------------------------------------------------------------|------------------------ + 1 | Identity importIdentity(String encryptedPrikey, String pwd,byte[] salt,String address) | 导入身份 + 2 | Identity createIdentity(String password) | 创建身份 + 3 | Identity createIdentityFromPriKey(String password, String prikey) | 根据私钥创建 + 4 | IdentityInfo createIdentityInfo(String password) | 创建身份 + 5 | IdentityInfo createIdentityInfoFromPriKey(String password, String prikey) | 根据私钥创建 + 6 | IdentityInfo getIdentityInfo(String dnaid, String password) | 查询身份信息 + 7 | List getIdentitys() | 查询所有身份 + 8 | Identity getIdentity(String dnaid) | 获取身份 + 9 | Identity getDefaultIdentity() | 获取默认身份 + 10 | Identity addDnaIdController(String dnaid, String key, String id) | 添加控制人 +``` + +### 数字资产: +1.原生数字资产 +2.Nep-5智能合约数字资产 + +* 原生数字资产: + +ont: +``` + + | Main Function | Description + -----|-------------------------------------------------------------------------------------------------------------|--------------------------------------------- + 1 | String sendTransfer(Account sendAcct, String recvAddr, long amount,Account payerAcct,long gaslimit,long gasprice) | 转账 + 2 | long queryBalanceOf(String address) | 查询余额 + 3 | long queryAllowance(String fromAddr,String toAddr) | 查询Allowance + 4 | String sendApprove(Account sendAcct, String recvAddr, long amount,Account payerAcct,long gaslimit,long gasprice) | 发送Approve + 5 | String sendTransferFrom(Account sendAcct, String fromAddr, String toAddr,long amount,Account payerAcct,long gaslimit,long gasprice) | 发送TransferFrom + 6 | String queryName() | 查询资产名 + 7 | String querySymbol() | 查询资产Symbol + 8 | long queryDecimals() | 查询精度 + 9 | long queryTotalSupply() | 查询总供应量 + +``` +ong: +``` + + | Main Function | Description + -----|-------------------------------------------------------------------------------------------------------------|--------------------------------------------- + 1 | String sendTransfer(Account sendAcct, String recvAddr, long amount,Account payerAcct,long gaslimit,long gasprice) | 转账 + 2 | long queryBalanceOf(String address) | 查询余额 + 3 | long queryAllowance(String fromAddr,String toAddr) | 查询Allowance + 4 | String sendApprove(Account sendAcct, String recvAddr, long amount,Account payerAcct,long gaslimit,long gasprice) | 发送Approve + 5 | String sendTransferFrom(Account sendAcct, String fromAddr, String toAddr,long amount,Account payerAcct,long gaslimit,long gasprice) | 发送TransferFrom + 6 | String queryName() | 查询资产名 + 7 | String querySymbol() | 查询资产Symbol + 8 | long queryDecimals() | 查询精度 + 9 | long queryTotalSupply() | 查询总供应量 + 10 | String claimOng(Account sendAcct, String toAddr, long amount, Account payerAcct, long gaslimit, long gasprice) | 提取ong + 11 | String unclaimOng(String address) | 查询未提取的ong + +``` + +* Nep-5智能合约数字资产: + +``` + | Main Function | Description + -----|-----------------------------------------------------------------------------------------------|--------------------------------------------- + 1 | void setContractAddress(String codeHash) | 设置合约地址 + 2 | String sendInit(Account acct, Account payerAcct,long gaslimit,long gasprice) | 初始化 + 3 | long sendInitGetGasLimit() | 预执行初始化 + 4 | String sendTransfer(Account acct, String recvAddr, long amount,Account payerAcct, long gaslimit,long gasprice) | 转账 + 5 | long sendTransferGetGasLimit(Account acct, String recvAddr, long amount) | 预执行转账 + 6 | String queryBalanceOf(String addr) | 查询余额 + 7 | String queryTotalSupply() | 查询总供应量 + 8 | String queryName() | 查询名字 + 9 | String queryDecimals() | 查询精度 + 10 | String querySymbol() | 查询资产Symbol + +``` + +### 数字身份: +1.数字身份包括注册、公钥、属性、恢复人等操作。 +2.claim接口包括颁发和验证 +3.claim存证接口 + +* dnaid功能接口: +``` + | Main Function | Description + -----|-------------------------------------------------------------------------------------------------------------|--------------------------------------------- + 1 | String getContractAddress() | 查询合约地址 + 2 | Identity sendRegister(Identity ident, String password,byte[] salt,Account payerAcct,long gaslimit,long gasprice) | 注册dnaid + 3 | Identity sendRegisterPreExec(Identity ident, String password,byte[] salt,Account payerAcct,long gaslimit,long gasprice) | 预执行注册dnaid + 4 | Identity sendRegisterWithAttrs(Identity ident, String password,byte[] salt,Attribute[] attributes,Account payerAcct,long gaslimit,long gasprice) | 注册dnaid并添加属性 + 5 | String sendAddPubKey(String dnaid, String password,byte[] salt, String newpubkey,Account payerAcct,long gaslimit,long gasprice) | 添加公钥 + 6 | String sendAddPubKey(String dnaid,String recoveryDnaid, String password,byte[] salt, String newpubkey,Account payerAcct,long gaslimit,long gasprice) | 添加公钥 + 7 | String sendGetPublicKeys(String dnaid) | 获取公钥 + 8 | String sendRemovePubKey(String dnaid, String password,byte[] salt, String removePubkey,Account payerAcct,long gaslimit,long gasprice) | 删除公钥 + 9 | String sendRemovePubKey(String dnaid, String recoveryDnaid,String password,byte[] salt, String removePubkey,Account payerAcct,long gaslimit,long gasprice)| 删除公钥 + 10 | String sendGetKeyState(String dnaid,int index) | 获取某公钥状态 + 11 | String sendAddAttributes(String dnaid, String password,byte[] salt, Attribute[] attributes,Account payerAcct,long gaslimit,long gasprice) | 添加属性 + 12 | String sendGetAttributes(String dnaid) | 查询属性 + 13 | String sendRemoveAttribute(String dnaid,String password,byte[] salt,String path,Account payerAcct,long gaslimit,long gasprice) | 删除属性 + 14 | String sendAddRecovery(String dnaid, String password,byte[] salt, String recoveryDnaid,Account payerAcct,long gaslimit,long gasprice) | 添加恢复人 + 15 | String sendChangeRecovery(String dnaid, String newRecovery, String oldRecovery, String password,byte[] salt,Account payerAcct, long gaslimit,long gasprice) | 修改恢复人 + 16 | String sendGetDDO(String dnaid) | 查询DDO + +``` + +* 构造交易接口: + + ``` + | Make Transaction Function | Description + ----|---------------------------------------------------------------------------------------------------------------------|------------------------ + 1 | Transaction makeRegister(String dnaid,String password,byte[] salt,String payer,long gaslimit,long gasprice) | 构造注册交易 + 2 | Transaction makeRegisterWithAttrs(String dnaid, String password,byte[] salt, Attribute[] attributes, String payer, long gaslimit, long gasprice) | 构造注册dnaid并添加属性交易 + 3 | Transaction makeAddPubKey(String dnaid,String password,byte[] salt,String newpubkey,String payer,long gaslimit,long gasprice) | 构造添加公钥交易 + 4 | Transaction makeAddPubKey(String dnaid,String recoveryAddr,String password,byte[] salt,String newpubkey,String payer,long gaslimit,long gasprice) | 构造添加公钥交易 + 5 | Transaction makeRemovePubKey(String dnaid, String password,byte[] salt, String removePubkey,String payer,long gaslimit,long gasprice) | 构造删除公钥交易 + 6 | Transaction makeRemovePubKey(String dnaid,String recoveryAddr, String password,byte[] salt, String removePubkey,String payer,long gaslimit,long gasprice)| 构造删除公钥交易 + 7 | Transaction makeAddAttributes(String dnaid, String password,byte[] salt, Attribute[] attributes,String payer,long gaslimit,long gasprice) | 构造添加属性交易 + 8 | Transaction makeRemoveAttribute(String dnaid,String password,byte[] salt,String path,String payer,long gaslimit,long gasprice) | 构造删除属性交易 + 9 | Transaction makeAddRecovery(String dnaid, String password,byte[] salt, String recoveryAddr,String payer,long gaslimit,long gasprice) | 构造添加恢复人交易 + ``` + +* Claim相关接口: + + ``` + | Claim Function | Description + ----|-------------------------------------------------------------------------------------------------------------------------------|------------------------ + 1 | public Object getMerkleProof(String txhash) | 获取merkle证明 + 2 | boolean verifyMerkleProof(String claim) | 验证merkle证明 + 3 | String createDnaIdClaim(String signerDnaid, String pwd, byte[] salt,String context, Map claimMap, Map metaData,Map clmRevMap,long expire) | 创建claim + 4 | boolean verifyDnaIdClaim(String claim) | 验证claim + + ``` + +* Claim存证接口: + + ``` + | Function | Description + ----|-------------------------------------------------------------------------------------------------------------|------------------------ + 1 | String sendCommit(String issuerDnaid,String password,byte[] salt,String subjectDnaid,String claimId,Account payerAcct,long gaslimit,long gasprice) | 存储claim + 2 | String sendRevoke(String issuerDnaid,String password,byte[] salt,String claimId,Account payerAcct,long gaslimit,long gasprice) | 吊销 + 3 | String sendGetStatus(String claimId) | 获取状态 + + ``` + + ### 智能合约部署与调用接口 + + 部署与调用 + ``` + | Function | Description + ----|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------ + 1 | DeployCode makeDeployCodeTransaction(String code, boolean needStorage, String name, String version, String author, String email, String desp, byte vmtype,String payer,long gaslimit,long gasprice)| 部署 + 2 | InvokeCode makeInvokeCodeTransaction(String codeAddr,String method,byte[] params, String payer,long gaslimit,long gasprice) | 调用 + + ``` + + ### Native合约调用 + + #### 权限管理合约 + +* 权限管理功能接口: + ``` + | Function | Description + ----|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------ + 1 | String sendTransfer(String adminDnaId,String password,byte[] salt,String contractAddr, String newAdminDnaID,int key,Account payerAcct,long gaslimit,long gasprice) | 合约管理员转让合约管理权限 + 2 | String assignFuncsToRole(String adminDnaID,String password,byte[] salt,String contractAddr,String role,String[] funcName,int key,Account payerAcct, long gaslimit,long gasprice) | 为角色分配函数 + 3 | String assignDnaIDsToRole(String adminDnaId,String password,byte[] salt,String contractAddr,String role,String[] dnaIDs, int key,Account payerAcct, long gaslimit,long gasprice) | 绑定角色到实体身份 + 4 | String delegate(String dnaid,String password,byte[] salt,String contractAddr,String toDnaId,String role,int period,int level,int key,Account payerAcct, long gaslimit,long gasprice)| 将合约调用权代理给其他人 + 5 | String withdraw(String initiatorDnaid,String password,byte[] salt,String contractAddr,String delegate, String role,int key,Account payerAcct, long gaslimit,long gasprice) | 收回合约调用权 + ``` + + * 构造交易接口: +``` + | Function | Description + ----|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------ + 1 | Transaction makeTransfer(String adminDnaID,String contractAddr, String newAdminDnaID,int key,String payer,long gaslimit,long gasprice) | 合约管理员转让合约管理权限 + 2 | Transaction makeAssignFuncsToRole(String adminDnaID,String contractAddr,String role,String[] funcName,int key,String payer,long gaslimit,long gasprice) | 为角色分配函数 + 3 | Transaction makeAssignDnaIDsToRole(String adminDnaId,String contractAddr,String role,String[] dnaIDs, int key,String payer,long gaslimit,long gasprice) | 绑定角色到实体身份 + 4 | Transaction makeDelegate(String dnaid,String contractAddr,String toAddr,String role,int period,int level,int key,String payer,long gaslimit,long gasprice)| 将合约调用权代理给其他人 + 5 | Transaction makeWithDraw(String dnaid,String contractAddr,String delegate, String role,int key,String payer,long gaslimit,long gasprice) | 收回合约调用权 + ``` + +#### 治理合约 + + | Function | Description + -----|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ + 1 | String registerCandidate(Account account, String peerPubkey, long initPos, String dnaid,String dnaidpwd,byte[] salt, long keyNo, Account payerAcct, long gaslimit, long gasprice) | 抵押一定的ONT,消耗一定的额外ONG,申请成为候选节点 + 2 | String unRegisterCandidate(Account account, String peerPubkey,Account payerAcct, long gaslimit, long gasprice) | 取消申请成为候选节点,解冻抵押的ONT + 3 | String withdrawGas(Account account,Account payerAcct,long gaslimit,long gasprice) | 提取解绑ong + 4 | String getPeerInfo(String peerPubkey) | 查询节点信息 + 5 | String getPeerInfoAll() | 查询所有节点 + 6 | String getAuthorizeInfo(String peerPubkey,Address addr) | 查询某个地址对某个节点的授权信息 + 7 | String withdraw(Account account,String peerPubkey[],long[] withdrawList,Account payerAcct,long gaslimit,long gasprice) | 取出处于未冻结状态的抵押ONT + 8 | String quitNode(Account account,String peerPubkey,Account payerAcct,long gaslimit,long gasprice) | 退出节点 + 9 | String addInitPos(Account account,String peerPubkey,int pos,Account payerAcct,long gaslimit,long gasprice) | 节点增加initPos接口,只能由节点所有者调用 + 10| String reduceInitPos(Account account,String peerPubkey,int pos,Account payerAcct,long gaslimit,long gasprice) | 节点减少initPos接口,只能由节点所有者调用,initPos不能低于承诺值,不能低于已接受授权数量的1/10 + 11| String setPeerCost(Account account,String peerPubkey,int peerCost,Account payerAcct,long gaslimit,long gasprice) | 节点设置自己独占激励的比例 + 12| String changeMaxAuthorization(Account account,String peerPubkey,int maxAuthorize,Account payerAcct,long gaslimit,long gasprice) | 节点修改自己接受的最大授权ONT数量 + 13| String getPeerAttributes(String peerPubkey) | 查询节点属性信息 + 14| String getSplitFeeAddress(String address) | 查询某地址得到的激励 + + +### 签名验签 + +``` + +com.github.DNAProject.account.Account acct = new com.github.DNAProject.account.Account(dnaSdk.defaultSignScheme); +byte[] data = "12345".getBytes(); +DataSignature sign = new DataSignature(dnaSdk.defaultSignScheme, acct, data); +byte[] signature = sign.signature(); + + +com.github.DNAProject.account.Account acct2 = new com.github.DNAProject.account.Account(false,acct.serializePublicKey()); +DataSignature sign2 = new DataSignature(); +System.out.println(sign2.verifySignature(acct2, data, signature)); + +``` \ No newline at end of file diff --git a/docs/sdk_get_start.md b/docs/sdk_get_start.md new file mode 100644 index 0000000..a3c27be --- /dev/null +++ b/docs/sdk_get_start.md @@ -0,0 +1,737 @@ +

Java sdk 使用说明

+ +

Version 1.0.0

+ +[English](../en/sdk_get_start.md) / 中文 + +ONT中有两种资产:原生资产和合约资产。原生资产如ont和ong。交易所对接时,主要处理这两种类型资产的充值、提现等操作。 + +sdk文档:[sdk文档](https://github.com/DNAProject/DNASDKJava/tree/master/docs/) + +本文大纲如下: +* [Java sdk 使用说明](#java-sdk-使用说明) + * [1. 公私钥和地址](#1-公私钥和地址) + * [1.1 公私钥存储](#11-公私钥存储) + * [1.1.1 自己存储:](#111-自己存储) + * [随机创建账号:](#随机创建账号) + * [根据私钥创建账号](#根据私钥创建账号) + * [1.1.2 按钱包规范存储:](#112-按钱包规范存储) + * [1.2 地址](#12-地址) + * [2. 原生资产转账](#2-原生资产转账) + * [2.1 初始化](#21-初始化) + * [2.2 查询](#22-查询) + * [ 查询ont,ong余额](#查询ontong余额) + * [ 查询交易是否在交易池中](#查询交易是否在交易池中) + * [ 查询交易是否调用成功](#查询交易是否调用成功) + * [ 同步查询智能合约event](#同步查询智能合约event) + * [其他与链交互接口列表:](#其他与链交互接口列表) + * [2.3 交易反序](#23-交易反序) + * [2.4 GAS转账](#24-GAS转账) + * [ 构造转账交易并发送](#构造转账交易并发送) + * [ 多次签名](#多次签名) + * [ 一转多或多转多](#一转多或多转多) + * [使用签名机签名](#使用签名机签名) + * [2.5 GAS转账](#25-GAS转账) + * [ GAS转账](#GAS转账) + * [ 提取GAS](#提取GAS) + * [3. OEP4转账](#3-OEP4转账) + * [3.1 查询](#31-查询) + * [3.2 转账](#32-转账) + * [4. 批量交易](#4-批量交易) + * [4.1 批量构造交易](#41-批量构造交易) + * [4.2 批量发送交易](#42-批量发送交易) + * [4.3 在钱包中创建Dnaid](#43-在钱包中创建Dnaid) +## 1. 公私钥和地址 + +账户是基于公私钥创建的,地址是公钥转换而来。 + +### 1.1 **公私钥存储** + +公私钥存储可以存储在数据库中,也可以根据钱包规范存储在文件中。 + +#### 1.1.1 自己存储: + +自己存储,是指账户信息保存在用户数据库或其他地方,而不存储在遵循钱包规范的文件中。 +##### 随机创建账号: +```java +com.github.DNAProject.account.Account acct = new com.github.DNAProject.account.Account(dnaSdk.defaultSignScheme); +acct.serializePrivateKey();//私钥 +acct.serializePublicKey();//公钥 +acct.getAddressU160().toBase58();//base58地址 +``` +##### 根据私钥创建账号 +```java +com.github.DNAProject.account.Account acct0 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey0), dnaSdk.defaultSignScheme); +com.github.DNAProject.account.Account acct1 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey1), dnaSdk.defaultSignScheme); +com.github.DNAProject.account.Account acct2 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey2), dnaSdk.defaultSignScheme); + +``` + +#### 1.1.2 按钱包规范存储: + +账户和身份信息保持在遵循钱包规范的文件中。[例子](https://github.com/DNAProject/DNASDKJava/blob/master/src/main/java/example/wallet/WalletDemo.java) + + + + +#### 在钱包中批量创建账号: + +一个创建多个账号的方法。 +```java +dnaSdk.getWalletMgr().createAccounts(10, "passwordtest"); +dnaSdk.getWalletMgr().writeWallet(); + +随机创建: +AccountInfo info0 = dnaSdk.getWalletMgr().createAccountInfo("passwordtest"); + +通过私钥创建: +AccountInfo info = dnaSdk.getWalletMgr().createAccountInfoFromPriKey("passwordtest","e467a2a9c9f56b012c71cf2270df42843a9d7ff181934068b4a62bcdd570e8be"); + +获取账号 +com.github.DNAProject.account.Account acct0 = dnaSdk.getWalletMgr().getAccount(info.addressBase58,"passwordtest",salt); + +``` + + + + +### 1.2 **地址** + + +包括单签地址和多签地址,生成方式与NEO地址相同。 + +签地址是由一个公钥转换而来,多签地址是由多个公钥转换而来。 + +```java +单签地址生成: +String privatekey0 = "c19f16785b8f3543bbaf5e1dbb5d398dfa6c85aaad54fc9d71203ce83e505c07"; +String privatekey1 = "49855b16636e70f100cc5f4f42bc20a6535d7414fb8845e7310f8dd065a97221"; +String privatekey2 = "1094e90dd7c4fdfd849c14798d725ac351ae0d924b29a279a9ffa77d5737bd96"; + +//生成账号,获取地址 +com.github.DNAProject.account.Account acct0 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey0), dnaSdk.defaultSignScheme); +Address sender = acct0.getAddressU160(); + +//base58地址解码 +sender = Address.decodeBase58("AVcv8YBABi9m6vH7faq3t8jWNamDXYytU2"); + +多签地址生成: +Address recvAddr = Address.addressFromMultiPubKeys(2, acct1.serializePublicKey(), acct2.serializePublicKey()); + + +``` + + +| 方法名 | 参数 | 参数描述 | +| :--- | :--- | :--- | +| addressFromMultiPubkeys | int m,byte\[\]... pubkeys | 最小验签个数(<=公钥个数),公钥 | + +## 2. 原生资产转账 + +参考例子:[例子](https://github.com/DNAProject/DNASDKJava/blob/master/src/main/java/example/transaction/MakeTxWithoutWalletDemo.java) + + +### 2.1 初始化 + +转账之前需要创建SDK实例,配置节点IP。 + +```java + +String ip = "http://polaris1.ont.io"; +String rpcUrl = ip + ":" + "20336"; +DnaSdk dnaSdk = DnaSdk.getInstance(); +dnaSdk.setRpc(rpcUrl); +dnaSdk.setDefaultConnect(wm.getRpc()); + +或使用restful: +String restUrl = ip + ":" + "20334"; +dnaSdk.setRestful(restUrl); +dnaSdk.setDefaultConnect(wm.getRestful()); + +也可以选择websocket: +String wsUrl = ip + ":" + "20335"; +dnaSdk.setWesocket(wsUrl, lock); +dnaSdk.setDefaultConnect(wm.getWebSocket()); + +``` + + +### 2.2 查询 + +当发完交易之后可能需要查询交易是否已经落账,还可能需要查询账户余额。 + +#### **查询gas余额** + +```java +dnaSdk.getConnect().getBalance("AVcv8YBABi9m6vH7faq3t8jWNamDXYytU2"); +dnaSdk.nativevm().gas().queryBalanceOf("AVcv8YBABi9m6vH7faq3t8jWNamDXYytU2") + +查gas信息: +System.out.println(dnaSdk.nativevm().gas().queryName()); +System.out.println(dnaSdk.nativevm().gas().querySymbol()); +System.out.println(dnaSdk.nativevm().gas().queryDecimals()); +System.out.println(dnaSdk.nativevm().gas().queryTotalSupply()); + + + +``` + +#### **查询交易是否在交易池中** + +通过接口查询交易是否在交易池中 +```json + +dnaSdk.getConnect().getMemPoolTxState("d441a967315989116bf0afad498e4016f542c1e7f8605da943f07633996c24cc") + + +response 交易池存在此交易: + +{ + "Action": "getmempooltxstate", + "Desc": "SUCCESS", + "Error": 0, + "Result": { + "State":[ + { + "Type":1, + "Height":744, + "ErrCode":0 + }, + { + "Type":0, + "Height":0, + "ErrCode":0 + } + ] + }, + "Version": "1.0.0" +} + +或 交易池不存在此交易 + +{ + "Action": "getmempooltxstate", + "Desc": "UNKNOWN TRANSACTION", + "Error": 44001, + "Result": "", + "Version": "1.0.0" +} + +``` + + +#### **查询交易是否调用成功** + +查询智能合约推送内容,代表交易执行成功,如果没有成功```States```中不会有```transfer```的事件。 + +```json +dnaSdk.getConnect().getSmartCodeEvent("d441a967315989116bf0afad498e4016f542c1e7f8605da943f07633996c24cc") + + +response: +{ + "Action": "getsmartcodeeventbyhash", + "Desc": "SUCCESS", + "Error": 0, + "Result": { + "TxHash": "20046da68ef6a91f6959caa798a5ac7660cc80cf4098921bc63604d93208a8ac", + "State": 1, + "GasConsumed": 0, + "Notify": [ + { + "ContractAddress": "ff00000000000000000000000000000000000001", + "States": [ + "transfer", + "T9yD14Nj9j7xAB4dbGeiX9h8unkKHxuWwb", + "TA4WVfUB1ipHL8s3PRSYgeV1HhAU3KcKTq", + 1000000000 + ] + } + ] + }, + "Version": "1.0.0" +} + +``` + +根据块高查询智能合约事件,返回有事件的交易hash + + +```json + +dnaSdk.getConnect().getSmartCodeEvent(10) + +response: +{ + "Action": "getsmartcodeeventbyheight", + "Desc": "SUCCESS", + "Error": 0, + "Result": [{ + "GasConsumed": 0, + "Notify": [{ + "States": ["transfer", "AFmseVrdL9f9oyCzZefL9tG6UbvhPbdYzM", "APrfMuKrAQB5sSb5GF8tx96ickZQJjCvwG", 1000000000], + "ContractAddress": "0100000000000000000000000000000000000000" + }], + "TxHash": "b8a4f77e19fcae04faa576fbc71fa5a9775166d4485ce13f1ba5ff30ce264c52", + "State": 1 + }, { + "GasConsumed": 0, + "Notify": [{ + "States": ["transfer", "AFmseVrdL9f9oyCzZefL9tG6UbvhPbdYzM", "AFmseVrdL9f9oyCzZefL9tG6UbvhUMqNMV", 1000000000000000000], + "ContractAddress": "0200000000000000000000000000000000000000" + }], + "TxHash": "7e8c19fdd4f9ba67f95659833e336eac37116f74ea8bf7be4541ada05b13503e", + "State": 1 + }, { + "GasConsumed": 0, + "Notify": [], + "TxHash": "80617b4a97eb4266e5e38886f234f324d57587362b5039a01c45cf413461f53b", + "State": 1 + }, { + "GasConsumed": 0, + "Notify": [], + "TxHash": "ede7ecc6e4e7e699b8ba1f07f2e5f8af3b65e70f126d82f7765d20a506080d2d", + "State": 0 +}], + "Version": "1.0.0" +} + +``` + +#### **同步查询智能合约event** + +发完交易后,直到查到交易才返回。 + +```json +//发完交易每隔3秒请求一次,最长等待60秒 + +Object object = dnaSdk.getConnect().waitResult(tx.hash().toString()); +System.out.println(object); + +response success: +{ + "GasConsumed": 0, + "Notify": [], + "TxHash": "cb9e0d4a7a4aea0518bb39409613b8ef76798df3962feb8f8040e05329674890", + "State": 1 +} + +response fail,reject by txpool: +com.github.DNAProject.sdk.exception.SDKException: {"Action":"getmempooltxstate","Desc":"UNKNOWN TRANSACTION","Error":44001,"Result":"","Version":"1.0.0"} + +``` + +#### 其他与链交互接口列表: + +与链交互还有如下接口。 +``` + + | Main Function | Description + -----|----------------------------------------------------------|--------------------------------------------- + 1 | dnaSdk.getConnect().getNodeCount() | 查询节点数量 + 2 | dnaSdk.getConnect().getBlock(15) | 查询块 + 3 | dnaSdk.getConnect().getBlockJson(15) | 查询块 + 4 | dnaSdk.getConnect().getBlockJson("txhash") | 查询块 + 5 | dnaSdk.getConnect().getBlock("txhash") | 查询块 + 6 | dnaSdk.getConnect().getBlockHeight() | 查询当前块高 + 7 | dnaSdk.getConnect().getTransaction("txhash") | 查询交易 + 8 | dnaSdk.getConnect().getStorage("contractaddress", key) | 查询智能合约存储 + 9 | dnaSdk.getConnect().getBalance("address") | 查询余额 + 10 | dnaSdk.getConnect().getContractJson("contractaddress") | 查询智能合约 + 11 | dnaSdk.getConnect().getSmartCodeEvent(59) | 查询智能合约事件 + 12 | dnaSdk.getConnect().getSmartCodeEvent("txhash") | 查询智能合约事件 + 13 | dnaSdk.getConnect().getBlockHeightByTxHash("txhash") | 查询交易所在高度 + 14 | dnaSdk.getConnect().getMerkleProof("txhash") | 获取merkle证明 + 15 | dnaSdk.getConnect().sendRawTransaction("txhexString") | 发送交易 + 16 | dnaSdk.getConnect().sendRawTransaction(Transaction) | 发送交易 + 17 | dnaSdk.getConnect().sendRawTransactionPreExec() | 发送预执行交易 + 18 | dnaSdk.getConnect().getAllowance("gas","from","to") | 查询允许使用值 + 19 | dnaSdk.getConnect().getMemPoolTxCount() | 查询交易池中交易总量 + 20 | dnaSdk.getConnect().getMemPoolTxState() | 查询交易池中交易状态 +``` + +### 2.3 交易反序 + +获取json格式的交易数据 + +```json +http://127.0.0.1:20334/api/v1/transaction/8f4ab5db768e41e56643eee10ad9749be0afa54a891bcd8e5c45543a8dd0cf7d?raw=0 + +{ + "Action": "gettransaction", + "Desc": "SUCCESS", + "Error": 0, + "Result": { + "Version": 0, + "Nonce": 391455426, + "GasPrice": 500, + "GasLimit": 20000, + "Payer": "ASyx6be9APCR6BzcM81615FgBU26gqr1JL", + "TxType": 209, + "Payload": { + "Code": "00c66b147af216ff3da82b999b26f5efe165de5f944ac5496a7cc814d2c124dd088190f709b684e0bc676d70c41b37766a7cc80800ca9a3b000000006a7cc86c51c1087472616e736665721400000000000000000000000000000000000000010068164f6e746f6c6f67792e4e61746976652e496e766f6b65" + }, + "Attributes": [], + "Sigs": [ + { + "PubKeys": [ + "0369d1e9a5a1d83fa1798bbd162e8d8d8ef8e4e1a0e03aa2753b472943e235e219" + ], + "M": 1, + "SigData": [ + "017b80d5f0826b52b2037ee564be55f0ada1d0cb714a80967deb2d04b49a59f6c4358c57d06ee8f7666aec3fc570c5251c30be1cd134acb791775de9e11cacd22c" + ] + } + ], + "Hash": "8f4ab5db768e41e56643eee10ad9749be0afa54a891bcd8e5c45543a8dd0cf7d", + "Height": 95796 + }, + "Version": "1.0.0" +} + +``` + +获取hex格式的交易数据 +```json +http://127.0.0.1:20334/api/v1/transaction/8f4ab5db768e41e56643eee10ad9749be0afa54a891bcd8e5c45543a8dd0cf7d?raw=1 + + +{ + "Action": "gettransaction", + "Desc": "SUCCESS", + "Error": 0, + "Result": "00d1c2225517f401000000000000204e0000000000007af216ff3da82b999b26f5efe165de5f944ac5497900c66b147af216ff3da82b999b26f5efe165de5f944ac5496a7cc814d2c124dd088190f709b684e0bc676d70c41b37766a7cc80800ca9a3b000000006a7cc86c51c1087472616e736665721400000000000000000000000000000000000000010068164f6e746f6c6f67792e4e61746976652e496e766f6b6500014241017b80d5f0826b52b2037ee564be55f0ada1d0cb714a80967deb2d04b49a59f6c4358c57d06ee8f7666aec3fc570c5251c30be1cd134acb791775de9e11cacd22c23210369d1e9a5a1d83fa1798bbd162e8d8d8ef8e4e1a0e03aa2753b472943e235e219ac", + "Version": "1.0.0" +} + +``` + +要理解交易中的数据内容,需要反序列化交易数据,才能推断出是什么类型的交易和具体信息。 +``` +//版本号 交易类型 随机数 gasprice gaslimit 网络费付款人 交易数据 +(version(1) type(1) nonce(4) gasprice(8) gaslimit(8))22 bytes + (payer)21 bytes + payload code bytes( any bytes) + +claim gas +// claim address contract address to address amount "transferFrom" gas SYSCALL "*.Native.Invoke" +//00 c66b 14bb2d5b718efeac060ac825338ca440216da4d8dc 6a7cc8 140000000000000000000000000000000000000001 6a7cc8 14bb2d5b718efeac060ac825338ca440216da4d8dc 6a7cc8 08 806a735501000000 6a7cc8 6c 0c7472616e7366657246726f6d 140000000000000000000000000000000000000002 0068 164f6e746f6c6f67792e4e61746976652e496e766f6b65 +gas transfer +// from to amount "transfer" gas SYSCALL "*.Native.Invoke" +//00 c66b 147af216ff3da82b999b26f5efe165de5f944ac549 6a7cc8 14d2c124dd088190f709b684e0bc676d70c41b3776 6a7cc8 08 00ca9a3b00000000 6a7cc8 6c 51c1 087472616e73666572 140000000000000000000000000000000000000001 0068 164f6e746f6c6f67792e4e61746976652e496e766f6b65 + +For amount : 1-16 is 0x51-0x60 . >=16 is long, 08 is the total amount bytes . +Example: 1000 is 0xe803000000000000 -> 0x00000000000003e8 change from little endian to big endian if print. + +``` + +### 2.4 GAS转账 + +GAS转账可以一对一,也可以一对多,多对多,多对一。 + +#### **构造转账交易并发送** + +```java +转出方与收款方地址: +Address sender = acct0.getAddressU160(); +Address recvAddr = acct1; +//多签地址生成 +//Address recvAddr = Address.addressFromMultiPubKeys(2, acct1.serializePublicKey(), acct2.serializePublicKey()); + +构造转账交易: +long amount = 1000; +Transaction tx = dnaSdk.nativevm().gas().makeTransfer(sender.toBase58(),recvAddr.toBase58(), amount,sender.toBase58(),30000,0); +String hash = tx.hash().toString() + +对交易做签名: +dnaSdk.signTx(tx, new com.github.DNAProject.account.Account[][]{{acct0}}); +//多签地址的签名方法: +dnaSdk.signTx(tx, new com.github.DNAProject.account.Account[][]{{acct1, acct2}}); +//如果转出方与网络费付款人不是同一个地址,需要添加网络费付款人的签名 + + +发送预执行(可选): +Object obj = dnaSdk.getConnect().sendRawTransactionPreExec(tx.toHexString()); +System.out.println(obj); +成功返回: +{"State":1,"Gas":30000,"Result":"01"} +余额不足返回异常: +com.github.DNAProject.network.exception.RestfulException: {"Action":"sendrawtransaction","Desc":"SMARTCODE EXEC ERROR","Error":47001,"Result":"","Version":"1.0.0"} + + +发送交易: +dnaSdk.getConnect().sendRawTransaction(tx.toHexString()); + + +同步发送交易: +Object obj = dnaSdk.getConnect().syncSendRawTransaction(tx.toHexString()); + +response success: +{ + "GasConsumed": 0, + "Notify": [], + "TxHash": "cb9e0d4a7a4aea0518bb39409613b8ef76798df3962feb8f8040e05329674890", + "State": 1 +} + +response fail,reject by txpool: +com.github.DNAProject.sdk.exception.SDKException: {"Action":"getmempooltxstate","Desc":"UNKNOWN TRANSACTION","Error":44001,"Result":"","Version":"1.0.0"} + +``` + + + +| 方法名 | 参数 | 参数描述 | +| :--- | :--- | :--- | +| makeTransfer | String sender,String recvAddr,long amount,String payer,long gaslimit,long gasprice | 发送方地址,接收方地址,金额,网络费付款人地址,gaslimit,gasprice | +| makeTransfer | State\[\] states,String payer,long gaslimit,long gasprice | 一笔交易包含多个转账。 | + + +#### **多次签名** + +如果转出方与网络费付款人不是同一个地址,需要添加网络费付款人的签名 + +```java + +1.添加单签签名 +dnaSdk.addSign(tx,acct0); + +2.添加多签签名 +dnaSdk.addMultiSign(tx,2,new byte[][]{acct.serializePublicKey(),acct2.serializePublicKey()},acct); +dnaSdk.addMultiSign(tx,2,new byte[][]{acct.serializePublicKey(),acct2.serializePublicKey()},acct2); + +3.多签签名分多次签 +acct0签名: +dnaSdk.addMultiSign(tx,2,new byte[][]{acct.serializePublicKey(),acct2.serializePublicKey()},acct); + +acct1签名: +dnaSdk.addMultiSign(tx,2,new byte[][]{acct.serializePublicKey(),acct2.serializePublicKey()},acct2); + +``` + + + +#### **一转多或多转多** + +1. 构造多个state的交易 +2. 签名 +3. 一笔交易上限为1024笔转账 + + +```java + +Address sender1 = acct0.getAddressU160(); +Address sender2 = Address.addressFromMultiPubKeys(2, acct1.serializePublicKey(), acct2.serializePublicKey()); +int amount = 10; +int amount2 = 20; + +State state = new State(sender1, recvAddr, amount); +State state2 = new State(sender2, recvAddr, amount2); +Transaction tx = dnaSdk.nativevm().ont().makeTransfer(new State[]{state1,state2},sender1.toBase58(),30000,0); + +//第一个转出方是单签地址,第二个转出方是多签地址: +dnaSdk.signTx(tx, new com.github.DNAProject.account.Account[][]{{acct0}}); +dnaSdk.addMultiSign(tx,2,new byte[][]{acct1.serializePublicKey(),acct2.serializePublicKey()},acct1); +dnaSdk.addMultiSign(tx,2,new byte[][]{acct1.serializePublicKey(),acct2.serializePublicKey()},acct2); +``` + +#### 使用签名机签名 + + **构造交易并签名** + +1. 构造交易,序列化交易,发送交易给签名机 +2. 签名机接收到交易,反序列化,检查交易,添加签名 +3. 发送交易 + +```java + +序列化交易发送给签名机: +Transaction tx = dnaSdk.nativevm().gas().makeTransfer(sender.toBase58(),recvAddr.toBase58(), amount,sender.toBase58(),30000,0); +String txHex = tx.toHexString(); + +接收方反序列化交易并签名: + +Transaction txRx = Transaction.deserializeFrom(Helper.hexToBytes(txHex)); + + +签名: +dnaSdk.addSign(txRx,acct0); +``` + +**SDK与签名机交互**: + +[例子](https://github.com/DNAProject/DNASDKJava/blob/master/src/main/java/example/signature/SignServerDemo.java) + +```java +节点启动时打开签名机服务: +go run SigSvr.go + + +设置签名机URL: +String url = ip + ":" + "20000/cli"; +DnaSdk dnaSdk = DnaSdk.getInstance(); +dnaSdk.setSignServer(url); + + +String txHex = tx.toHexString(); + +请求单签交易: +dnaSdk.getSignServer().sendSigRawTx(txHex); + +请求多签交易: +String[] signs = new String[]{"02039b196d5ed74a4d771ade78752734957346597b31384c3047c1946ce96211c2a7", + "0203428daa06375b8dd40a5fc249f1d8032e578b5ebb5c62368fc6c5206d8798a966"}; +dnaSdk.getSignServer().sendMultiSigRawTx(txHex,2,signs); + +请求构造转账交易并签名: +dnaSdk.getSignServer().sendSigTransferTx("ont","TU5exRFVqjRi5wnMVzNoWKBq9WFncLXEjK","TA5SgQXTeKWyN4GNfWGoXqioEQ4eCDFMqE",10,30000,0); + + +``` + + **对数据做签名** + +SDK提供直接对数据做签名的接口。[例子](https://github.com/DNAProject/DNASDKJava/blob/master/src/main/java/example/signature/SignatureDemo.java) + + +```java +com.github.DNAProject.account.Account acct = new com.github.DNAProject.account.Account(dnaSdk.defaultSignScheme); + +byte[] data = "12345".getBytes(); +byte[] signature = dnaSdk.signatureData(acct, data); + +System.out.println(dnaSdk.verifySignature(acct.serializePublicKey(), data, signature)); + +``` + + + +### 2.5 GAS转账 + +GAS的精度是9。 +#### **GAS转账** + + +```json +dnaSdk.nativevm().gas().makeTransfer(sender.toBase58(),recvAddr.toBase58(), amount,sender.toBase58(),30000,0); +``` + +#### **提取gas** + +1. 查询是否有gas可以提取 +2. 发送提取gas交易 + +```json +查询未提取gas: +String addr = acct0.getAddressU160().toBase58(); +String gas = sdk.nativevm().gas().unboundGas(addr); + +//提取gas +com.github.DNAProject.account.Account account = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey0), dnaSdk.signatureScheme); +String hash = dnaSdk.nativevm().gas().withdrawGas(account,toAddr,64000L,payerAcct,30000,500); + +``` + + + +## 3. OEP4转账 + + +### 3.1 查询 + +``` +dnaSdk.neovm().oep4().setContractAddress("dff96f4a83b9cb0de3d5e05ca3dff7af841dc0f3"); +System.out.println(dnaSdk.neovm().oep4().queryBalanceOf(account.getAddressU160().toBase58())); + +``` +### 3.2 转账 + +``` +dnaSdk.neovm().oep4().setContractAddress("dff96f4a83b9cb0de3d5e05ca3dff7af841dc0f3"); +String txhash = dnaSdk.neovm().oep4().sendTransfer(acct1, acct2.getAddressU160().toBase58(), 1000, acct1, 20000, 500); + +``` + +### 3.3 并发 + +实现步骤如 [例子](https://github.com/DNAProject/DNASDKJava/tree/master/src/main/java/example/oep/Oep4MultiTheadDemo.java) + + + +## 4. 批量交易 + +SDK发送注册Dnaid和转账等交易时,根据钱包中账户和身份信息解密出私钥再做签名,这个过程大概需要1-2秒时间。为了节省发交易时间,可以多线程或多机器事先创建交易,再批量发送。 + +实现步骤如下,[例子](https://github.com/DNAProject/DNASDKJava/tree/master/src/main/java/example/transaction/CreateManyTx.java) + +### 4.1 批量构造交易 + +1. 打开文件 +2. 构造交易,下面以构造注册Dnaid交易为例。 +3. 写入交易 + +> 构造交易时,如果新创建账户,需要用户自己保存账户私钥。 + +``` +//open file, make registry dnaid transaction, save tx to file. +File file = new File(filePath); +if (!file.exists()) { + file.createNewFile(); +} +com.github.DNAProject.account.Account payerAcct = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey1), SignatureScheme.SHA256WITHECDSA); +FileOutputStream fos = new FileOutputStream(file); +for (int i = 0; i < 3; i++) { + com.github.DNAProject.account.Account account = new com.github.DNAProject.account.Account(SignatureScheme.SHA256WITHECDSA); + String dnaid = Common.diddna + account.getAddressU160().toBase58(); + Transaction tx = dnaSdk.nativevm().dnaId().makeRegister(dnaid, Helper.toHexString(account.serializePublicKey()), payerAcct.getAddressU160().toBase58(), 20000, 500); + dnaSdk.addSign(tx, account); + dnaSdk.addSign(tx, payerAcct); + System.out.println("PrivateKey:"+Helper.toHexString(account.serializePrivateKey())+",txhash:"+tx.hash().toString()); + + fos.write(tx.toHexString().getBytes()); + fos.write(",".getBytes()); + fos.write(tx.hash().toString().getBytes()); + fos.write("\n".getBytes()); +} + + +``` +文件中数据格式: + +``` +交易,交易hash +交易,交易hash + +00d1df24a313f401000000000000204e000000000000aa6e06c79f864152ab7f3139074aad822ffea8559800c66b2a6469643a6f6e743a414774577a7933693148453654516e31633265636b78527841516d524662467333686a7cc821036391476eed630fc1cffb1317545d9390f22d68cdc7092095dc1b78e4baeef27c6a7cc86c127265674944576974685075626c69634b65791400000000000000000000000000000000000000030068164f6e746f6c6f67792e4e61746976652e496e766f6b6500024241011928500aa1ac40d908e92c9db7c16be4063dda2cdabe9908206747c6303635578fde0be66032f586596e91c80f490a085e612be28b95da0edb319cb60f774e472321036391476eed630fc1cffb1317545d9390f22d68cdc7092095dc1b78e4baeef27cac424101bb1df17b91cd709ce38b4ec40db10c2dfd5e9ca7219dd5ca1c6200eaf60d8ccf1be9b85b9b22398204c6366ac20e8bb7797f21ebc17e7db540627b99d5a8bb41232102df6f28e327352a44720f2b384e55034c1a7f54ba31785aa3a338f613a5b7cc26ac,b7e2c99f449cb3403619bc5c5887c52f44993180c61c9fae85d5e772ce3d7fda +00d1039e89c7f401000000000000204e000000000000aa6e06c79f864152ab7f3139074aad822ffea8559800c66b2a6469643a6f6e743a416446335547344867515864515a5577714a53756536744a6f534e564237644d32596a7cc82102a1f44af3d81c6cb0aaa5e1d597b891c436b0c724ae446b5d9cb9039e09b9938c6a7cc86c127265674944576974685075626c69634b65791400000000000000000000000000000000000000030068164f6e746f6c6f67792e4e61746976652e496e766f6b65000242410168436b2f5da6db0b2b4260b587ba7bce3dba1597a400dec52d0f00a4aa77f37c9979d10c31a80888edd6a41da4c89596033ab9ee634886f26850b32e83681f4e232102a1f44af3d81c6cb0aaa5e1d597b891c436b0c724ae446b5d9cb9039e09b9938cac4241019ba8633b42d3427ab202cafcb1c50a65de30c65120a96d958f985aff7205fcc6230e64842ea5cdf4e6b2d0b8bef1b19c795bf392a0c1cc8a93bc9ec9bebc9a35232102df6f28e327352a44720f2b384e55034c1a7f54ba31785aa3a338f613a5b7cc26ac,a8bd8258c8819f0ecf0652bb1d8c08860a5b75d16e194f3d6cd395f5c2a9f7fe +00d1554170d9f401000000000000204e000000000000aa6e06c79f864152ab7f3139074aad822ffea8559800c66b2a6469643a6f6e743a41547a4d6e79556d42614369686355556872786472566d437173336d73426351685a6a7cc8210274af46f5f038d040e5096f4653df4e7ea5598567effe4542ad6f19cda6ea05846a7cc86c127265674944576974685075626c69634b65791400000000000000000000000000000000000000030068164f6e746f6c6f67792e4e61746976652e496e766f6b650002424101ea9d7dedf17ecfef8d1d03f4d00b819c16fab8275b5d77d811a1db8140d25722fc2200a60ea76e5a449cce4e127ceec73377cce1b227c624b8df9f95be55bf4123210274af46f5f038d040e5096f4653df4e7ea5598567effe4542ad6f19cda6ea0584ac424101e401877fc4892212a309b7de30d5d9dd675a7171f89d945fe44c3b9eba46df2c2966f54fefdf5eabfa651acf63332cf9475868aa3055531a97a1fffbd43b09b8232102df6f28e327352a44720f2b384e55034c1a7f54ba31785aa3a338f613a5b7cc26ac,bd888014a82cec39f72400e4b8c43e46702bd96a16172b144361cb7b3bc024f4 + +``` + +### 4.2 批量发送交易 + +1. 打开文件 +2. 读取一行数据 +3. 提取交易数据,发送交易数据 + +``` +//read transaction from file, send transaction to node +FileReader fr = new FileReader(filePath); +BufferedReader bf = new BufferedReader(fr); +String txHex = null; +while ((txHex=bf.readLine())!=null){ + txHex = txHex.split(",")[0]; + Object obj = dnaSdk.getConnect().sendRawTransactionPreExec(txHex);//change to sendRawTransaction + System.out.println(obj); +} + + +``` + + +### 4.3 在钱包中创建Dnaid + +如果需要把Dnaid保存到钱包,根据4.1中保存的私钥,在钱包中创建Dnaid即可。 + +``` +Identity identity = dnaSdk.getWalletMgr().createIdentityFromPriKey(password,privatekey0); +dnaSdk.getWalletMgr().writeWallet(); +``` \ No newline at end of file diff --git a/docs/smartcontract.md b/docs/smartcontract.md new file mode 100644 index 0000000..a58a0ec --- /dev/null +++ b/docs/smartcontract.md @@ -0,0 +1,398 @@ +

Java sdk 智能合约

+ +

Version 1.0.0

+ + +## 介绍 + +这个章节介绍如何通过Java SDK使用智能合约。 + +## 智能合约部署、调用、事件推送 + +> Note:目前java-sdk支持neo智能合约部署和调用,暂不支持WASM合约,NEO和WASM合约部署操作一样,调用略有不同,见下面详解: + + +### 部署 + +通过[SmartX](https://smartx.ont.io/)编译智能合约,可以在SmartX上直接部署合约,也可以通过java sdk部署合约。 + +```java +InputStream is = new FileInputStream("/Users/sss/dev/test/IdContract/IdContract.avm"); +byte[] bys = new byte[is.available()]; +is.read(bys); +is.close(); +code = Helper.toHexString(bys); +dnaSdk.setCodeAddress(Address.AddressFromVmCode(code).toHexString()); + +//部署合约 +Transaction tx = dnaSdk.vm().makeDeployCodeTransaction(code, true, "name", + "v1.0", "author", "email", "desp", account.getAddressU160().toBase58(),dnaSdk.DEFAULT_DEPLOY_GAS_LIMIT,500); +String txHex = Helper.toHexString(tx.toArray()); +dnaSdk.getConnect().sendRawTransaction(txHex); +//等待出块 +Thread.sleep(6000); +DeployCodeTransaction t = (DeployCodeTransaction) dnaSdk.getConnect().getTransaction(txHex); +``` + +**makeDeployCodeTransaction** + +```java +public DeployCode makeDeployCodeTransaction(String codeStr, boolean needStorage, String name, String codeVersion, String author, String email, String desp,String payer,long gaslimit,long gasprice) + +``` + +| 参数 | 字段 | 类型 | 描述 | 说明 | +| ----- | ------- | ------ | ------------- | ----------- | +| 输入参数 | codeHexStr| String | 合约code十六进制字符串 | 必选 | +| | needStorage | Boolean | 是否需要存储 | 必选 | +| | name | String | 名字 | 必选| +| | codeVersion | String | 版本 | 必选 | +| | author | String | 作者 | 必选 | +| | email | String | emal | 必选 | +| | desp | String | 描述信息 | 必选 | +| | VmType | byte | 虚拟机类型 | 必选 | +| | payer | String | 支付交易费用的账户地址 | 必选 | +| | gaslimit | long | gaslimit | 必选 | +| | gasprice | long | gas价格 | 必选 | +| 输出参数 | tx | Transaction | 交易实例 | | + +### 调用 + +#### NEO智能合约调用 + +* 基本流程: + + 1. 构造调用智能合约调用参数; + 2. 构造交易; + 3. 交易签名(预执行不需要签名); + 4. 发送交易。 + +* 示例 + +```java + +List paramList = new ArrayList<>(); +paramList.add("testHello".getBytes()); + +List args = new ArrayList(); +args.add(true); +args.add(100); +args.add("test".getBytes()); +args.add("test"); +args.add(account.getAddressU160().toArray()); + +paramList.add(args); +byte[] params = BuildParams.createCodeParamsScript(paramList); + +String result = invokeContract(params, account, 20000, 500,true); +System.out.println(result); + +public static String invokeContract(byte[] params, Account payerAcct, long gaslimit, long gasprice, boolean preExec) throws Exception{ + if(payerAcct == null){ + throw new SDKException("params should not be null"); + } + if(gaslimit < 0 || gasprice< 0){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + Transaction tx = dnaSdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress),null,params,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + dnaSdk.addSign(tx, payerAcct); + Object result = null; + if(preExec) { + result = dnaSdk.getConnect().sendRawTransactionPreExec(tx.toHexString()); + }else { + result = dnaSdk.getConnect().sendRawTransaction(tx.toHexString()); + return tx.hash().toString(); + } + return result.toString(); +} +``` + + + +#### WASM智能合约调用-目前不支持WASM + +* 基本流程: + 1. 构造调用合约中的方法需要的参数; + 2. 构造交易; + 3. 交易签名(如果是预执行不需要签名); + 4. 发送交易。 + +* 示例: + +```java +//设置要调用的合约地址codeAddress +dnaSdk.getSmartcodeTx().setCodeAddress(codeAddress); +String funcName = "add"; +//构造合约函数需要的参数 +String params = dnaSdk.vm().buildWasmContractJsonParam(new Object[]{20,30}); +//指定虚拟机类型构造交易 +Transaction tx = dnaSdk.vm().makeInvokeCodeTransaction(dnaSdk.getSmartcodeTx().getCodeAddress(),funcName,params.getBytes(),VmType.WASMVM.value(),payer,gas); +//发送交易 +dnaSdk.getConnect().sendRawTransaction(tx.toHexString()); +``` + +#### 智能合约调用例子 + +合约中的方法 +```c# + +public static bool Transfer(byte[] from, byte[] to, object[] param) +{ + StorageContext context = Storage.CurrentContext; + + if (from.Length != 20 || to.Length != 20) return false; + + for (int i = 0; i < param.Length; i++) + { + + TransferPair transfer = (TransferPair)param[i]; + byte[] hash = GetContractHash(transfer.Key); + if (hash.Length != 20 || transfer.Amount < 0) throw new Exception(); + if (!TransferNEP5(from, to, hash, transfer.Amount)) throw new Exception(); + + } + return true; +} +struct TransferPair +{ + public string Key; + public ulong Amount; +} +``` + +Java-SDK 调用Transfer函数的方法 + +分析:合约中的Transfer方法需要三个参数,前两个参数都是字节数组类型的参数,最后一个参数是对象数组,数组中的每个元素的结构可以通过TransferPair知道各个属性数据类型。 + +```java +String functionName = "Transfer"; +//构造Transfer方法需要的param 数组 +List list = new ArrayList(); +List list2 = new ArrayList(); +list2.add("Atoken"); +list2.add(100); +list.add(list2); +List list3 = new ArrayList(); +list3.add("Btoken"); +list3.add(100); +list.add(list3); +//设置函数需要的参数 +func.setParamsValue(account999.getAddressU160().toArray(),Address.decodeBase58("AacHGsQVbTtbvSWkqZfvdKePLS6K659dgp").toArray(),list); +String txhash = dnaSdk.neovm().sendTransaction(Helper.reverse("44f1f4ee6940b4f162d857411842f2d533892084"),acct,acct,20000,500,func,false); +Thread.sleep(6000); +System.out.println(dnaSdk.getConnect().getSmartCodeEvent(tx.hash().toHexString())); +``` + + + +> 如果需要监控推送结果,可以了解下面章节。 + +### 智能合约事件推送 + +创建websocket线程,解析推送结果。 + + +#### 1. 设置websocket链接 + + +```java +//lock 全局变量,同步锁 +public static Object lock = new Object(); + +//获得ont实例 +String ip = "http://127.0.0.1"; +String wsUrl = ip + ":" + "20335"; +DnaSdk wm = DnaSdk.getInstance(); +wm.setWesocket(wsUrl, lock); +wm.setDefaultConnect(wm.getWebSocket()); +wm.openWalletFile("OntAssetDemo.json"); + +``` + + +#### 2. 启动websocket线程 + + +```java +//false 表示不打印回调函数信息 +dnaSdk.getWebSocket().startWebsocketThread(false); + +``` + + +#### 3. 启动结果处理线程 + + +```java +Thread thread = new Thread( + new Runnable() { + @Override + public void run() { + waitResult(lock); + } + }); + thread.start(); + //将MsgQueue中的数据取出打印 + public static void waitResult(Object lock) { + try { + synchronized (lock) { + while (true) { + lock.wait(); + for (String e : MsgQueue.getResultSet()) { + System.out.println("RECV: " + e); + Result rt = JSON.parseObject(e, Result.class); + //TODO + MsgQueue.removeResult(e); + if (rt.Action.equals("getblockbyheight")) { + Block bb = Serializable.from(Helper.hexToBytes((String) rt.Result), Block.class); + //System.out.println(bb.json()); + } + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } +``` + + +#### 4. 每6秒发送一次心跳程序,维持socket链接 + + +```java +for (;;){ + Map map = new HashMap(); + if(i >0) { + map.put("SubscribeEvent", true); + map.put("SubscribeRawBlock", false); + }else{ + map.put("SubscribeJsonBlock", false); + map.put("SubscribeRawBlock", true); + } + //System.out.println(map); + dnaSdk.getWebSocket().setReqId(i); + dnaSdk.getWebSocket().sendSubscribe(map); + Thread.sleep(6000); + } +``` + + +#### 5. 推送事例详解 + + +以调用存证合约的put函数为例, + +//存证合约abi.json文件部分内容如下 + +```json +{ + "hash":"0x27f5ae9dd51499e7ac4fe6a5cc44526aff909669", + "entrypoint":"Main", + "functions": + [ + + ], + "events": + [ + { + "name":"putRecord", + "parameters": + [ + { + "name":"arg1", + "type":"String" + }, + { + "name":"arg2", + "type":"ByteArray" + }, + { + "name":"arg3", + "type":"ByteArray" + } + ], + "returntype":"Void" + } + ] +} +``` + + +当调用put函数保存数据时,触发putRecord事件,websocket 推送的结果是{"putRecord", "arg1", "arg2", "arg3"}的十六进制字符串 + +例子如下: + +```json +RECV: +{ + "Action": "Log", + "Desc": "SUCCESS", + "Error": 0, + "Result": { + "Message": "Put", + "TxHash": "8cb32f3a1817d88d8562fdc0097a0f9aa75a926625c6644dfc5417273ca7ed71", + "ContractAddress": "80f6bff7645a84298a1a52aa3745f84dba6615cf" + }, + "Version": "1.0.0" +} +RECV: { + "Action": "Notify", + "Desc": "SUCCESS", + "Error": 0, + "Result": [{ + "States": ["7075745265636f7264", "507574", "6b6579", "7b2244617461223a7b22416c6772697468656d223a22534d32222c2248617368223a22222c2254657874223a2276616c75652d7465737431222c225369676e6174757265223a22227d2c2243416b6579223a22222c225365714e6f223a22222c2254696d657374616d70223a307d"], + "TxHash": "8cb32f3a1817d88d8562fdc0097a0f9aa75a926625c6644dfc5417273ca7ed71", + "ContractAddress": "80f6bff7645a84298a1a52aa3745f84dba6615cf" + }], + "Version": "1.0.0" + } +``` + + +## FAQ + + +* contractAddress是什么 + +contractAddress是智能合约的唯一标识。 + +* 如何获得contractAddress ? + +```java +InputStream is = new FileInputStream("IdContract.avm"); +byte[] bys = new byte[is.available()]; +is.read(bys); +is.close(); +code = Helper.toHexString(bys); +System.out.println("Code:" + Helper.toHexString(bys)); +System.out.println("CodeAddress:" + Address.AddressFromVmCode(code).toHexString()); +``` + +> Note: 在获得codeAddress的时候,需要设置该合约需要运行在什么虚拟机上,目前支持的虚拟机是NEO和WASM。 + +* 调用智能合约invokeTransaction的过程,sdk中具体做了什么 + +```java +//step1:构造交易 +//需先将智能合约参数转换成vm可识别的opcode +Transaction tx = dnaSdk.vm().makeInvokeCodeTransaction(ontContractAddr, null, contract.toArray(), VmType.Native.value(), sender.toBase58(),gaslimit,gasprice); + +//step2:对交易签名 +dnaSdk.signTx(tx, info1.address, password); + +//step3:发送交易 +dnaSdk.getConnectMgr().sendRawTransaction(tx.toHexString()); +``` + +* invoke时为什么要传入账号和密码 + +调用智能合约时需要用户签名,如果是预执行不需要签名,钱包中保存的是加密后的用户私钥,需要密码才能解密获取私钥。 + + +* 查询资产操作时,智能合约预执行是怎么回事,如何使用? + +如智能合约get相关操作,从智能合约存储空间里读取数据,无需走节点共识,只在该节点执行即可返回结果。发送交易时调用预执行接口。 +```java +String result = (String) sdk.getConnect().sendRawTransactionPreExec(txHex); +``` diff --git a/pom.xml b/pom.xml index 1ac304c..1380dad 100644 --- a/pom.xml +++ b/pom.xml @@ -1,46 +1,157 @@ - - 4.0.0 - - DNA-SDK - DNA-SDK - 0.0.1-SNAPSHOT - jar - - DNA-SDK - http://maven.apache.org - - - UTF-8 - - - - - - - - - - - - org.bouncycastle - bcprov-jdk15on - 1.54 - - - org.xerial - sqlite-jdbc - 3.14.2 - - - - - - - - com.alibaba - fastjson - 1.2.9 - - - + + + 4.0.0 + + com.github.DNAProject + DNASDKJava + 2.0.0 + + + UTF-8 + 1.8 + 1.8 + 4.12 + + + + org.sonatype.oss + oss-parent + 7 + + + + + DNASDKJava-snapshots + https://oss.sonatype.org/content/repositories/snapshots + + + DNASDKJava-release + https://oss.sonatype.org/service/local/staging/deploy/maven2 + + + + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + repo + + + + master + https://github.com/DNAProject/DNASDKJava + scm:git:git@github.com:DNAProject/DNASDKJava.git + scm:git:git@github.com:DNAProject/DNASDKJava.git + + + + hellomyworld + messixaviinsta0303@163.com + DNAProject + + + + + + jcenter + https://jcenter.bintray.com/ + + + + + + org.apache.httpcomponents + httpclient + 4.5.5 + + + io.github.novacrypto + BIP39 + 0.1.9 + + + + io.github.novacrypto + Base58 + 0.1.2 + + + + com.squareup.okhttp3 + okhttp + 3.6.0 + + + + org.bouncycastle + bcprov-jdk15on + 1.59 + + + + com.alibaba + fastjson + 1.2.51 + + + + junit + junit + 4.12 + test + + + + org.fusesource.leveldbjni + leveldbjni-all + 1.8 + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12.2 + + + **/ConnectMgrTest.java + **/GasAssetTxTest.java + **/MerkleVerifierTest.java + **/NativeDnaIdTxTest.java + **/GasTest.java + **/NeoVmTest.java + **/AuthTest.java + **/WasmVmTest.java + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.0.1 + + + attach-sources + verify + + jar-no-fork + + + + + + + \ No newline at end of file diff --git a/src/main/java/DNA/Core/AssetType.java b/src/main/java/DNA/Core/AssetType.java deleted file mode 100644 index f96ba85..0000000 --- a/src/main/java/DNA/Core/AssetType.java +++ /dev/null @@ -1,46 +0,0 @@ -package DNA.Core; - -/** - * 资产类别 - */ -public enum AssetType { - - /** - * 法币 - */ - Currency(0x00), - - /** - * 股权 - */ - Share(0x01), - - /** - * 电子发票 - */ - Invoice(0x10), - - /** - * 代币 - */ - Token(0x11), - ; - - private byte value; - AssetType(int v) { - value = (byte)v; - } - - public byte value() { - return value; - } - - public static AssetType valueOf(byte v) { - for (AssetType tt : AssetType.values()) { - if(tt.value() == v) { - return tt; - } - } - throw new IllegalArgumentException(); - } -} diff --git a/src/main/java/DNA/Core/Block.java b/src/main/java/DNA/Core/Block.java deleted file mode 100644 index 4776bed..0000000 --- a/src/main/java/DNA/Core/Block.java +++ /dev/null @@ -1,292 +0,0 @@ -package DNA.Core; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.Arrays; -import java.util.function.Function; - -import DNA.UInt160; -import DNA.UInt256; -import DNA.Core.Scripts.Program; -import DNA.Cryptography.MerkleTree; -import DNA.IO.BinaryReader; -import DNA.IO.BinaryWriter; -import DNA.IO.Serializable; -import DNA.IO.Json.JArray; -import DNA.IO.Json.JNumber; -import DNA.IO.Json.JObject; -import DNA.IO.Json.JString; -import DNA.Network.Inventory; -import DNA.Network.InventoryType; - -/** - * 区块或区块头 - */ -public class Block extends Inventory { - /** - * 区块版本 - */ - public int version; - /** - * 前一个区块的散列值 - */ - public UInt256 prevBlock; - /** - * 该区块中所有交易的Merkle树的根 - */ - public UInt256 merkleRoot; - /** - * 时间戳 - */ - public int timestamp; - /** - * 区块高度 - */ - public int height; - /** - * 随机数 - */ - public long nonce; - /** - * 下一个区块的记账合约的散列值 - */ - public UInt160 nextMiner; - /** - * 用于验证该区块的脚本 - */ - public Program script; - /** - * 交易列表,当列表中交易的数量为0时,该Block对象表示一个区块头 - */ - public Transaction[] transactions; - - /** - * 该区块的区块头 - */ - //[NonSerialized] - private Block _header = null; - public Block header() { - if (isHeader()) return this; - if (_header == null) { - _header = new Block(); - _header.prevBlock = prevBlock; - _header.merkleRoot = this.merkleRoot; - _header.timestamp = this.timestamp; - _header.height = this.height; - _header.nonce = this.nonce; - _header.nextMiner = this.nextMiner; - _header.script = this.script; - _header.transactions = new Transaction[0]; - } - return _header; - } - - /** - * 资产清单的类型 - */ - @Override - public InventoryType inventoryType() { return InventoryType.Block; } - - /** - * 是否为区块头 - */ - public boolean isHeader() { return transactions.length == 0; } - - /** - * 反序列化 - * 数据来源 - * @throws IOException - * @throws IllegalAccessException - * @throws InstantiationException - */ - @Override - public void deserialize(BinaryReader reader) throws IOException { - // 未签名 - deserializeUnsigned(reader); - // 填充值 - if (reader.readByte() != 1) - throw new IOException(); - // 脚本 - try { - script = reader.readSerializable(Program.class); - } catch (InstantiationException | IllegalAccessException ex) { - throw new IOException(ex); - } - // 交易 -// transactions = new Transaction[(int) reader.readVarInt(0x10000000)];//xy - transactions = new Transaction[(int) reader.readInt()]; //dna - for (int i = 0; i < transactions.length; i++) { - transactions[i] = Transaction.deserializeFrom(reader); - } - if (transactions.length > 0) { - if (transactions[0].type != TransactionType.BookKeeping - || Arrays.stream(transactions).skip(1).anyMatch(p -> p.type == TransactionType.BookKeeping)) { - throw new IOException(); - } - } - } - - @Override - public void deserializeUnsigned(BinaryReader reader) throws IOException { - try { - version = reader.readInt(); - prevBlock = reader.readSerializable(UInt256.class); - merkleRoot = reader.readSerializable(UInt256.class); - timestamp = reader.readInt(); - height = reader.readInt(); - nonce = Long.valueOf(reader.readLong()); - nextMiner = reader.readSerializable(UInt160.class); - transactions = new Transaction[0]; - } catch (InstantiationException | IllegalAccessException ex) { - throw new IOException(ex); - } - } - - @Override - public void serialize(BinaryWriter writer) throws IOException { - serializeUnsigned(writer); - writer.writeByte((byte)1); - writer.writeSerializable(script); - writer.writeSerializableArray2(transactions); - } - - @Override - public void serializeUnsigned(BinaryWriter writer) throws IOException { - writer.writeInt(version); - writer.writeSerializable(prevBlock); - writer.writeSerializable(merkleRoot); - writer.writeInt(timestamp); - writer.writeInt(height); - writer.writeLong(nonce); - writer.writeSerializable(nextMiner); - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof Block)) { - return false; - } - return this.hash().equals(((Block) obj).hash()); - } - - @Override - public int hashCode() { - return hash().hashCode(); - } - - /** - * 反序列化Block(static) - */ - public static Block fromTrimmedData(byte[] data, int index) throws IOException { - return fromTrimmedData(data, index, null); - } - - public static Block fromTrimmedData(byte[] data, int index, Function txSelector) throws IOException { - Block block = new Block(); - try (ByteArrayInputStream ms = new ByteArrayInputStream(data, index, data.length - index)) { - try (BinaryReader reader = new BinaryReader(ms)) { - // 未签名的 - block.deserializeUnsigned(reader); - // 填充值 - reader.readByte(); - // 脚本 - block.script = reader.readSerializable(Program.class); - // 交易 - if (txSelector == null) { - block.transactions = new Transaction[0]; - } else { - block.transactions = new Transaction[(int)reader.readVarInt(0x10000000)]; - for (int i = 0; i < block.transactions.length; i++) { - block.transactions[i] = txSelector.apply(reader.readSerializable(UInt256.class)); - } - } - } catch (InstantiationException | IllegalAccessException ex) { - throw new IOException(ex); - } - } - return block; - } - - /** - * 获取验证脚本 - */ - @Override - public UInt160[] getScriptHashesForVerifying() { - if (prevBlock.equals(UInt256.ZERO)) { - return new UInt160[] { Program.toScriptHash(script.parameter) }; - } - Block prev_header; - try { - prev_header = Blockchain.current().getHeader(prevBlock); - } catch (Exception ex) { - throw new IllegalStateException(ex); - } - if (prev_header == null) { - throw new IllegalStateException(); - } - return new UInt160[] { prev_header.nextMiner }; - } - - /** - * 根据区块中所有交易的Hash生成MerkleRoot - */ - public void rebuildMerkleRoot() { - merkleRoot = MerkleTree.computeRoot(Arrays.stream(transactions).map(p -> p.hash()).toArray(UInt256[]::new)); - } - - public JObject json() { - JObject json = new JObject(); - json.set("hash", new JString(hash().toString())); - json.set("version", new JNumber(Integer.toUnsignedLong(version))); - json.set("previousblockhash", new JString(prevBlock.toString())); - json.set("merkleroot", new JString(merkleRoot.toString())); - json.set("time", new JNumber(timestamp)); - json.set("height", new JNumber(Integer.toUnsignedLong(height))); - json.set("nonce", new JNumber(nonce)); -// json.set("nextminer", new JString(Wallet.toAddress(nextMiner))); - json.set("script", script.json()); - json.set("tx", new JArray(Arrays.stream(transactions).map(p -> p.json()).toArray(JObject[]::new))); - return json; - } - - /** - * 把区块对象变为只包含区块头和交易Hash的字节数组,去除交易数据 - * 返回只包含区块头和交易Hash的字节数组 - */ - public byte[] trim() { - try (ByteArrayOutputStream ms = new ByteArrayOutputStream()) { - try (BinaryWriter writer = new BinaryWriter(ms)) { - serializeUnsigned(writer); - writer.writeByte((byte)1); - writer.writeSerializable(script); - writer.writeSerializableArray(Arrays.stream(transactions).map(p -> p.hash()).toArray(Serializable[]::new)); - writer.flush(); - return ms.toByteArray(); - } - } catch (IOException ex) { - throw new UnsupportedOperationException(ex); - } - } - - /** - * 验证该区块头是否合法 - * - */ - @Override public boolean verify() { - return verify(false); - } - - /** - * 验证该区块头是否合法 - * - * @param completely 是否同时验证区块中的每一笔交易 - * @return - */ - public boolean verify(boolean completely) { - return true; - } -} \ No newline at end of file diff --git a/src/main/java/DNA/Core/Blockchain.java b/src/main/java/DNA/Core/Blockchain.java deleted file mode 100644 index c5836c4..0000000 --- a/src/main/java/DNA/Core/Blockchain.java +++ /dev/null @@ -1,310 +0,0 @@ -package DNA.Core; - -import java.time.Duration; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.Map; -import java.util.stream.Stream; - -import org.bouncycastle.math.ec.ECPoint; - -import DNA.Fixed8; -import DNA.Helper; -import DNA.Out; -import DNA.UInt160; -import DNA.UInt256; -import DNA.Core.Scripts.Program; -import DNA.Cryptography.ECC; -import DNA.Wallets.Contract; - -/** - * 实现区块链功能的基类 - */ -public abstract class Blockchain implements AutoCloseable { - /** - * 产生每个区块的时间间隔,已秒为单位 - */ - public static final int SECONDS_PER_BLOCK = 15; - /** - * 小蚁币产量递减的时间间隔,以区块数量为单位 - */ - public static final int DECREMENT_INTERVAL = 2000000; - /** - * 每个区块产生的小蚁币的数量 - */ - public static final int[] MINTING_AMOUNT = { 8, 7, 6, 5, 4, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; - /** - * 产生每个区块的时间间隔 - */ - public static final Duration TIME_PER_BLOCK = Duration.ofSeconds(SECONDS_PER_BLOCK); - /** - * 后备记账人列表 - */ - public static final ECPoint[] STANDBY_MINERS = { - ECC.secp256r1.getCurve().decodePoint(Helper.hexToBytes("0327da12b5c40200e9f65569476bbff2218da4f32548ff43b6387ec1416a231ee8")), - ECC.secp256r1.getCurve().decodePoint(Helper.hexToBytes("026ce35b29147ad09e4afe4ec4a7319095f08198fa8babbe3c56e970b143528d22")), - ECC.secp256r1.getCurve().decodePoint(Helper.hexToBytes("0209e7fd41dfb5c2f8dc72eb30358ac100ea8c72da18847befe06eade68cebfcb9")), - ECC.secp256r1.getCurve().decodePoint(Helper.hexToBytes("039dafd8571a641058ccc832c5e2111ea39b09c0bde36050914384f7a48bce9bf9")), - ECC.secp256r1.getCurve().decodePoint(Helper.hexToBytes("038dddc06ce687677a53d54f096d2591ba2302068cf123c1f2d75c2dddc5425579")), - ECC.secp256r1.getCurve().decodePoint(Helper.hexToBytes("02d02b1873a0863cd042cc717da31cea0d7cf9db32b74d4c72c01b0011503e2e22")), - ECC.secp256r1.getCurve().decodePoint(Helper.hexToBytes("034ff5ceeac41acf22cd5ed2da17a6df4dd8358fcb2bfb1a43208ad0feaab2746b")), - }; - - /** - * 区块链所提供的功能 - */ - public abstract EnumSet ability(); - /** - * 当前最新区块散列值 - * @throws Exception - */ - public abstract UInt256 currentBlockHash() throws Exception; - /** - * 当前最新区块头的散列值 - * @throws Exception - */ - public UInt256 currentHeaderHash() throws Exception{ return currentBlockHash(); } - /** - * 默认的区块链实例 - */ - private static Blockchain _default = null; - public static Blockchain current() { return _default; } - /** - * 区块头高度 - * @throws Exception - */ - public int headerHeight() throws Exception { return height(); } - /** - * 区块高度 - * @throws Exception - */ - public abstract int height() throws Exception; - /** - * 表示当前的区块链实现是否为只读的 - */ - public abstract boolean isReadOnly(); - - /** - * 将指定的区块添加到区块链中 - * 要添加的区块 - * 返回是否添加成功 - */ - protected abstract boolean addBlock(Block block); - - /** - * 将指定的区块头添加到区块头链中 - * 要添加的区块头列表 - */ - protected abstract void addHeaders(Iterable headers); - - @Override - public abstract void close(); - - /** - * 判断区块链中是否包含指定的资产 - * 资产编号 - * 如果包含指定资产则返回true - */ - public boolean containsAsset(UInt256 hash) { return false;} - - /** - * 判断区块链中是否包含指定的区块 - * 区块编号 - * 如果包含指定区块则返回true - */ - public boolean containsBlock(UInt256 hash){ return false;} - - /** - * 判断区块链中是否包含指定的交易 - * 交易编号 - * 如果包含指定交易则返回true - */ - public boolean containsTransaction(UInt256 hash){ return false;} - - public boolean containsUnspent(TransactionInput input) throws Exception { - return containsUnspent(input.prevHash, input.prevIndex); - } - - public abstract boolean containsUnspent(UInt256 hash, int index) throws Exception; - - public abstract Stream getAssets(); - - /** - * 根据指定的高度,返回对应的区块信息 - * 区块高度 - * 返回对应的区块信息 - * @throws Exception - */ - public Block getBlock(int height) throws Exception { - return getBlock(getBlockHash(height)); - } - - /** - * 根据指定的散列值,返回对应的区块信息 - * 散列值 - * 返回对应的区块信息 - * @throws Exception - */ - public abstract Block getBlock(UInt256 hash) throws Exception; - - /** - * 根据指定的高度,返回对应区块的散列值 - * 区块高度 - * 返回对应区块的散列值 - * @throws Exception - */ - public abstract UInt256 getBlockHash(int height); - - /** - * 根据指定的高度,返回对应的区块头信息 - * 区块高度 - * 返回对应的区块头信息 - * @throws Exception - */ - public Block getHeader(int height) throws Exception { - return getHeader(getBlockHash(height)); - } - - /** - * 根据指定的散列值,返回对应的区块头信息 - * 散列值 - * 返回对应的区块头信息 - * @throws Exception - */ - public Block getHeader(UInt256 hash) throws Exception { - Block b = getBlock(hash); - return b == null ? null : b.header(); - } - - public abstract UInt256[] getLeafHeaderHashes(); - - /** - * 获取记账人的合约地址 - * 记账人的公钥列表 - * 返回记账人的合约地址 - */ - public static UInt160 getMinerAddress(ECPoint[] miners) { - return Program.toScriptHash(Contract.createMultiSigRedeemScript(miners.length - (miners.length - 1) / 3, miners)); - } - - private ArrayList _miners = new ArrayList(); - /** - * 获取下一个区块的记账人列表 - * 返回一组公钥,表示下一个区块的记账人列表 - */ - public ECPoint[] getMiners() { - synchronized (_miners) { - if (_miners.size() == 0) { - // ... - } - return _miners.toArray(new ECPoint[_miners.size()]); - } - } - - /** - * 根据指定的散列值,返回下一个区块的信息 - * 散列值 - * 返回下一个区块的信息> - */ - public abstract Block getNextBlock(UInt256 hash); - - /** - * 根据指定的散列值,返回下一个区块的散列值 - * 散列值 - * 返回下一个区块的散列值 - */ - public abstract UInt256 getNextBlockHash(UInt256 hash); - - /** - * 根据指定的资产编号,返回对应资产的发行量 - * 资产编号 - * 返回对应资产的当前已经发行的数量 - */ - public abstract Fixed8 getQuantityIssued(UInt256 asset_id); - - /** - * 根据指定的区块高度,返回对应区块及之前所有区块中包含的系统费用的总量 - * 区块高度 - * 返回对应的系统费用的总量 - * @throws Exception - */ - public long getSysFeeAmount(int height) throws Exception { - return getSysFeeAmount(getBlockHash(height)); - } - - /** - * 根据指定的区块散列值,返回对应区块及之前所有区块中包含的系统费用的总量 - * 散列值 - * 返回系统费用的总量 - */ - public abstract long getSysFeeAmount(UInt256 hash); - - /** - * 根据指定的散列值,返回对应的交易信息 - * 散列值 - * 返回对应的交易信息 - * @throws Exception - */ - public Transaction getTransaction(UInt256 hash) throws Exception { - Out height = new Out(); - return getTransaction(hash, height); - } - - /** - * 根据指定的散列值,返回对应的交易信息与该交易所在区块的高度 - * 交易散列值 - * 返回该交易所在区块的高度 - * 返回对应的交易信息 - */ - public Transaction getTransaction(UInt256 hash, Out height) { return null; } - - public abstract Map getUnclaimed(UInt256 hash); - - /** - * 根据指定的散列值和索引,获取对应的未花费的资产 - * 交易散列值 - * 输出的索引 - * 返回一个交易输出,表示一个未花费的资产 - * @throws Exception - */ - public abstract TransactionOutput getUnspent(UInt256 hash, int index) throws Exception; - - /** - * 获取选票信息 - * 返回一个选票列表,包含当前区块链中所有有效的选票 - */ - public Stream getVotes() { - return getVotes(Stream.empty()); - } - - public abstract Stream getVotes(Stream others); - - /** - * 判断交易是否双花 - * 交易 - * 返回交易是否双花 - */ - public abstract boolean isDoubleSpend(Transaction tx); - - /** - * 注册默认的区块链实例 - * 区块链实例 - * 返回注册后的区块链实例 - */ - public static Blockchain register(Blockchain blockchain) { - if (blockchain == null) { - throw new NullPointerException(); - } - if (_default != null) { - _default.close(); - } - _default = blockchain; - return blockchain; - } - - public int getBlockHeightFromDb() throws Exception {return 0;} - public Block getBlockFromDb(int height) throws Exception {return null;} - - - -} diff --git a/src/main/java/DNA/Core/BlockchainAbility.java b/src/main/java/DNA/Core/BlockchainAbility.java deleted file mode 100644 index 194aef2..0000000 --- a/src/main/java/DNA/Core/BlockchainAbility.java +++ /dev/null @@ -1,40 +0,0 @@ -package DNA.Core; - -import java.util.EnumSet; - -/** - * 表示特定区块链实现所提供的功能 - */ -public enum BlockchainAbility { - /** - * 必须实现的虚函数:GetBlockAndHeight, GetBlockHeight, GetNextBlock, GetNextBlockHash, GetSysFeeAmount - */ - BlockIndexes(0x01), - - /** - * 必须实现的虚函数:ContainsAsset, GetAssets, GetEnrollments - */ - TransactionIndexes(0x02), - - /** - * 必须实现的虚函数:ContainsUnspent, GetUnclaimed, GetUnspent, GetVotes, IsDoubleSpend - */ - UnspentIndexes(0x04), - - /** - * 必须实现的虚函数:GetQuantityIssued - */ - Statistics(0x08); - - public static final EnumSet None = EnumSet.noneOf(BlockchainAbility.class); - public static final EnumSet All = EnumSet.allOf(BlockchainAbility.class); - private byte value; - - BlockchainAbility(int v) { - value = (byte)v; - } - - public byte getByte() { - return value; - } -} diff --git a/src/main/java/DNA/Core/BookKeeper.java b/src/main/java/DNA/Core/BookKeeper.java deleted file mode 100644 index 1c4087b..0000000 --- a/src/main/java/DNA/Core/BookKeeper.java +++ /dev/null @@ -1,37 +0,0 @@ -package DNA.Core; - -import java.io.IOException; -import java.math.BigInteger; - -import org.bouncycastle.math.ec.ECPoint; - -import DNA.Helper; -import DNA.Cryptography.ECC; -import DNA.IO.BinaryReader; -import DNA.IO.BinaryWriter; - -public class BookKeeper extends Transaction { - public ECPoint issuer; - public BookKeeperAction action; - public byte[] cert; - - public BookKeeper() { - super(TransactionType.BookKeeper); - } - - @Override - protected void deserializeExclusiveData(BinaryReader reader) throws IOException { - issuer = ECC.secp256r1.getCurve().createPoint( - new BigInteger(1,reader.readVarBytes()), new BigInteger(1,reader.readVarBytes())); - action = BookKeeperAction.valueOf(reader.readByte()); - cert = reader.readVarBytes(); - } - - @Override - protected void serializeExclusiveData(BinaryWriter writer) throws IOException { - writer.writeVarBytes(Helper.removePrevZero(issuer.getXCoord().toBigInteger().toByteArray())); - writer.writeVarBytes(Helper.removePrevZero(issuer.getYCoord().toBigInteger().toByteArray())); - writer.writeByte(action.value()); - writer.writeVarBytes(cert); - } -} diff --git a/src/main/java/DNA/Core/BookKeeperAction.java b/src/main/java/DNA/Core/BookKeeperAction.java deleted file mode 100644 index 7844a39..0000000 --- a/src/main/java/DNA/Core/BookKeeperAction.java +++ /dev/null @@ -1,23 +0,0 @@ -package DNA.Core; - -public enum BookKeeperAction { - BookKeeperAction_ADD(0x00), - BookKeeperAction_SUB(0x01), - ; - private byte value; - BookKeeperAction(int v) { - value = (byte)v; - } - public byte value() { - return value; - } - - public static BookKeeperAction valueOf(byte v) { - for (BookKeeperAction e : BookKeeperAction.values()) { - if (e.value == v) { - return e; - } - } - throw new IllegalArgumentException(); - } -} \ No newline at end of file diff --git a/src/main/java/DNA/Core/BookKeeping.java b/src/main/java/DNA/Core/BookKeeping.java deleted file mode 100644 index 9b2965f..0000000 --- a/src/main/java/DNA/Core/BookKeeping.java +++ /dev/null @@ -1,28 +0,0 @@ -package DNA.Core; - -import java.io.IOException; - -import DNA.IO.BinaryReader; -import DNA.IO.BinaryWriter; - -public class BookKeeping extends Transaction { - private long nonce; // nonce is not exist when version=2 - - public BookKeeping() { - super(TransactionType.BookKeeping); - } - - @Override - protected void deserializeExclusiveData(BinaryReader reader) throws IOException { - if(version == 3) { - nonce = reader.readLong(); - } - } - - @Override - protected void serializeExclusiveData(BinaryWriter writer) throws IOException { - if(version == 3) { - writer.writeLong(nonce); - } - } -} diff --git a/src/main/java/DNA/Core/Claimable.java b/src/main/java/DNA/Core/Claimable.java deleted file mode 100644 index fb2244f..0000000 --- a/src/main/java/DNA/Core/Claimable.java +++ /dev/null @@ -1,13 +0,0 @@ -package DNA.Core; - -import DNA.Fixed8; - -public class Claimable { - public TransactionOutput output; - public int startHeight; - public int endHeight; - - public Fixed8 value() { - return output.value; - } -} diff --git a/src/main/java/DNA/Core/DataFileTransaction.java b/src/main/java/DNA/Core/DataFileTransaction.java deleted file mode 100644 index 2aefc47..0000000 --- a/src/main/java/DNA/Core/DataFileTransaction.java +++ /dev/null @@ -1,38 +0,0 @@ -package DNA.Core; - -import java.io.IOException; -import java.math.BigInteger; - -import org.bouncycastle.math.ec.ECPoint; - -import DNA.Helper; -import DNA.Cryptography.ECC; -import DNA.IO.BinaryReader; -import DNA.IO.BinaryWriter; - -public class DataFileTransaction extends Transaction { - public String ipfsPath; - public String fileName; - public String note; - public ECPoint issuer; - - protected DataFileTransaction() { - super(TransactionType.DataFile); - } - - protected void deserializeExclusiveData(BinaryReader reader) throws IOException { - ipfsPath = reader.readVarString(); - fileName = reader.readVarString(); - note = reader.readVarString(); - issuer = ECC.secp256r1.getCurve().createPoint( - new BigInteger(1,reader.readVarBytes()), new BigInteger(1,reader.readVarBytes())); - } - - protected void serializeExclusiveData(BinaryWriter writer) throws IOException { - writer.writeVarString(ipfsPath); - writer.writeVarString(fileName); - writer.writeVarString(note); - writer.writeVarBytes(Helper.removePrevZero(issuer.getXCoord().toBigInteger().toByteArray())); - writer.writeVarBytes(Helper.removePrevZero(issuer.getYCoord().toBigInteger().toByteArray())); - } -} diff --git a/src/main/java/DNA/Core/DeployCodeTransaction.java b/src/main/java/DNA/Core/DeployCodeTransaction.java deleted file mode 100644 index 0b42b38..0000000 --- a/src/main/java/DNA/Core/DeployCodeTransaction.java +++ /dev/null @@ -1,36 +0,0 @@ -package DNA.Core; - -import java.io.IOException; -import DNA.IO.BinaryReader; -import DNA.IO.BinaryWriter; - -public class DeployCodeTransaction extends Transaction { - public FunctionCode code; - public String name; - public String codeVersion; - public String author; - public String email; - public String description; - - protected DeployCodeTransaction() { - super(TransactionType.DeployCode); - } - - protected void deserializeExclusiveData(BinaryReader reader) throws IOException { - code.deserialize(reader); - name = reader.readVarString(); - codeVersion = reader.readVarString(); - author = reader.readVarString(); - email = reader.readVarString(); - description = reader.readVarString(); - } - - protected void serializeExclusiveData(BinaryWriter writer) throws IOException { - code.serialize(writer); - writer.writeVarString(name); - writer.writeVarString(codeVersion); - writer.writeVarString(author); - writer.writeVarString(email); - writer.writeVarString(description); - } -} diff --git a/src/main/java/DNA/Core/DestroyTransaction.java b/src/main/java/DNA/Core/DestroyTransaction.java deleted file mode 100644 index 0301d8e..0000000 --- a/src/main/java/DNA/Core/DestroyTransaction.java +++ /dev/null @@ -1,14 +0,0 @@ -package DNA.Core; - -/** - * 注销资产 - * - * @author 12146 - * - */ -public class DestroyTransaction extends Transaction { - - public DestroyTransaction() { - super(TransactionType.DestroyTransaction); - } -} diff --git a/src/main/java/DNA/Core/EncryptedPayloadType.java b/src/main/java/DNA/Core/EncryptedPayloadType.java deleted file mode 100644 index 5fcac25..0000000 --- a/src/main/java/DNA/Core/EncryptedPayloadType.java +++ /dev/null @@ -1,25 +0,0 @@ -package DNA.Core; - -public enum EncryptedPayloadType { - RawPayload(0x01), - ; - - private byte value; - public int value() { - return value; - } - - EncryptedPayloadType(int value) { - this.value = (byte) value; - } - - public static EncryptedPayloadType from(byte i) { - for(EncryptedPayloadType type: EncryptedPayloadType.values()) { - if(type.value == i) { - return type; - } - } - throw new IllegalArgumentException(); - } - -} diff --git a/src/main/java/DNA/Core/FunctionCode.java b/src/main/java/DNA/Core/FunctionCode.java deleted file mode 100644 index 31d703e..0000000 --- a/src/main/java/DNA/Core/FunctionCode.java +++ /dev/null @@ -1,81 +0,0 @@ -package DNA.Core; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import DNA.UInt160; -import DNA.Core.Scripts.Program; -import DNA.IO.BinaryReader; -import DNA.IO.BinaryWriter; -import DNA.IO.Serializable; -import DNA.Wallets.ContractParameterType; - -public class FunctionCode implements ICode, Serializable{ - public byte[] code; - public ContractParameterType[] parameterTypes; - public ContractParameterType[] returnTypes; - public UInt160 scriptHash; - - @Override - public void deserialize(BinaryReader reader) throws IOException { - parameterTypes = toEnum(reader.readVarBytes()); - code = reader.readVarBytes(); - } - - @Override - public void serialize(BinaryWriter writer) throws IOException { - writer.writeVarBytes(toByte(parameterTypes)); - writer.writeVarBytes(code); - } - - private ContractParameterType toEnum(byte bt) { - return Arrays.stream(ContractParameterType.values()).filter(p -> p.ordinal() == bt).findAny().get(); - } - private ContractParameterType[] toEnum(byte[] bt) { - if(bt == null) { - return null; - } - List list = new ArrayList(); - for(byte b: bt) { - ContractParameterType type = toEnum(b); - list.add(type); - } - return list.stream().toArray(ContractParameterType[]::new); - } - private byte[] toByte(ContractParameterType[] types) { - if(types == null) { - return new byte[0]; - } - int len = types.length; - byte[] bt = new byte[len]; - for(int i=0; i hashes = new HashSet(Arrays.asList(super.getScriptHashesForVerifying())); - for (TransactionResult result : Arrays.stream(getTransactionResults()).filter(p -> p.amount.compareTo(Fixed8.ZERO) < 0).toArray(TransactionResult[]::new)) { - Transaction tx; - try { - tx = Blockchain.current().getTransaction(result.assetId); - } catch (Exception ex) { - throw new IllegalStateException(ex); - } - if (tx == null || !(tx instanceof RegisterTransaction)) { - throw new IllegalStateException(); - } - RegisterTransaction asset = (RegisterTransaction)tx; - hashes.add(asset.admin); - } - return hashes.stream().sorted().toArray(UInt160[]::new); - } - - @Override - public String toString() { - return "IssueTransaction [iss]"; - } -} diff --git a/src/main/java/DNA/Core/PayloadEncryptAttr.java b/src/main/java/DNA/Core/PayloadEncryptAttr.java deleted file mode 100644 index 0799173..0000000 --- a/src/main/java/DNA/Core/PayloadEncryptAttr.java +++ /dev/null @@ -1,8 +0,0 @@ -package DNA.Core; - -import DNA.IO.Serializable; - -public interface PayloadEncryptAttr extends Serializable{ - public byte[] encrypt(byte[] msg, byte[] keys); - public byte[] decrypt(byte[] msg, byte[] keys); -} diff --git a/src/main/java/DNA/Core/PayloadEncryptType.java b/src/main/java/DNA/Core/PayloadEncryptType.java deleted file mode 100644 index 23dc5e7..0000000 --- a/src/main/java/DNA/Core/PayloadEncryptType.java +++ /dev/null @@ -1,25 +0,0 @@ -package DNA.Core; - -public enum PayloadEncryptType { - ECDH_AES256(0x01), - ; - - private byte value; - public int value() { - return value; - } - - PayloadEncryptType(int value) { - this.value = (byte) value; - } - - public static PayloadEncryptType from(byte i) { - for(PayloadEncryptType type: PayloadEncryptType.values()) { - if(type.value == i) { - return type; - } - } - throw new IllegalArgumentException(); - } - -} diff --git a/src/main/java/DNA/Core/PrivacyPayloadTransaction.java b/src/main/java/DNA/Core/PrivacyPayloadTransaction.java deleted file mode 100644 index 009c95c..0000000 --- a/src/main/java/DNA/Core/PrivacyPayloadTransaction.java +++ /dev/null @@ -1,34 +0,0 @@ -package DNA.Core; - -import java.io.IOException; - -import DNA.IO.BinaryReader; -import DNA.IO.BinaryWriter; - -public class PrivacyPayloadTransaction extends Transaction { - public EncryptedPayloadType payloadType; - public byte[] payload; - public PayloadEncryptType encryptType; - public PayloadEncryptAttr encryptAttr; - - protected PrivacyPayloadTransaction() { - super(TransactionType.PrivacyPayload); - } - - protected void deserializeExclusiveData(BinaryReader reader) throws IOException { - byte[] bb = new byte[1]; - reader.read(bb); - payloadType = EncryptedPayloadType.from(bb[0]); - payload = reader.readVarBytes(); - reader.read(bb); - encryptType = PayloadEncryptType.from(bb[0]); - encryptAttr.deserialize(reader); - } - - protected void serializeExclusiveData(BinaryWriter writer) throws IOException { - writer.write(new byte[]{(byte)payloadType.value()}); - writer.writeVarBytes(payload); - writer.write(new byte[]{(byte)encryptType.value()}); - encryptAttr.serialize(writer); - } -} diff --git a/src/main/java/DNA/Core/RecordTransaction.java b/src/main/java/DNA/Core/RecordTransaction.java deleted file mode 100644 index 5fcf9d9..0000000 --- a/src/main/java/DNA/Core/RecordTransaction.java +++ /dev/null @@ -1,31 +0,0 @@ -package DNA.Core; - -import java.io.IOException; - -import DNA.IO.BinaryReader; -import DNA.IO.BinaryWriter; - -/** - * 存证交易 - * - */ -public class RecordTransaction extends Transaction { - public String recordType; - public byte[] recordData; - - public RecordTransaction() { - super(TransactionType.RecordTransaction); - } - - @Override - protected void deserializeExclusiveData(BinaryReader reader) throws IOException { - recordType = reader.readVarString(); - recordData = reader.readVarBytes(); - } - - @Override - protected void serializeExclusiveData(BinaryWriter writer) throws IOException { - writer.writeVarString(recordType); - writer.writeVarBytes(recordData); - } -} diff --git a/src/main/java/DNA/Core/RecordType.java b/src/main/java/DNA/Core/RecordType.java deleted file mode 100644 index b3a86f7..0000000 --- a/src/main/java/DNA/Core/RecordType.java +++ /dev/null @@ -1,26 +0,0 @@ -package DNA.Core; - -/** - * 记账模式 - */ -public enum RecordType { - UTXO(0x00), // utxo模式 - Balance(0x01), // 余额模式 - ; - - private byte v; - RecordType(int v) { - this.v = (byte)v; - } - public byte value() { - return v; - } - public static RecordType valueOf(byte b) { - for(RecordType tt: RecordType.values()) { - if(tt.value() == b) { - return tt; - } - } - throw new IllegalArgumentException(); - } -} \ No newline at end of file diff --git a/src/main/java/DNA/Core/RegisterTransaction.java b/src/main/java/DNA/Core/RegisterTransaction.java deleted file mode 100644 index fa48530..0000000 --- a/src/main/java/DNA/Core/RegisterTransaction.java +++ /dev/null @@ -1,129 +0,0 @@ -package DNA.Core; - -import java.io.IOException; -import java.math.BigInteger; -import java.util.Arrays; -import java.util.HashSet; - -import org.bouncycastle.math.ec.ECPoint; - -import DNA.Fixed8; -import DNA.Helper; -import DNA.UInt160; -import DNA.Core.Scripts.Program; -import DNA.Cryptography.ECC; -import DNA.IO.BinaryReader; -import DNA.IO.BinaryWriter; -import DNA.IO.Json.JNumber; -import DNA.IO.Json.JObject; -import DNA.IO.Json.JString; -import DNA.Wallets.Contract; - - -/** - * 注册资产交易 - * - */ -public class RegisterTransaction extends Transaction { - /** - * 资产名称 - */ - public String name; // 资产名称 - /** - * 资产描述 - */ - public String description; // 资产描述 - /** - * 精度 - */ - public byte precision; // 精度 - /** - * 资产类型 - */ - public AssetType assetType; // 资产类型 - /** - * 资产名称 - */ - public RecordType recordType; // 记账模式 - /** - * 资产数量 - */ - public Fixed8 amount; // 资产数量 - /** - * 发行者公钥 - */ - public ECPoint issuer; // 发行者公钥 - /** - * 管理者地址 - */ - public UInt160 admin; // 管理者地址 - - public RegisterTransaction() { - super(TransactionType.RegisterTransaction); - } - - @Override - protected void deserializeExclusiveData(BinaryReader reader) throws IOException { - try { - name = reader.readVarString(); - description = reader.readVarString(); - precision = reader.readByte(); - assetType = AssetType.valueOf(reader.readByte()); - recordType = RecordType.valueOf(reader.readByte()); - amount = reader.readSerializable(Fixed8.class); - byte[] xx = reader.readVarBytes(); - byte[] yy = reader.readVarBytes(); - admin = reader.readSerializable(UInt160.class); - issuer = ECC.secp256r1.getCurve().createPoint( - new BigInteger(1,xx), new BigInteger(1,yy)); - } catch (Exception ex) { - throw new IOException(ex); - } - } - @Override - protected void serializeExclusiveData(BinaryWriter writer) throws IOException { - writer.writeVarString(name); - writer.writeVarString(description); - writer.writeByte(precision); - writer.writeByte(assetType.value()); - writer.writeByte(recordType.value()); - writer.writeSerializable(amount); - writer.writeVarBytes(Helper.removePrevZero(issuer.getXCoord().toBigInteger().toByteArray())); - writer.writeVarBytes(Helper.removePrevZero(issuer.getYCoord().toBigInteger().toByteArray())); -// writer.writeVarBytes(issuer.getXCoord().toBigInteger().toByteArray()); -// writer.writeVarBytes(issuer.getYCoord().toBigInteger().toByteArray()); - writer.writeSerializable(admin); - } - - /** - * 获取验证脚本 - */ - @Override - public UInt160[] getScriptHashesForVerifying() { - HashSet hashes = new HashSet(Arrays.asList(super.getScriptHashesForVerifying())); - hashes.add(Program.toScriptHash(Contract.createSignatureRedeemScript(issuer))); - return hashes.stream().sorted().toArray(UInt160[]::new); - } - - @Override - public JObject json() { - JObject json = super.json(); - json.set("Asset", new JObject()); - json.get("Asset").set("Name", new JString(name)); - json.get("Asset").set("Precision", new JNumber(precision)); - json.get("Asset").set("AssetType", new JString(String.valueOf(assetType.value()))); - json.get("Asset").set("RecordType", new JString(String.valueOf(recordType))); - json.set("Amount", new JNumber(amount.toLong())); - json.set("Issuer", new JObject()); - json.get("Issuer").set("X", new JString(issuer.getXCoord().toBigInteger().toString())); - json.get("Issuer").set("Y", new JString(issuer.getYCoord().toBigInteger().toString())); - json.set("Controller", new JString(admin.toString())); - return json; - } - - @Override - public String toString() { - return "RegisterTransaction [name=" + name + "]"; - } - -} diff --git a/src/main/java/DNA/Core/Scripts/Program.java b/src/main/java/DNA/Core/Scripts/Program.java deleted file mode 100644 index 7fcb226..0000000 --- a/src/main/java/DNA/Core/Scripts/Program.java +++ /dev/null @@ -1,65 +0,0 @@ -package DNA.Core.Scripts; - -import java.io.IOException; - -import DNA.Helper; -import DNA.UInt160; -import DNA.Cryptography.Digest; -import DNA.IO.BinaryReader; -import DNA.IO.BinaryWriter; -import DNA.IO.JsonReader; -import DNA.IO.JsonSerializable; -import DNA.IO.JsonWriter; -import DNA.IO.Serializable; -import DNA.IO.Json.JObject; -import DNA.IO.Json.JString; - -/** - * 脚本 - */ -public class Program implements Serializable, JsonSerializable { - public byte[] parameter; - public byte[] code; - - @Override - public void deserialize(BinaryReader reader) throws IOException { - parameter = reader.readVarBytes(); // sign data - code = reader.readVarBytes(); // pubkey - } - - @Override - public void serialize(BinaryWriter writer) throws IOException { - writer.writeVarBytes(parameter); - writer.writeVarBytes(code); - } - - /** - * 变成json对象 - * 返回json对象 - */ - public JObject json() { - JObject json = new JObject(); - json.set("code", new JString(Helper.toHexString(code))); - json.set("parameter", new JString(Helper.toHexString(parameter))); - return json; - } - - public static UInt160 toScriptHash(byte[] script) { - return new UInt160(Digest.hash160(script)); - } - - /** - * byte格式数据反序列化 - */ - @Override - public void fromJson(JsonReader reader) { - JObject json = reader.json(); - code = Helper.hexToBytes(json.get("Code").asString()); - parameter = Helper.hexToBytes(json.get("Parameter").asString()); - } - - @Override - public void toJson(JsonWriter writer) { - // ... - } -} diff --git a/src/main/java/DNA/Core/Scripts/Script.java b/src/main/java/DNA/Core/Scripts/Script.java deleted file mode 100644 index 63d8918..0000000 --- a/src/main/java/DNA/Core/Scripts/Script.java +++ /dev/null @@ -1,65 +0,0 @@ -package DNA.Core.Scripts; - -import java.io.IOException; - -import DNA.Helper; -import DNA.UInt160; -import DNA.Cryptography.Digest; -import DNA.IO.BinaryReader; -import DNA.IO.BinaryWriter; -import DNA.IO.JsonReader; -import DNA.IO.JsonSerializable; -import DNA.IO.JsonWriter; -import DNA.IO.Serializable; -import DNA.IO.Json.JObject; -import DNA.IO.Json.JString; - -/** - * 脚本 - */ -public class Script implements Serializable, JsonSerializable { - public byte[] stackScript; - public byte[] redeemScript; - - @Override - public void deserialize(BinaryReader reader) throws IOException { - stackScript = reader.readVarBytes(); - redeemScript = reader.readVarBytes(); - } - - @Override - public void serialize(BinaryWriter writer) throws IOException { - writer.writeVarBytes(stackScript); - writer.writeVarBytes(redeemScript); - } - - /** - * 变成json对象 - * 返回json对象 - */ - public JObject json() { - JObject json = new JObject(); - json.set("stack", new JString(Helper.toHexString(stackScript))); - json.set("redeem", new JString(Helper.toHexString(redeemScript))); - return json; - } - - public static UInt160 toScriptHash(byte[] script) { - return new UInt160(Digest.hash160(script)); - } - - /** - * byte格式数据反序列化 - */ - @Override - public void fromJson(JsonReader reader) { - JObject json = reader.json(); - stackScript = Helper.hexToBytes(json.get("Code").asString()); - redeemScript = Helper.hexToBytes(json.get("Parameter").asString()); - } - - @Override - public void toJson(JsonWriter writer) { - // ... - } -} diff --git a/src/main/java/DNA/Core/Scripts/ScriptBuilder.java b/src/main/java/DNA/Core/Scripts/ScriptBuilder.java deleted file mode 100644 index 244288f..0000000 --- a/src/main/java/DNA/Core/Scripts/ScriptBuilder.java +++ /dev/null @@ -1,108 +0,0 @@ -package DNA.Core.Scripts; - -import java.io.*; -import java.math.BigInteger; -import java.nio.*; - -import DNA.UIntBase; - -/** - * 脚本生成器 - */ -public class ScriptBuilder implements AutoCloseable { - private ByteArrayOutputStream ms = new ByteArrayOutputStream(); - - /** - * 添加操作符 - * 操作符 - * 返回添加操作符之后的脚本生成器 - */ - public ScriptBuilder add(ScriptOp op) { - return add(op.getByte()); - } - - private ScriptBuilder add(byte op) { - ms.write(op); - return this; - } - - /** - * 添加一段脚本 - * 脚本 - * 返回添加脚本之后的脚本生成器 - */ - public ScriptBuilder add(byte[] script) { - ms.write(script, 0, script.length); - return this; - } - - @Override - public void close() { - try { - ms.close(); - } catch (IOException ex) { - throw new RuntimeException(ex); - } - } - - /** - * 添加一段脚本,该脚本的作用是将一个整数压入栈中 - * 要压入栈中的整数 - * 返回添加脚本之后的脚本生成器 - */ - public ScriptBuilder push(BigInteger number) { - if (number.equals(BigInteger.ONE.negate())) - return add(ScriptOp.OP_1NEGATE); - if (number.equals(BigInteger.ZERO)) - return add(ScriptOp.OP_0); - if (number.compareTo(BigInteger.ZERO) > 0 && number.compareTo(BigInteger.valueOf(16)) <= 0) - return add((byte)(ScriptOp.OP_1.getByte() - 1 + number.byteValue())); - return push(number.toByteArray()); - } - - /** - * 添加一段脚本,该脚本的作用是将一个字节数组压入栈中 - * 要压入栈中的字节数组 - * 返回添加脚本之后的脚本生成器 - */ - public ScriptBuilder push(byte[] data) { - if (data == null) { - throw new NullPointerException(); - } - if (data.length <= (int)ScriptOp.OP_PUSHBYTES75.getByte()) { - ms.write((byte)data.length); - ms.write(data, 0, data.length); - } else if (data.length < 0x100) { - add(ScriptOp.OP_PUSHDATA1); - ms.write((byte)data.length); - ms.write(data, 0, data.length); - } else if (data.length < 0x10000) { - add(ScriptOp.OP_PUSHDATA2); - ms.write(ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN).putShort((short)data.length).array(), 0, 2); - ms.write(data, 0, data.length); - } else if (data.length < 0x100000000L) { - add(ScriptOp.OP_PUSHDATA4); - ms.write(ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(data.length).array(), 0, 4); - ms.write(data, 0, data.length); - } else { - throw new IllegalArgumentException(); - } - return this; - } - - /** - * 添加一段脚本,该脚本的作用是将一个散列值压入栈中 - * 要压入栈中的散列值 - * 返回添加脚本之后的脚本生成器 - */ - public ScriptBuilder push(UIntBase hash) { - return push(hash.toArray()); - } - - /** - * 获取脚本生成器中包含的脚本代码 - */ - public byte[] toArray() { - return ms.toByteArray(); - } -} diff --git a/src/main/java/DNA/Core/Scripts/ScriptEngine.java b/src/main/java/DNA/Core/Scripts/ScriptEngine.java deleted file mode 100644 index feed563..0000000 --- a/src/main/java/DNA/Core/Scripts/ScriptEngine.java +++ /dev/null @@ -1,6 +0,0 @@ -package DNA.Core.Scripts; - - -public class ScriptEngine { - // ... -} \ No newline at end of file diff --git a/src/main/java/DNA/Core/Scripts/StackItem.java b/src/main/java/DNA/Core/Scripts/StackItem.java deleted file mode 100644 index 36d5184..0000000 --- a/src/main/java/DNA/Core/Scripts/StackItem.java +++ /dev/null @@ -1,6 +0,0 @@ -package DNA.Core.Scripts; - - -class StackItem { - // ... -} diff --git a/src/main/java/DNA/Core/Signable.java b/src/main/java/DNA/Core/Signable.java deleted file mode 100644 index fb8fda9..0000000 --- a/src/main/java/DNA/Core/Signable.java +++ /dev/null @@ -1,65 +0,0 @@ -package DNA.Core; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.math.BigInteger; - -import org.bouncycastle.crypto.params.ECPrivateKeyParameters; -import org.bouncycastle.crypto.signers.ECDSASigner; -import org.bouncycastle.util.BigIntegers; - -import DNA.UInt160; -import DNA.Cryptography.*; -import DNA.IO.*; -import DNA.Wallets.Account; - -/** - * 为需要签名的数据提供一个接口 - */ -public interface Signable extends Serializable { - /** - * 反序列化未签名的数据 - * 数据来源 - * @throws IOException - */ - void deserializeUnsigned(BinaryReader reader) throws IOException; - - /** - * 序列化未签名的数据 - * 存放序列化后的结果 - * @throws IOException - */ - void serializeUnsigned(BinaryWriter writer) throws IOException; - - /** - * 获得需要校验的脚本Hash值 - * 返回需要校验的脚本Hash值 - */ - UInt160[] getScriptHashesForVerifying(); - - default byte[] getHashData() { - try (ByteArrayOutputStream ms = new ByteArrayOutputStream()) { - try (BinaryWriter writer = new BinaryWriter(ms)) { - serializeUnsigned(writer); - writer.flush(); - return ms.toByteArray(); - } - } catch (IOException ex) { - throw new UnsupportedOperationException(ex); - } - } - - default byte[] sign(Account account) { - ECDSASigner signer = new ECDSASigner(); - signer.init(true, new ECPrivateKeyParameters(new BigInteger(1, account.privateKey), ECC.secp256r1)); - BigInteger[] bi = signer.generateSignature(Digest.sha256(getHashData()));// dna - byte[] signature = new byte[64]; - System.arraycopy(BigIntegers.asUnsignedByteArray(32, bi[0]), 0, signature, 0, 32); - System.arraycopy(BigIntegers.asUnsignedByteArray(32, bi[1]), 0, signature, 32, 32); - return signature; - } - - default boolean verifySignature() { - return true; - } -} diff --git a/src/main/java/DNA/Core/SignatureContext.java b/src/main/java/DNA/Core/SignatureContext.java deleted file mode 100644 index d5361c8..0000000 --- a/src/main/java/DNA/Core/SignatureContext.java +++ /dev/null @@ -1,155 +0,0 @@ -package DNA.Core; - -import java.lang.reflect.Array; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; - -import org.bouncycastle.math.ec.ECPoint; - -import DNA.Helper; -import DNA.UInt160; -import DNA.Core.Scripts.Program; -import DNA.Core.Scripts.ScriptBuilder; -import DNA.Cryptography.ECC; -import DNA.IO.Json.JArray; -import DNA.IO.Json.JBoolean; -import DNA.IO.Json.JObject; -import DNA.IO.Json.JString; -import DNA.Wallets.Contract; -import DNA.Wallets.ContractParameterType; - -/** - * 签名上下文 - * - */ -public class SignatureContext { - /** - * 要签名的数据 - */ - public final Signable signable; - /** - * 要验证的脚本散列值 - */ - public final UInt160[] scriptHashes; - /** - * 合约脚本代码 - */ - private final byte[][] redeemScripts; - /** - * 公钥-签名数据 - */ - private final Map[] signatures; - - private final boolean[] completed; - - /** - * 判断签名是否完成 - */ - public boolean isCompleted() { - for (boolean b : completed) { - if (!b) { - return false; - } - } - return true; - } - - /** - * 对指定的数据构造签名上下文 - * 要签名的数据 - */ - @SuppressWarnings("unchecked") - public SignatureContext(Signable signable) { - this.signable = signable; - this.scriptHashes = signable.getScriptHashesForVerifying(); - this.redeemScripts = new byte[scriptHashes.length][]; - this.signatures = (Map[]) Array.newInstance(Map.class, scriptHashes.length); - this.completed = new boolean[scriptHashes.length]; - } - - /** - * 添加一个签名 - * 该签名所对应的合约 - * 该签名所对应的公钥 - * 签名 - * 返回签名是否已成功添加 - */ - public boolean add(Contract contract, ECPoint pubkey, byte[] signature) { - for (int i = 0; i < scriptHashes.length; i++) { - if (scriptHashes[i].equals(contract.scriptHash())) { - if (redeemScripts[i] == null) { - redeemScripts[i] = contract.redeemScript; - } - if (signatures[i] == null) { - signatures[i] = new HashMap(); - } - signatures[i].put(pubkey, signature); - completed[i] |= - contract.parameterList.length == signatures[i].size() - && Arrays.stream(contract.parameterList).allMatch( - p -> p == ContractParameterType.Signature); - return true; - } - } - return false; - } - - /** - * 从签名上下文中获得完整签名的合约脚本 - * 返回合约脚本 - */ - public Program[] getScripts() { - if (!isCompleted()) throw new IllegalStateException(); - Program[] scripts = new Program[signatures.length]; - for (int i = 0; i < scripts.length; i++) { - try (ScriptBuilder sb = new ScriptBuilder()) { - for (byte[] signature : signatures[i].entrySet().stream() - .sorted((a, b) -> ECC.compare(a.getKey(), b.getKey())) - .map(p -> p.getValue()).toArray(byte[][]::new)) { - sb.push(signature); - } - scripts[i] = new Program(); - scripts[i].parameter = sb.toArray(); // sign - scripts[i].code = redeemScripts[i]; // pk - } - } - return scripts; - } - - /** - * 把签名上下文转为json对象 - * 返回json对象 - */ - public JObject json() { - JObject json = new JObject(); - json.set("type", new JString(signable.getClass().getTypeName())); - json.set("hex", new JString(Helper.toHexString(signable.getHashData()))); - JArray scripts = new JArray(); - for (int i = 0; i < signatures.length; i++) { - if (signatures[i] == null) { - scripts.add(null); - } else { - scripts.add(new JObject()); - scripts.get(i).set("redeem_script", new JString(Helper.toHexString(redeemScripts[i]))); - JArray sigs = new JArray(); - for (Entry pair : signatures[i].entrySet()) { - JObject signature = new JObject(); - signature.set("pubkey", new JString(Helper.toHexString(pair.getKey().getEncoded(true)))); - signature.set("signature", new JString(Helper.toHexString(pair.getValue()))); - sigs.add(signature); - } - scripts.get(i).set("signatures", sigs); - scripts.get(i).set("completed", new JBoolean(completed[i])); - } - } - json.set("scripts", scripts); - return json; - } - - @Override - public String toString() { - return json().toString(); - } -} diff --git a/src/main/java/DNA/Core/StateUpdateTransaction.java b/src/main/java/DNA/Core/StateUpdateTransaction.java deleted file mode 100644 index 0ca08db..0000000 --- a/src/main/java/DNA/Core/StateUpdateTransaction.java +++ /dev/null @@ -1,52 +0,0 @@ -package DNA.Core; - -import java.io.IOException; -import java.math.BigInteger; -import java.util.Arrays; -import java.util.HashSet; - -import org.bouncycastle.math.ec.ECPoint; - -import DNA.Helper; -import DNA.UInt160; -import DNA.Core.Scripts.Program; -import DNA.Cryptography.ECC; -import DNA.IO.BinaryReader; -import DNA.IO.BinaryWriter; -import DNA.Wallets.Contract; - -public class StateUpdateTransaction extends Transaction { - public byte[] namespace; - public byte[] key; - public byte[] value; - public ECPoint updater; - - public StateUpdateTransaction() { - super(TransactionType.StateUpdateTransaction); - } - - @Override - protected void deserializeExclusiveData(BinaryReader reader) throws IOException { - namespace = reader.readVarBytes(); - key = reader.readVarBytes(); - value = reader.readVarBytes(); - updater = ECC.secp256r1.getCurve().createPoint( - new BigInteger(1,reader.readVarBytes()), new BigInteger(1,reader.readVarBytes())); - } - - @Override - protected void serializeExclusiveData(BinaryWriter writer) throws IOException { - writer.writeVarBytes(namespace); - writer.writeVarBytes(key); - writer.writeVarBytes(value); - writer.writeVarBytes(Helper.removePrevZero(updater.getXCoord().toBigInteger().toByteArray())); - writer.writeVarBytes(Helper.removePrevZero(updater.getYCoord().toBigInteger().toByteArray())); - } - - @Override - public UInt160[] getScriptHashesForVerifying() { - HashSet hashes = new HashSet(Arrays.asList(super.getScriptHashesForVerifying())); - hashes.add(Program.toScriptHash(Contract.createSignatureRedeemScript(updater))); - return hashes.stream().sorted().toArray(UInt160[]::new); - } -} diff --git a/src/main/java/DNA/Core/StateUpdaterTransaction.java b/src/main/java/DNA/Core/StateUpdaterTransaction.java deleted file mode 100644 index a45fab1..0000000 --- a/src/main/java/DNA/Core/StateUpdaterTransaction.java +++ /dev/null @@ -1,46 +0,0 @@ -package DNA.Core; - -import java.io.IOException; -import java.math.BigInteger; - -import org.bouncycastle.math.ec.ECPoint; - -import DNA.Helper; -import DNA.Cryptography.ECC; -import DNA.IO.BinaryReader; -import DNA.IO.BinaryWriter; - -/** - * 账本状态控制者交易 - * - * @author 12146 - * - */ -public class StateUpdaterTransaction extends Transaction { - public ECPoint issuer; - public BookKeeperAction action; - public byte[] cert; - public String namespace; - - public StateUpdaterTransaction() { - super(TransactionType.StateUpdaterTransaction); - } - - @Override - protected void deserializeExclusiveData(BinaryReader reader) throws IOException { - issuer = ECC.secp256r1.getCurve().createPoint( - new BigInteger(1,reader.readVarBytes()), new BigInteger(1,reader.readVarBytes())); - action = BookKeeperAction.valueOf(reader.readByte()); - cert = reader.readVarBytes(); - namespace = reader.readVarString(); - } - - @Override - protected void serializeExclusiveData(BinaryWriter writer) throws IOException { - writer.writeVarBytes(Helper.removePrevZero(issuer.getXCoord().toBigInteger().toByteArray())); - writer.writeVarBytes(Helper.removePrevZero(issuer.getYCoord().toBigInteger().toByteArray())); - writer.writeByte(action.value()); - writer.writeVarBytes(cert); - writer.writeVarString(namespace); - } -} diff --git a/src/main/java/DNA/Core/Transaction.java b/src/main/java/DNA/Core/Transaction.java deleted file mode 100644 index 0888ed5..0000000 --- a/src/main/java/DNA/Core/Transaction.java +++ /dev/null @@ -1,256 +0,0 @@ -package DNA.Core; - -import java.io.*; -import java.util.*; -import java.util.Map.Entry; -import java.util.stream.*; - -import DNA.*; -import DNA.Core.Scripts.Program; -import DNA.IO.*; -import DNA.IO.Json.*; -import DNA.Network.*; - -/** - * 交易 - */ -public abstract class Transaction extends Inventory { - /** - * 交易类型 - */ - public final TransactionType type; - /** - * 版本 - */ - public byte version = 0; - /** - * 随机数 - */ - public long nonce; - /** - * 交易属性 - */ - public TransactionAttribute[] attributes; - /** - * 交易资产来源 - */ - public TransactionInput[] inputs; - /** - * 交易资产去向 - */ - public TransactionOutput[] outputs; - /** - * 验证脚本 - */ - public Program[] scripts; - - protected Transaction(TransactionType type) { - this.type = type; - } - - @Override - public void deserialize(BinaryReader reader) throws IOException { - deserializeUnsigned(reader); - try { - scripts = reader.readSerializableArray(Program.class); - } catch (InstantiationException | IllegalAccessException ex) { - throw new RuntimeException(ex); - } - onDeserialized(); - } - @Override - public void deserializeUnsigned(BinaryReader reader) throws IOException { - if (type.value() != reader.readByte()) { // type - throw new IOException(); - } - deserializeUnsignedWithoutType(reader); - } - - private void deserializeUnsignedWithoutType(BinaryReader reader) throws IOException { - try { - version = reader.readByte(); - deserializeExclusiveData(reader); - attributes = reader.readSerializableArray(TransactionAttribute.class); - inputs = reader.readSerializableArray(TransactionInput.class); - TransactionInput[] inputs_all = getAllInputs().toArray(TransactionInput[]::new); - for (int i = 1; i < inputs_all.length; i++) { - for (int j = 0; j < i; j++) { - if (inputs_all[i].prevHash == inputs_all[j].prevHash && inputs_all[i].prevIndex == inputs_all[j].prevIndex) { - throw new IOException(); - } - } - } - outputs = reader.readSerializableArray(TransactionOutput.class); - } catch (InstantiationException | IllegalAccessException ex) { - throw new IOException(ex); - } - } - - protected void deserializeExclusiveData(BinaryReader reader) throws IOException { - } - - @Override - public void serialize(BinaryWriter writer) throws IOException { - serializeUnsigned(writer); - writer.writeSerializableArray(scripts); - } - - @Override - public void serializeUnsigned(BinaryWriter writer) throws IOException { - writer.writeByte(type.value()); - writer.writeByte(version); - serializeExclusiveData(writer); - writer.writeSerializableArray(attributes); - writer.writeSerializableArray(inputs); - writer.writeSerializableArray(outputs); - } - - protected void serializeExclusiveData(BinaryWriter writer) throws IOException { - } - - @Override - public boolean equals(Object obj) { - if (obj == this) { - return true; - } - if (obj == null) { - return false; - } - if (!(obj instanceof Transaction)) { - return false; - } - Transaction tx = (Transaction)obj; - return hash().equals(tx.hash()); - } - - @Override - public int hashCode() { - return hash().hashCode(); - } - - /** - * 反序列化Transaction(static) - */ - public static Transaction deserializeFrom(byte[] value) throws IOException { - return deserializeFrom(value, 0); - } - - public static Transaction deserializeFrom(byte[] value, int offset) throws IOException { - try (ByteArrayInputStream ms = new ByteArrayInputStream(value, offset, value.length - offset)) { - try (BinaryReader reader = new BinaryReader(ms)) { - return deserializeFrom(reader); - } - } - } - - public static Transaction deserializeFrom(BinaryReader reader) throws IOException { - try { - TransactionType type = TransactionType.valueOf(reader.readByte()); - String typeName = "DNA.Core." + type.toString(); - Transaction transaction = (Transaction)Class.forName(typeName).newInstance(); - transaction.deserializeUnsignedWithoutType(reader); - transaction.scripts = reader.readSerializableArray(Program.class); - return transaction; - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) { - throw new IOException(ex); - } - } - - public Stream getAllInputs() { - return Arrays.stream(inputs); - } - - public Stream getAllOutputs() { - return Arrays.stream(outputs); - } - - /** - * 获取验证脚本 - */ - @Override - public UInt160[] getScriptHashesForVerifying() { - if (references() == null) throw new IllegalStateException(); - HashSet hashes = new HashSet(getAllInputs().map(p -> references().get(p).scriptHash).collect(Collectors.toList())); - for (Entry> group : getAllOutputs().collect(Collectors.groupingBy(p -> p.assetId)).entrySet()) { - Transaction tx; - try { - tx = Blockchain.current().getTransaction(group.getKey()); - } catch (Exception ex) { - throw new IllegalStateException(ex); - } - if (tx == null || !(tx instanceof RegisterTransaction)) { - throw new IllegalStateException(); - } - } - return hashes.stream().sorted().toArray(UInt160[]::new); - } - - public TransactionResult[] getTransactionResults() { - if (references() == null) return null; - Stream in = references().values().stream().map(p -> new TransactionResult(p.assetId, p.value)); - Stream out = getAllOutputs().map(p -> new TransactionResult(p.assetId, p.value.negate())); - Map results = Stream.concat(in, out).collect(Collectors.toMap(p -> p.assetId, p -> p.amount, (a, b) -> a.add(b))); - return results.entrySet().stream().filter(p -> !p.getValue().equals(Fixed8.ZERO)).map(p -> new TransactionResult(p.getKey(), p.getValue())).toArray(TransactionResult[]::new); - } - - @Override - public final InventoryType inventoryType() { - return InventoryType.TX; - } - - public JObject json() { - JObject json = new JObject(); - json.set("txid", new JString(hash().toString())); - json.set("TxType", new JString(type.toString())); - json.set("PayloadVersion", new JString(String.valueOf(version))); - json.set("Nonce", new JNumber(nonce)); - json.set("Attributes", new JArray(Arrays.stream(attributes).map(p -> p.json()).toArray(JObject[]::new))); - json.set("UTXOInputs", new JArray(Arrays.stream(inputs).map(p -> p.json()).toArray(JObject[]::new))); - json.set("Outputs", new JArray(IntStream.range(0, outputs.length).boxed().map(i -> outputs[i].json(i)).toArray(JObject[]::new))); - json.set("Programs", new JArray(Arrays.stream(scripts).map(p -> p.json()).toArray(JObject[]::new))); - return json; - } - - - protected void onDeserialized() throws IOException { - } - - //[NonSerialized] - private Map _references = null; - public Map references() { - if (_references == null) { - Map map = new HashMap(); - for (Entry> entry : getAllInputs().collect(Collectors.groupingBy(p -> p.prevHash)).entrySet()) { - Transaction tx; - try { - tx = Blockchain.current().getTransaction(entry.getKey()); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - if (tx == null) { - return null; - } - for (TransactionInput input : entry.getValue()) { - map.put(input, tx.outputs[input.prevIndex]); - } - } - _references = map; - } - return _references; - } - - /** - * 系统费用 - */ - public Fixed8 systemFee() { - return Fixed8.ZERO; - } - - /** - * 校验 - */ - @Override - public boolean verify() { - return true; - } -} diff --git a/src/main/java/DNA/Core/TransactionAttribute.java b/src/main/java/DNA/Core/TransactionAttribute.java deleted file mode 100644 index 04b10d7..0000000 --- a/src/main/java/DNA/Core/TransactionAttribute.java +++ /dev/null @@ -1,71 +0,0 @@ -package DNA.Core; - -import java.io.IOException; -import java.util.Arrays; - -import DNA.Helper; -import DNA.IO.BinaryReader; -import DNA.IO.BinaryWriter; -import DNA.IO.Serializable; -import DNA.IO.Json.JObject; -import DNA.IO.Json.JString; - -/** - * 交易属性 - */ -public class TransactionAttribute implements Serializable { - /** - * 用途 - */ - public TransactionAttributeUsage usage; - /** - * 描述 - */ - public byte[] data; - - /** - * byte格式数据反序列化 - */ - @Override - public void serialize(BinaryWriter writer) throws IOException { - // usage - writer.writeByte(usage.value()); - // data - if (usage == TransactionAttributeUsage.Script - || usage == TransactionAttributeUsage.DescriptionUrl - || usage == TransactionAttributeUsage.Description - || usage == TransactionAttributeUsage.Nonce) { - writer.writeVarBytes(data); - } else { - throw new IOException(); - } - } - - @Override - public void deserialize(BinaryReader reader) throws IOException { - // usage - usage = TransactionAttributeUsage.valueOf(reader.readByte()); - // data - if (usage == TransactionAttributeUsage.Script - || usage == TransactionAttributeUsage.DescriptionUrl - || usage == TransactionAttributeUsage.Description - || usage == TransactionAttributeUsage.Nonce) { - data = reader.readVarBytes(255); - } else { - throw new IOException(); - } - } - - public JObject json() { - JObject json = new JObject(); - json.set("usage", new JString(usage.toString())); - json.set("data", new JString(Helper.toHexString(data))); - return json; - } - - @Override - public String toString() { - return "TransactionAttribute [usage=" + usage + ", data=" - + Arrays.toString(data) + "]"; - } -} diff --git a/src/main/java/DNA/Core/TransactionAttributeUsage.java b/src/main/java/DNA/Core/TransactionAttributeUsage.java deleted file mode 100644 index 263bb69..0000000 --- a/src/main/java/DNA/Core/TransactionAttributeUsage.java +++ /dev/null @@ -1,36 +0,0 @@ -package DNA.Core; - -/** - * 表示交易特性的用途 - */ -public enum TransactionAttributeUsage { - - Nonce(0x00), - /** - * 用于对交易进行额外的验证 - */ - Script(0x20), - - DescriptionUrl(0x81), - Description(0x90), - - ; - private byte value; - - TransactionAttributeUsage(int v) { - value = (byte)v; - } - - public byte value() { - return value; - } - - public static TransactionAttributeUsage valueOf(byte v) { - for (TransactionAttributeUsage e : TransactionAttributeUsage.values()) { - if (e.value == v) { - return e; - } - } - throw new IllegalArgumentException(); - } -} diff --git a/src/main/java/DNA/Core/TransactionInput.java b/src/main/java/DNA/Core/TransactionInput.java deleted file mode 100644 index f01666d..0000000 --- a/src/main/java/DNA/Core/TransactionInput.java +++ /dev/null @@ -1,77 +0,0 @@ -package DNA.Core; - -import java.io.IOException; - -import DNA.UInt256; -import DNA.IO.BinaryReader; -import DNA.IO.BinaryWriter; -import DNA.IO.Serializable; -import DNA.IO.Json.JNumber; -import DNA.IO.Json.JObject; -import DNA.IO.Json.JString; - -/** - * 交易输入 - */ -public class TransactionInput implements Serializable { - /** - * 引用交易的散列值 - */ - public UInt256 prevHash; - /** - * 引用交易输出的索引 - */ - public short prevIndex; - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (null == obj) { - return false; - } - if (!(obj instanceof TransactionInput)) { - return false; - } - TransactionInput other = (TransactionInput) obj; - return prevHash.equals(other.prevHash) && prevIndex == other.prevIndex; - } - - @Override - public int hashCode() { - return prevHash.hashCode() + prevIndex; - } - - /** - * byte格式数据反序列化 - */ - @Override - public void deserialize(BinaryReader reader) throws IOException { - try { - prevHash = reader.readSerializable(UInt256.class); - prevIndex = reader.readShort(); -// prevIndex = (short) reader.readVarInt(); - } catch (InstantiationException | IllegalAccessException e) { - } - } - @Override - public void serialize(BinaryWriter writer) throws IOException { - writer.writeSerializable(prevHash); - writer.writeShort(prevIndex); -// writer.writeVarInt(prevIndex); - } - - public JObject json() { - JObject json = new JObject(); - json.set("txid", new JString(prevHash.toString())); - json.set("vout", new JNumber(Short.toUnsignedInt(prevIndex))); - return json; - } - - @Override - public String toString() { - return "TransactionInput [prevHash=" + prevHash + ", prevIndex=" - + prevIndex + "]"; - } -} diff --git a/src/main/java/DNA/Core/TransactionOutput.java b/src/main/java/DNA/Core/TransactionOutput.java deleted file mode 100644 index 4952e4e..0000000 --- a/src/main/java/DNA/Core/TransactionOutput.java +++ /dev/null @@ -1,64 +0,0 @@ -package DNA.Core; - -import java.io.IOException; - -import DNA.*; -import DNA.IO.*; -import DNA.IO.Json.*; -import DNA.Wallets.Wallet; - -/** - * 交易输出 - */ -public class TransactionOutput implements Serializable { - /** - * 资产编号 - */ - public UInt256 assetId; - /** - * 金额 - */ - public Fixed8 value; - /** - * 收款地址 - */ - public UInt160 scriptHash; - - /** - * byte格式数据反序列化 - */ - @Override - public void serialize(BinaryWriter writer) throws IOException { - writer.writeSerializable(assetId); - writer.writeSerializable(value); - writer.writeSerializable(scriptHash); - } - - @Override - public void deserialize(BinaryReader reader) throws IOException { - try { - assetId = reader.readSerializable(UInt256.class); - value = reader.readSerializable(Fixed8.class); - scriptHash = reader.readSerializable(UInt160.class); - } catch (InstantiationException | IllegalAccessException e) { - throw new IOException(); - } - } - - public JObject json(int index) { - JObject json = new JObject(); - json.set("n", new JNumber(index)); - json.set("asset", new JString(assetId.toString())); - json.set("value", new JString(value.toString())); - json.set("high", new JNumber(value.getData() >> 32)); - json.set("low", new JNumber(value.getData() & 0xffffffff)); - json.set("address", new JString(Wallet.toAddress(scriptHash))); - return json; - } - - @Override - public String toString() { - return "TransactionOutput [assetId=" + assetId + ", value=" + value - + ", scriptHash=" + scriptHash + "]"; - } -} diff --git a/src/main/java/DNA/Core/TransactionResult.java b/src/main/java/DNA/Core/TransactionResult.java deleted file mode 100644 index 4c783c8..0000000 --- a/src/main/java/DNA/Core/TransactionResult.java +++ /dev/null @@ -1,22 +0,0 @@ -package DNA.Core; - -import DNA.*; - -/** - * 交易结果,表示交易中资产的变化量 - */ -public class TransactionResult { - /** - * 资产编号 - */ - public final UInt256 assetId; - /** - * 该资产的变化量 - */ - public final Fixed8 amount; - - public TransactionResult(UInt256 assetId, Fixed8 amount) { - this.assetId = assetId; - this.amount = amount; - } -} diff --git a/src/main/java/DNA/Core/TransactionType.java b/src/main/java/DNA/Core/TransactionType.java deleted file mode 100644 index 07d80fb..0000000 --- a/src/main/java/DNA/Core/TransactionType.java +++ /dev/null @@ -1,77 +0,0 @@ -package DNA.Core; - -/** - * list transaction types supported by DNA - */ -public enum TransactionType { - /** - * used for accounting - */ - BookKeeping(0x00), - /** - * used for accounting - */ - IssueTransaction(0x01), - /** - * - */ - BookKeeper(0x02), - /** - * - */ - DataFile(0x12), - /** - * - */ - DeployCode(0xd0), - /** - * - */ - PrivacyPayload(0x20), - /** - * - */ - RegisterTransaction(0x40), - /** - * used for transfering Transaction, this is - */ - TransferTransaction(0x80), - /** - * used for storing certificate - */ - RecordTransaction(0x81), - - /** - * 账本状态资产 - */ - StateUpdateTransaction(0x90), - - /** - * 账本状态资产控制 - */ - StateUpdaterTransaction(0x91), - - /** - * 销毁资产 - */ - DestroyTransaction(0x18), - - ; - - private byte value; - TransactionType(int v) { - value = (byte)v; - } - public byte value() { - return value; - } - - public static TransactionType valueOf(byte v) { - for (TransactionType e : TransactionType.values()) { - if (e.value == v) { - return e; - } - } - throw new IllegalArgumentException(); - } -} diff --git a/src/main/java/DNA/Core/TransferTransaction.java b/src/main/java/DNA/Core/TransferTransaction.java deleted file mode 100644 index 5d228ae..0000000 --- a/src/main/java/DNA/Core/TransferTransaction.java +++ /dev/null @@ -1,12 +0,0 @@ -package DNA.Core; - -/** - * 资产转移交易 - * - */ -public class TransferTransaction extends Transaction { - - public TransferTransaction() { - super(TransactionType.TransferTransaction); - } -} diff --git a/src/main/java/DNA/Core/Vote.java b/src/main/java/DNA/Core/Vote.java deleted file mode 100644 index ab55cc5..0000000 --- a/src/main/java/DNA/Core/Vote.java +++ /dev/null @@ -1,17 +0,0 @@ -package DNA.Core; - -import DNA.*; - -/** - * 投票信息 - */ -public class Vote { - /** - * 报名表的散列值列表 - */ - public UInt256[] enrollments; - /** - * 选票的数目 - */ - public Fixed8 count; -} diff --git a/src/main/java/DNA/Cryptography/Base58.java b/src/main/java/DNA/Cryptography/Base58.java deleted file mode 100644 index de604c3..0000000 --- a/src/main/java/DNA/Cryptography/Base58.java +++ /dev/null @@ -1,58 +0,0 @@ -package DNA.Cryptography; - -import java.math.BigInteger; - -public class Base58 { - /** - * base58编码的字母表 - */ - public static final String ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - private static final BigInteger BASE = BigInteger.valueOf(ALPHABET.length()); - - /** - * 解码 - * 要解码的字符串 - * 返回解码后的字节数组 - */ - public static byte[] decode(String input) { - BigInteger bi = BigInteger.ZERO; - for (int i = input.length() - 1; i >= 0; i--) { - int index = ALPHABET.indexOf(input.charAt(i)); - if (index == -1) { - throw new IllegalArgumentException(); - } - bi = bi.add(BASE.pow(input.length() - 1 - i).multiply(BigInteger.valueOf(index))); - } - byte[] bytes = bi.toByteArray(); - boolean stripSignByte = bytes.length > 1 && bytes[0] == 0 && bytes[1] < 0; - int leadingZeros = 0; - for (; leadingZeros < input.length() && input.charAt(leadingZeros) == ALPHABET.charAt(0); leadingZeros++); - byte[] tmp = new byte[bytes.length - (stripSignByte ? 1 : 0) + leadingZeros]; - System.arraycopy(bytes, stripSignByte ? 1 : 0, tmp, leadingZeros, tmp.length - leadingZeros); - return tmp; - } - - /** - * 编码 - * 要编码的字节数组 - * 返回编码后的字符串 - */ - public static String encode(byte[] input) { - BigInteger value = new BigInteger(1, input); - StringBuilder sb = new StringBuilder(); - while (value.compareTo(BASE) >= 0) { - BigInteger[] r = value.divideAndRemainder(BASE); - sb.insert(0, ALPHABET.charAt(r[1].intValue())); - value = r[0]; - } - sb.insert(0, ALPHABET.charAt(value.intValue())); - for (byte b : input) { - if (b == 0) { - sb.insert(0, ALPHABET.charAt(0)); - } else { - break; - } - } - return sb.toString(); - } -} diff --git a/src/main/java/DNA/Cryptography/Digest.java b/src/main/java/DNA/Cryptography/Digest.java deleted file mode 100644 index 6a16c43..0000000 --- a/src/main/java/DNA/Cryptography/Digest.java +++ /dev/null @@ -1,46 +0,0 @@ -package DNA.Cryptography; - -import java.security.*; - -import org.bouncycastle.jce.provider.BouncyCastleProvider; - -public class Digest { - static { - Security.addProvider(new BouncyCastleProvider()); - } - - public static byte[] hash160(byte[] value) { - return ripemd160(sha256(value)); - } - - public static byte[] hash256(byte[] value) { - return sha256(sha256(value)); - } - - public static byte[] ripemd160(byte[] value) { - try { - MessageDigest md = MessageDigest.getInstance("RipeMD160"); - return md.digest(value); - } catch (NoSuchAlgorithmException ex) { - throw new RuntimeException(ex); - } - } - - public static byte[] sha256(byte[] value) { - try { - MessageDigest md = MessageDigest.getInstance("SHA-256"); - return md.digest(value); - } catch (NoSuchAlgorithmException ex) { - throw new RuntimeException(ex); - } - } - - public static byte[] sha256(byte[] value, int offset, int length) { - if (offset != 0 || length != value.length) { - byte[] array = new byte[length]; - System.arraycopy(value, offset, array, 0, length); - value = array; - } - return sha256(value); - } -} diff --git a/src/main/java/DNA/Cryptography/ECC.java b/src/main/java/DNA/Cryptography/ECC.java deleted file mode 100644 index c6ae609..0000000 --- a/src/main/java/DNA/Cryptography/ECC.java +++ /dev/null @@ -1,43 +0,0 @@ -package DNA.Cryptography; - -import java.security.*; - -import org.bouncycastle.asn1.x9.*; -import org.bouncycastle.crypto.params.ECDomainParameters; -import org.bouncycastle.math.ec.ECPoint; - -import DNA.Helper; - -public class ECC { - private static final X9ECParameters secp256r1nc = ECNamedCurveTable.getByName("secp256r1"); - public static final ECDomainParameters secp256r1 = new ECDomainParameters(secp256r1nc.getCurve(), secp256r1nc.getG(), secp256r1nc.getN(), secp256r1nc.getH(), secp256r1nc.getSeed()); - - public static int compare(ECPoint a, ECPoint b) { - if (a == b) { - return 0; - } - int result = a.getXCoord().toBigInteger().compareTo(b.getXCoord().toBigInteger()); - if (result != 0) { - return result; - } - return a.getYCoord().toBigInteger().compareTo(b.getYCoord().toBigInteger()); - } - - public static byte[] generateKey(int len) { - byte[] key = new byte[len]; - SecureRandom sr = new SecureRandom(); - sr.nextBytes(key); - return key; - } - - public static byte[] generateKey() { - byte[] key = new byte[32]; - SecureRandom sr = new SecureRandom(); - sr.nextBytes(key); - return key; - } - - public static String toString(ECPoint p) { - return Helper.toHexString(p.getEncoded(true)); - } -} diff --git a/src/main/java/DNA/Helper.java b/src/main/java/DNA/Helper.java deleted file mode 100644 index 90f8edf..0000000 --- a/src/main/java/DNA/Helper.java +++ /dev/null @@ -1,68 +0,0 @@ -package DNA; - -import java.text.SimpleDateFormat; -import java.util.Arrays; -import java.util.Date; - -/** - * Byte Handle Helper - * - * @author 12146 - * @since JDK1.8 - */ -public class Helper { - public static String getbyteStr(byte[] bs) { - StringBuilder sb = new StringBuilder(); - for(byte b: bs) { - sb.append(" ").append(Byte.toUnsignedInt(b)); - } - return sb.substring(1); - } - - public static byte[] reverse(byte[] v) { - byte[] result = new byte[v.length]; - for (int i = 0; i < v.length; i++) { - result[i] = v[v.length - i - 1]; - } - return result; - } - - public static byte[] hexToBytes(String value) { - if (value == null || value.length() == 0) { - return new byte[0]; - } - if (value.length() % 2 == 1) { - throw new IllegalArgumentException(); - } - byte[] result = new byte[value.length() / 2]; - for (int i = 0; i < result.length; i++) { - result[i] = (byte) Integer.parseInt(value.substring(i * 2, i * 2 + 2), 16); - } - return result; - } - - public static String toHexString(byte[] value) { - StringBuilder sb = new StringBuilder(); - for (byte b : value) { - int v = Byte.toUnsignedInt(b); - sb.append(Integer.toHexString(v >>> 4)); - sb.append(Integer.toHexString(v & 0x0f)); - } - return sb.toString(); - } - - public static String reverse(String value) { - return toHexString(reverse(hexToBytes(value))); - } - - public static byte[] removePrevZero(byte[] bt) { - if(bt.length == 33 && bt[0] == 0) { - return Arrays.copyOfRange(bt, 1, 33); - } - return bt; - } - - public static String now() { - return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()); - } -} diff --git a/src/main/java/DNA/IO/BinaryReader.java b/src/main/java/DNA/IO/BinaryReader.java deleted file mode 100644 index f6bd173..0000000 --- a/src/main/java/DNA/IO/BinaryReader.java +++ /dev/null @@ -1,163 +0,0 @@ -package DNA.IO; - -import java.io.*; -import java.lang.reflect.Array; -import java.nio.*; - -import org.bouncycastle.math.ec.ECPoint; - -import DNA.Cryptography.ECC; - -public class BinaryReader implements AutoCloseable { - private DataInputStream reader; - private byte[] array = new byte[8]; - private ByteBuffer buffer = ByteBuffer.wrap(array).order(ByteOrder.LITTLE_ENDIAN); - - public BinaryReader(InputStream stream) { - this.reader = new DataInputStream(stream); - } - - @Override - public void close() throws IOException { - reader.close(); - } - - public void mark(int readlimit) { - reader.mark(readlimit); - } - - public void reset() throws IOException { - reader.reset(); - } - - - public void read(byte[] buffer) throws IOException { - reader.readFully(buffer); - } - - public void read(byte[] buffer, int index, int length) throws IOException { - reader.readFully(buffer, index, length); - } - - public boolean readBoolean() throws IOException { - return reader.readBoolean(); - } - - public byte readByte() throws IOException { - return reader.readByte(); - } - - public byte[] readBytes(int count) throws IOException { - byte[] buffer = new byte[count]; - reader.readFully(buffer); - return buffer; - } - - public double readDouble() throws IOException { - reader.readFully(array, 0, 8); - return buffer.getDouble(0); - } - - public ECPoint readECPoint() throws IOException { - byte[] encoded; - byte fb = reader.readByte(); - switch (fb) - { - case 0x00: - encoded = new byte[1]; - break; - case 0x02: - case 0x03: - encoded = new byte[33]; - encoded[0] = fb; - reader.readFully(encoded, 1, 32); - break; - case 0x04: - encoded = new byte[65]; - encoded[0] = fb; - reader.readFully(encoded, 1, 64); - break; - default: - throw new IOException(); - } - return ECC.secp256r1.getCurve().decodePoint(encoded); - } - - public String readFixedString(int length) throws IOException { - byte[] data = readBytes(length); - int count = -1; - while (data[++count] != 0); - return new String(data, 0, count, "UTF-8"); - } - - public float readFloat() throws IOException { - reader.readFully(array, 0, 4); - return buffer.getFloat(0); - } - - public int readInt() throws IOException { - reader.readFully(array, 0, 4); - return buffer.getInt(0); - } - - public long readLong() throws IOException { - reader.readFully(array, 0, 8); - return buffer.getLong(0); - } - - public T readSerializable(Class t) throws InstantiationException, IllegalAccessException, IOException { - T obj = t.newInstance(); - obj.deserialize(this); - return obj; - } - - public T[] readSerializableArray(Class t) throws InstantiationException, IllegalAccessException, IOException { - @SuppressWarnings("unchecked") - T[] array = (T[])Array.newInstance(t, (int)readVarInt(0x10000000)); -// System.out.println("arr.len==="+array.length); - for (int i = 0; i < array.length; i++) { - array[i] = t.newInstance(); - array[i].deserialize(this); - } - return array; - } - - public short readShort() throws IOException { - reader.readFully(array, 0, 2); - return buffer.getShort(0); - } - - public byte[] readVarBytes() throws IOException { - return readVarBytes(0X7fffffc7); - } - - public byte[] readVarBytes(int max) throws IOException { - return readBytes((int)readVarInt(max)); - } - - public long readVarInt() throws IOException { - return readVarInt(Long.MAX_VALUE); - } - - public long readVarInt(long max) throws IOException { - long fb = Byte.toUnsignedLong(readByte()); - long value; - if (fb == 0xFD) { - value = Short.toUnsignedLong(readShort()); - } else if (fb == 0xFE) { - value = Integer.toUnsignedLong(readInt()); - } else if (fb == 0xFF) { - value = readLong(); - } else { - value = fb; - } - if (Long.compareUnsigned(value, max) > 0) { - throw new IOException(); - } - return value; - } - - public String readVarString() throws IOException { - return new String(readVarBytes(), "UTF-8"); - } -} diff --git a/src/main/java/DNA/IO/Caching/ITrackable.java b/src/main/java/DNA/IO/Caching/ITrackable.java deleted file mode 100644 index 3b492d8..0000000 --- a/src/main/java/DNA/IO/Caching/ITrackable.java +++ /dev/null @@ -1,7 +0,0 @@ -package DNA.IO.Caching; - -public interface ITrackable { - TKey key(); - TrackState getTrackState(); - void setTrackState(TrackState state); -} diff --git a/src/main/java/DNA/IO/Caching/TrackState.java b/src/main/java/DNA/IO/Caching/TrackState.java deleted file mode 100644 index bb64fd6..0000000 --- a/src/main/java/DNA/IO/Caching/TrackState.java +++ /dev/null @@ -1,8 +0,0 @@ -package DNA.IO.Caching; - -public enum TrackState { - None, - Added, - Changed, - Deleted -} diff --git a/src/main/java/DNA/IO/Caching/TrackableCollection.java b/src/main/java/DNA/IO/Caching/TrackableCollection.java deleted file mode 100644 index 3d14c64..0000000 --- a/src/main/java/DNA/IO/Caching/TrackableCollection.java +++ /dev/null @@ -1,79 +0,0 @@ -package DNA.IO.Caching; - -import java.util.*; -import java.util.function.IntFunction; - -public class TrackableCollection> extends AbstractCollection { - private HashMap map = new HashMap(); - - public TrackableCollection() { } - - public TrackableCollection(TItem[] items) { - for (TItem item : items) { - this.add(item); - item.setTrackState(TrackState.None); - } - } - - @Override - public void clear() { - map.clear(); - } - - @Override - public boolean add(TItem e) { - e.setTrackState(TrackState.Added); - return map.put(e.key(), e) == null; - } - - public boolean remove(TItem key) { - TItem item = map.get(key); - if (item == null) { - return false; - } - if (item.getTrackState() == TrackState.Added) { - map.remove(key); - } else { - item.setTrackState(TrackState.Deleted); - } - return true; - } - - public void commit() { - Iterator iterator = map.values().iterator(); - while (iterator.hasNext()) { - TItem item = iterator.next(); - if (item.getTrackState() == TrackState.Deleted) { - iterator.remove(); - } else { - item.setTrackState(TrackState.None); - } - } - } - - public boolean containsKey(TKey key) { - return map.containsKey(key); - } - - public boolean containsValue(TItem item) { - return containsKey(item.key()); - } - - public TItem get(TKey key) { - return map.get(key); - } - - public TItem[] getChangeSet(IntFunction generator) { - return map.values().stream().filter(p -> p.getTrackState() != TrackState.None).toArray(generator); - } - - @Override - public Iterator iterator() { - return map.values().iterator(); - } - - @Override - public int size() { - return map.size(); - } -} \ No newline at end of file diff --git a/src/main/java/DNA/IO/Json/JArray.java b/src/main/java/DNA/IO/Json/JArray.java deleted file mode 100644 index 52b6768..0000000 --- a/src/main/java/DNA/IO/Json/JArray.java +++ /dev/null @@ -1,191 +0,0 @@ -package DNA.IO.Json; - -import java.io.*; -import java.util.*; - -public class JArray extends JObject implements List { - private List items = new ArrayList(); - - public JArray(JObject ...items) { - this.items.addAll(Arrays.asList(items)); - } - - public JArray(Collection items) { - this.items.addAll(items); - } - - @Override - public boolean add(JObject item) { - return items.add(item); - } - - @Override - public void add(int index, JObject element) { - items.add(index, element); - } - - @Override - public boolean addAll(Collection c) { - return items.addAll(c); - } - - @Override - public boolean addAll(int index, Collection c) { - return items.addAll(index, c); - } - - @Override - public void clear() { - items.clear(); - } - - @Override - public boolean contains(Object item) { - return items.contains(item); - } - - @Override - public boolean containsAll(Collection c) { - return items.containsAll(c); - } - - @Override - public boolean equals(Object o) { - if (o == null) { - return false; - } - if (!(o instanceof JArray)) { - return false; - } - JArray array = (JArray)o; - return this.items.equals(array.items); - } - - @Override - public JObject get(int index) { - return items.get(index); - } - - @Override - public int hashCode() { - return items.hashCode(); - } - - @Override - public int indexOf(Object o) { - return items.indexOf(o); - } - - @Override - public boolean isEmpty() { - return items.isEmpty(); - } - - @Override - public Iterator iterator() { - return items.iterator(); - } - - @Override - public int lastIndexOf(Object o) { - return items.lastIndexOf(o); - } - - @Override - public ListIterator listIterator() { - return items.listIterator(); - } - - @Override - public ListIterator listIterator(int index) { - return items.listIterator(index); - } - - static JArray parseArray(BufferedReader reader) throws IOException { - skipSpace(reader); - if (reader.read() != '[') { - throw new IOException(); - } - skipSpace(reader); - JArray array = new JArray(); - while (true) { - reader.mark(1); - int c = reader.read(); - if (c == ']') { - break; - } - if (c != ',') { - reader.reset(); - } - JObject obj = JObject.parse(reader); - array.items.add(obj); - skipSpace(reader); - } - return array; - } - - @Override - public JObject remove(int index) { - return items.remove(index); - } - - @Override - public boolean remove(Object item) { - return items.remove(item); - } - - @Override - public boolean removeAll(Collection c) { - return items.removeAll(c); - } - - @Override - public boolean retainAll(Collection c) { - return items.retainAll(c); - } - - @Override - public JObject set(int index, JObject jobj) { - return items.set(index, jobj); - } - - @Override - public int size() { - return items.size(); - } - - @Override - public List subList(int fromIndex, int toIndex) { - return items.subList(fromIndex, toIndex); - } - - @Override - public Object[] toArray() { - return items.toArray(); - } - - @Override - public T[] toArray(T[] a) { - return items.toArray(a); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append('['); - for (JObject item : items) { - if (item == null) { - sb.append("null"); - } else { - sb.append(item); - } - sb.append(','); - } - if (items.size() == 0) { - sb.append(']'); - } else { - sb.setCharAt(sb.length() - 1, ']'); - } - return sb.toString(); - } -} diff --git a/src/main/java/DNA/IO/Json/JBigInt.java b/src/main/java/DNA/IO/Json/JBigInt.java deleted file mode 100644 index 27cebad..0000000 --- a/src/main/java/DNA/IO/Json/JBigInt.java +++ /dev/null @@ -1,69 +0,0 @@ -package DNA.IO.Json; - -import java.io.BufferedReader; -import java.io.IOException; -import java.math.BigInteger; - -public class JBigInt extends JObject{ - private BigInteger _value; - public BigInteger value() { - return _value; - } - - public JBigInt(String val) { - this._value = new BigInteger(val); - } - - @Override - public boolean asBoolean() { - if (_value.intValue() == 0) { - return false; - } - return true; - } - - @Override - public double asNumber() { - return _value.doubleValue(); - } - - @Override - public String asString() { - return _value.toString(); - } - - @Override - public boolean canConvertTo(Class type) { - if (type.equals(boolean.class)) { - return true; - } - if (type.equals(double.class)) { - return true; - } - if (type.equals(String.class)) { - return true; - } - return false; - } - - static JBigInt parseNumber(BufferedReader reader) throws IOException { - skipSpace(reader); - StringBuilder sb = new StringBuilder(); - while (true) { - reader.mark(1); - int c = reader.read(); - if (c >= '0' && c <= '9' || c == '.' || c == '-') { - sb.append((char)c); - } else { - reader.reset(); - break; - } - } - return new JBigInt(sb.toString()); - } - - @Override - public String toString() { - return asString(); - } -} diff --git a/src/main/java/DNA/IO/Json/JBoolean.java b/src/main/java/DNA/IO/Json/JBoolean.java deleted file mode 100644 index c9cdb5e..0000000 --- a/src/main/java/DNA/IO/Json/JBoolean.java +++ /dev/null @@ -1,62 +0,0 @@ -package DNA.IO.Json; - -import java.io.*; - -public class JBoolean extends JObject { - private final boolean _value; - public boolean value() { - return _value; - } - - public JBoolean(boolean val) { - this._value = val; - } - - @Override - public boolean asBoolean() { - return _value; - } - - @Override - public String asString() { - return String.valueOf(_value).toLowerCase(); - } - - @Override - public boolean canConvertTo(Class type) { - if (type.equals(boolean.class)) { - return true; - } - if (type.equals(String.class)) { - return true; - } - return false; - } - - static JBoolean parseBoolean(BufferedReader reader) throws IOException { - skipSpace(reader); - int firstChar = reader.read(); - if (firstChar == 't') { - int c2 = reader.read(); - int c3 = reader.read(); - int c4 = reader.read(); - if (c2 == 'r' && c3 == 'u' && c4 == 'e') { - return new JBoolean(true); - } - } else if (firstChar == 'f') { - int c2 = reader.read(); - int c3 = reader.read(); - int c4 = reader.read(); - int c5 = reader.read(); - if (c2 == 'a' && c3 == 'l' && c4 == 's' && c5 == 'e') { - return new JBoolean(false); - } - } - throw new IOException(); - } - - @Override - public String toString() { - return asString(); - } -} \ No newline at end of file diff --git a/src/main/java/DNA/IO/Json/JNumber.java b/src/main/java/DNA/IO/Json/JNumber.java deleted file mode 100644 index 3916ac2..0000000 --- a/src/main/java/DNA/IO/Json/JNumber.java +++ /dev/null @@ -1,68 +0,0 @@ -package DNA.IO.Json; - -import java.io.BufferedReader; -import java.io.IOException; - -public class JNumber extends JObject { - private double _value; - public double value() { - return _value; - } - - public JNumber(double val) { - this._value = val; - } - - @Override - public boolean asBoolean() { - if (_value == 0) { - return false; - } - return true; - } - - @Override - public double asNumber() { - return _value; - } - - @Override - public String asString() { - return String.valueOf(_value); - } - - @Override - public boolean canConvertTo(Class type) { - if (type.equals(boolean.class)) { - return true; - } - if (type.equals(double.class)) { - return true; - } - if (type.equals(String.class)) { - return true; - } - return false; - } - - static JNumber parseNumber(BufferedReader reader) throws IOException { - skipSpace(reader); - StringBuilder sb = new StringBuilder(); - while (true) { - reader.mark(1); - int c = reader.read(); - if (c >= '0' && c <= '9' || c == '.' || c == '-') { - sb.append((char)c); - } else { - reader.reset(); - break; - } - } - return new JNumber(Double.parseDouble(sb.toString())); - } - - @Override - public String toString() { - return asString(); - } -} diff --git a/src/main/java/DNA/IO/Json/JObject.java b/src/main/java/DNA/IO/Json/JObject.java deleted file mode 100644 index ae6b69c..0000000 --- a/src/main/java/DNA/IO/Json/JObject.java +++ /dev/null @@ -1,180 +0,0 @@ -package DNA.IO.Json; - -import java.io.*; -import java.util.*; -import java.util.Map.Entry; - -public class JObject { - public static final JObject NULL = null; - private Map properties = new HashMap(); - - public int size() { - return properties.size(); - } - - public JObject get(String name) { - return properties.get(name); - } - - public void set(String name, JObject value) { - properties.put(name, value); - } - - public boolean asBoolean() { - throw new UnsupportedOperationException(); - } - - public boolean asBooleanOrDefault(boolean value) { - if (!canConvertTo(boolean.class)) - return value; - return asBoolean(); - } - - @SuppressWarnings("rawtypes") - public T asEnum(boolean ignoreCase) { - throw new UnsupportedOperationException(); - } - - @SuppressWarnings("rawtypes") - public T asEnumOrDefault(T value, boolean ignoreCase) { - if (!canConvertTo(value.getClass())) - return value; - return asEnum(ignoreCase); - } - - public double asNumber() { - throw new UnsupportedOperationException(); - } - - public double asNumberOrDefault(double value) { - if (!canConvertTo(double.class)) - return value; - return asNumber(); - } - - public String asString() { - throw new UnsupportedOperationException(); - } - - public String asStringOrDefault(String value) { - if (!canConvertTo(String.class)) { - return value; - } - return asString(); - } - - public boolean canConvertTo(Class type) { - return false; - } - - public boolean containsProperty(String key) { - return properties.containsKey(key); - } - - public static JObject parse(Reader reader2) throws IOException { - BufferedReader r = reader2 instanceof BufferedReader ? (BufferedReader)reader2 : new BufferedReader(reader2); - skipSpace(r); - r.mark(1); - int firstChar = r.read(); - if (firstChar == '\"' || firstChar == '\'') { - r.reset(); - return JString.parseString(r); - } - if (firstChar == '[') { - r.reset(); - return JArray.parseArray(r); - } - if ((firstChar >= '0' && firstChar <= '9') || firstChar == '-') { - r.reset(); - return JNumber.parseNumber(r); - } - if (firstChar == 't' || firstChar == 'f') { - r.reset(); - return JBoolean.parseBoolean(r); - } - if (firstChar == 'n') { - r.reset(); - return parseNull(r); - } - if (firstChar != '{') throw new IOException(); - skipSpace(r); - JObject obj = new JObject(); - while (true) { - r.mark(1); - int c = r.read(); - if (c == '}') { - break; - } - if (c != ',') { - r.reset(); - } - skipSpace(r); - String name = JString.parseString(r).value(); - skipSpace(r); - if (r.read() != ':') { - throw new IOException(); - } - JObject value = parse(r); - obj.properties.put(name, value); - skipSpace(r); - } - return obj; - } - - public static JObject parse(String value) { - StringReader reader = new StringReader(value); - try { - return parse(reader); - } catch (IOException ex) { - throw new IllegalArgumentException(ex); - } - } - - static JObject parseNull(Reader reader) throws IOException { - char firstChar = (char)reader.read(); - if (firstChar == 'n') { - int c2 = reader.read(); - int c3 = reader.read(); - int c4 = reader.read(); - if (c2 == 'u' && c3 == 'l' && c4 == 'l') { - return null; - } - } - throw new IllegalArgumentException(); - } - - protected static void skipSpace(BufferedReader reader) throws IOException { - while (true) { - reader.mark(1); - int c = reader.read(); - if (c != ' ' && c != '\r' && c != '\n') { - reader.reset(); - return; - } - } - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append('{'); - for (Entry pair : properties.entrySet()) { - sb.append('"'); - sb.append(pair.getKey()); - sb.append('"'); - sb.append(':'); - if (pair.getValue() == null) { - sb.append("null"); - } else { - sb.append(pair.getValue()); - } - sb.append(','); - } - if (properties.size() == 0) { - sb.append('}'); - } else { - sb.setCharAt(sb.length() - 1, '}'); - } - return sb.toString(); - } -} diff --git a/src/main/java/DNA/IO/Json/JString.java b/src/main/java/DNA/IO/Json/JString.java deleted file mode 100644 index 07dc35a..0000000 --- a/src/main/java/DNA/IO/Json/JString.java +++ /dev/null @@ -1,85 +0,0 @@ -package DNA.IO.Json; - -import java.io.*; -import java.util.*; - -public class JString extends JObject { - private String _value; - public String value() { - return _value; - } - - public JString(String val) { - if (val == null) { - throw new NullPointerException(); - } - this._value = val; - } - - @Override - public boolean asBoolean() { - Collection falseValues = new HashSet(); - falseValues.add("0"); - falseValues.add("f"); - falseValues.add("false"); - falseValues.add("n"); - falseValues.add("no"); - falseValues.add("off"); - return ! falseValues.contains(_value.toLowerCase()); - } - - @Override - public double asNumber() { - return Double.parseDouble(_value); - } - - @Override - public String asString() { - return _value; - } - - @Override - public boolean canConvertTo(Class type) { - if (type.equals(boolean.class)) { - return true; - } - if (type.equals(double.class)) { - return true; - } - if (type.equals(String.class)) { - return true; - } - return false; - } - - static JString parseString(BufferedReader reader) throws IOException { - skipSpace(reader); - char[] buffer = new char[4]; - int firstChar = reader.read(); - if (firstChar != '\"' && firstChar != '\'') throw new IOException(); - StringBuilder sb = new StringBuilder(); - while (true) { - int c = reader.read(); - if (c == 65535) { - throw new IOException(); - } - if (c == firstChar) { - break; - } - if (c == '\\') { - c = (char)reader.read(); - if (c == 'u') { - reader.read(buffer, 0, 4); - c = Integer.valueOf(new String(buffer), 16); - } - } - sb.append((char)c); - } - return new JString(sb.toString()); - } - - @Override - public String toString() { - return "\"" + _value.replaceAll("\"", "\\\"") + "\""; - } -} \ No newline at end of file diff --git a/src/main/java/DNA/IO/JsonReader.java b/src/main/java/DNA/IO/JsonReader.java deleted file mode 100644 index 2d44076..0000000 --- a/src/main/java/DNA/IO/JsonReader.java +++ /dev/null @@ -1,36 +0,0 @@ -package DNA.IO; - -import java.io.IOException; -import java.lang.reflect.Array; - -import DNA.IO.Json.JArray; -import DNA.IO.Json.JObject; - -public class JsonReader { - private JObject json; - - public JsonReader(JObject json) { - this.json = json; - } - - public T readSerializable(Class t) throws InstantiationException, IllegalAccessException, IOException { - T obj = t.newInstance(); - obj.fromJson(this); - return obj; - } - - @SuppressWarnings("unchecked") - public T[] readSerializableArray(Class t, int count, String field) throws InstantiationException, IllegalAccessException, IOException { - JArray jsonArr = (JArray)json.get(field); - T[] array = (T[])Array.newInstance(t, count); - for (int i = 0; i < count; i++) { - array[i] = t.newInstance(); - array[i].fromJson(new JsonReader(jsonArr.get(i))); - } - return array; - } - - public JObject json() { - return json; - } -} diff --git a/src/main/java/DNA/IO/JsonSerializable.java b/src/main/java/DNA/IO/JsonSerializable.java deleted file mode 100644 index 74e8b1b..0000000 --- a/src/main/java/DNA/IO/JsonSerializable.java +++ /dev/null @@ -1,28 +0,0 @@ -package DNA.IO; - -import java.io.IOException; - -import DNA.IO.Json.JObject; - -public interface JsonSerializable { - public void toJson(JsonWriter writer); - public void fromJson(JsonReader reader); - - // 序列化 - default JObject to() { - JsonWriter writer = new JsonWriter(new JObject()); - toJson(writer); - return writer.json(); - } - - // 反序列化 - static T from(JObject json, Class t) throws InstantiationException, IllegalAccessException { - JsonReader reader = new JsonReader(json); - try { - return reader.readSerializable(t); - } catch (IOException e) { - throw new IllegalArgumentException(e); - } - } - -} diff --git a/src/main/java/DNA/IO/JsonWriter.java b/src/main/java/DNA/IO/JsonWriter.java deleted file mode 100644 index 0b99ba8..0000000 --- a/src/main/java/DNA/IO/JsonWriter.java +++ /dev/null @@ -1,27 +0,0 @@ -package DNA.IO; - -import java.io.IOException; - -import DNA.IO.Json.JObject; - -public class JsonWriter { - private JObject json; - - public JsonWriter(JObject json) { - this.json = json; - } - public void writeSerializable(JsonSerializable v) throws IOException { - v.toJson(this); - } - - public void writeSerializableArray(JsonSerializable[] v) throws IOException { - for (int i = 0; i < v.length; i++) { - v[i].toJson(this); - } - } - - public JObject json() { - return json; - } - -} diff --git a/src/main/java/DNA/IO/Serializable.java b/src/main/java/DNA/IO/Serializable.java deleted file mode 100644 index 86638e9..0000000 --- a/src/main/java/DNA/IO/Serializable.java +++ /dev/null @@ -1,44 +0,0 @@ -package DNA.IO; - -import java.io.*; - -/** - * 为序列化提供一个接口 - */ -public interface Serializable { - /** - * 反序列化 - * 数据来源 - * @throws IOException - */ - void deserialize(BinaryReader reader) throws IOException; - - /** - * 序列化 - * 存放序列化后的结果 - * @throws IOException - */ - void serialize(BinaryWriter writer) throws IOException; - - default byte[] toArray() { - try (ByteArrayOutputStream ms = new ByteArrayOutputStream()) { - try (BinaryWriter writer = new BinaryWriter(ms)) { - serialize(writer); - writer.flush(); - return ms.toByteArray(); - } - } catch (IOException ex) { - throw new UnsupportedOperationException(ex); - } - } - - static T from(byte[] value, Class t) throws InstantiationException, IllegalAccessException { - try (ByteArrayInputStream ms = new ByteArrayInputStream(value)) { - try (BinaryReader reader = new BinaryReader(ms)) { - return reader.readSerializable(t); - } - } catch (IOException ex) { - throw new IllegalArgumentException(ex); - } - } -} diff --git a/src/main/java/DNA/IVersion.java b/src/main/java/DNA/IVersion.java deleted file mode 100644 index bc07cfd..0000000 --- a/src/main/java/DNA/IVersion.java +++ /dev/null @@ -1,20 +0,0 @@ -package DNA; - -/** - * SDK Version Info - * - * @author 12146 - * @since JDK1.8 - * - */ -public class IVersion { - private static final String version = "sdk-v0.6"; - public static final String[] versionInfo = new String[] { - "project:" + "DNA SDK", - "version:" + version, - "description:"+ "This version is suitable for DNA-v0.6alpha, named sdk-v0.6", - "lastModified:"+"2017-07-10", - "author:"+"ts" - }; - -} diff --git a/src/main/java/DNA/Implementations/Blockchains/Rest/RestBlockchain.java b/src/main/java/DNA/Implementations/Blockchains/Rest/RestBlockchain.java deleted file mode 100644 index d8796f4..0000000 --- a/src/main/java/DNA/Implementations/Blockchains/Rest/RestBlockchain.java +++ /dev/null @@ -1,159 +0,0 @@ -package DNA.Implementations.Blockchains.Rest; - -import java.util.EnumSet; -import java.util.Map; -import java.util.stream.Stream; - -import DNA.Fixed8; -import DNA.UInt256; -import DNA.Core.Block; -import DNA.Core.Blockchain; -import DNA.Core.BlockchainAbility; -import DNA.Core.Claimable; -import DNA.Core.RegisterTransaction; -import DNA.Core.Transaction; -import DNA.Core.TransactionOutput; -import DNA.Core.Vote; -import DNA.Network.Rest.RestNode; - -public class RestBlockchain extends Blockchain { - private RestNode rest; - public RestBlockchain(RestNode rest) { - this.rest = rest; - } - @Override - public EnumSet ability() { - return BlockchainAbility.None; - } - - @Override - public int height() throws Exception { - return rest.getBlockHeight(); - } - - @Override - public Block getBlock(int height) throws Exception { - return rest.getBlock(height); - } - - public int getBlockHeightFromDb() throws Exception { - return rest.getBlockHeightFromDb(); - } - @Override - public Block getBlockFromDb(int height) throws Exception { - return rest.getBlockFromDb(height); - } - - @Override - public Block getBlock(UInt256 hash) throws Exception { - return rest.getBlock(hash.toString()); - } - - @Override - public Transaction getTransaction(UInt256 hash) throws Exception { - return rest.getRawTransaction(hash.toString()); - } - - @Override - public UInt256 currentBlockHash() throws Exception { - // TODO Auto-generated method stub - return null; - } - - @Override - public boolean isReadOnly() { - // TODO Auto-generated method stub - return false; - } - - @Override - protected boolean addBlock(Block block) { - // TODO Auto-generated method stub - return false; - } - - @Override - protected void addHeaders(Iterable headers) { - // TODO Auto-generated method stub - - } - - @Override - public void close() { - // TODO Auto-generated method stub - - } - - @Override - public boolean containsUnspent(UInt256 hash, int index) throws Exception { - // TODO Auto-generated method stub - return false; - } - - @Override - public Stream getAssets() { - // TODO Auto-generated method stub - return null; - } - - @Override - public UInt256[] getLeafHeaderHashes() { - // TODO Auto-generated method stub - return null; - } - - @Override - public Block getNextBlock(UInt256 hash) { - // TODO Auto-generated method stub - return null; - } - - @Override - public UInt256 getNextBlockHash(UInt256 hash) { - // TODO Auto-generated method stub - return null; - } - - @Override - public Fixed8 getQuantityIssued(UInt256 asset_id) { - // TODO Auto-generated method stub - return null; - } - - @Override - public long getSysFeeAmount(UInt256 hash) { - // TODO Auto-generated method stub - return 0; - } - - @Override - public Map getUnclaimed(UInt256 hash) { - // TODO Auto-generated method stub - return null; - } - - @Override - public TransactionOutput getUnspent(UInt256 hash, int index) - throws Exception { - // TODO Auto-generated method stub - return null; - } - - @Override - public Stream getVotes(Stream others) { - // TODO Auto-generated method stub - return null; - } - - @Override - public boolean isDoubleSpend(Transaction tx) { - // TODO Auto-generated method stub - return false; - } - @Override - public UInt256 getBlockHash(int height) { - // TODO Auto-generated method stub - return null; - } - -} diff --git a/src/main/java/DNA/Implementations/Wallets/AbstractWallet.java b/src/main/java/DNA/Implementations/Wallets/AbstractWallet.java deleted file mode 100644 index 34d7dd0..0000000 --- a/src/main/java/DNA/Implementations/Wallets/AbstractWallet.java +++ /dev/null @@ -1,65 +0,0 @@ -package DNA.Implementations.Wallets; - -import javax.crypto.BadPaddingException; -import javax.crypto.IllegalBlockSizeException; - -import DNA.Core.Block; -import DNA.Core.Transaction; -import DNA.Wallets.Account; -import DNA.Wallets.Coin; -import DNA.Wallets.Contract; -import DNA.Wallets.Wallet; - - -public class AbstractWallet extends Wallet { - - protected AbstractWallet(String path, String password, boolean create) - throws BadPaddingException, IllegalBlockSizeException { - super(path, password, create); - } - - @Override - protected Account[] loadAccounts() { - // TODO Auto-generated method stub - return null; - } - - @Override - protected Contract[] loadContracts() { - // TODO Auto-generated method stub - return null; - } - - @Override - protected Coin[] loadCoins() { - // TODO Auto-generated method stub - return null; - } - - @Override - protected byte[] loadStoredData(String name) { - // TODO Auto-generated method stub - return null; - } - - @Override - protected void saveStoredData(String name, byte[] value) { - // TODO Auto-generated method stub - - } - - @Override - protected void onProcessNewBlock(Block block, Coin[] added, Coin[] changed, - Coin[] deleted) { - // TODO Auto-generated method stub - - } - - @Override - protected void onSaveTransaction(Transaction tx, Coin[] added, - Coin[] changed) { - // TODO Auto-generated method stub - - } - -} diff --git a/src/main/java/DNA/Implementations/Wallets/AccountStoreType.java b/src/main/java/DNA/Implementations/Wallets/AccountStoreType.java deleted file mode 100644 index 3d25d8f..0000000 --- a/src/main/java/DNA/Implementations/Wallets/AccountStoreType.java +++ /dev/null @@ -1,28 +0,0 @@ -package DNA.Implementations.Wallets; - -public enum AccountStoreType { - SQLITE(0x01), - MYSQL(0x02), - ORACLE(0x02), - - ; - - private byte value; - - public int value() { - return value; - } - - AccountStoreType(int value) { - this.value = (byte)value; - } - - public static AccountStoreType from(int type) { - for(AccountStoreType tt: AccountStoreType.values()) { - if(tt.value == type) { - return tt; - } - } - throw new IllegalArgumentException(); - } -} diff --git a/src/main/java/DNA/Implementations/Wallets/IUserManager.java b/src/main/java/DNA/Implementations/Wallets/IUserManager.java deleted file mode 100644 index f88bb9f..0000000 --- a/src/main/java/DNA/Implementations/Wallets/IUserManager.java +++ /dev/null @@ -1,57 +0,0 @@ -package DNA.Implementations.Wallets; - -import java.util.Map; - -import DNA.Fixed8; -import DNA.UInt160; -import DNA.Core.SignatureContext; -import DNA.Core.Transaction; -import DNA.Wallets.Account; -import DNA.Wallets.Coin; -import DNA.Wallets.CoinException; -import DNA.Wallets.Contract; - -public interface IUserManager { - - public void start(); - - public void close(); - - public Account createAccount(); - - public Account createAccount(byte[] privateKey); - - public Contract getContract(String address); - - public Account[] getAccounts(); - - public Contract[] getContracts(); - - public void rebuild(); - - public T makeTransaction(T regTx,Fixed8 zero) throws CoinException; - - public T makeTransaction(T tx, Fixed8 fee, UInt160 from) throws CoinException; - - public boolean saveTransaction(Transaction tx); - - public boolean sign(SignatureContext context); - - public boolean hasFinishedSyncBlock() throws Exception; - - public Account getAccount(UInt160 publicKeyHash); - - public Account getAccountByScriptHash(UInt160 scriptHash); - - public Coin[] findUnspentCoins(); - - public Coin[] findUnconfirmedCoins(); - - public Map LoadTransactions(); - - public Coin[] getCoin(); - - public int getBlockHeight(); - public int getWalletHeight(); - -} diff --git a/src/main/java/DNA/Implementations/Wallets/SQLite/Account.java b/src/main/java/DNA/Implementations/Wallets/SQLite/Account.java deleted file mode 100644 index 4e0fc6f..0000000 --- a/src/main/java/DNA/Implementations/Wallets/SQLite/Account.java +++ /dev/null @@ -1,6 +0,0 @@ -package DNA.Implementations.Wallets.SQLite; - -public class Account { - public byte[] privateKeyEncrypted; - public byte[] publicKeyHash; -} diff --git a/src/main/java/DNA/Implementations/Wallets/SQLite/Coin.java b/src/main/java/DNA/Implementations/Wallets/SQLite/Coin.java deleted file mode 100644 index fc5d889..0000000 --- a/src/main/java/DNA/Implementations/Wallets/SQLite/Coin.java +++ /dev/null @@ -1,10 +0,0 @@ -package DNA.Implementations.Wallets.SQLite; - -class Coin { - public byte[] txid; - public int index; - public byte[] assetId; - public byte[] scriptHash; - public int state; - public long value; -} diff --git a/src/main/java/DNA/Implementations/Wallets/SQLite/Contract.java b/src/main/java/DNA/Implementations/Wallets/SQLite/Contract.java deleted file mode 100644 index d29aca0..0000000 --- a/src/main/java/DNA/Implementations/Wallets/SQLite/Contract.java +++ /dev/null @@ -1,7 +0,0 @@ -package DNA.Implementations.Wallets.SQLite; - -public class Contract { - public byte[] scriptHash; - public byte[] publicKeyHash; - public byte[] rawData; -} diff --git a/src/main/java/DNA/Implementations/Wallets/SQLite/Key.java b/src/main/java/DNA/Implementations/Wallets/SQLite/Key.java deleted file mode 100644 index c01c150..0000000 --- a/src/main/java/DNA/Implementations/Wallets/SQLite/Key.java +++ /dev/null @@ -1,6 +0,0 @@ -package DNA.Implementations.Wallets.SQLite; - -class Key { - public String name; - public byte[] value; -} diff --git a/src/main/java/DNA/Implementations/Wallets/SQLite/Transaction.java b/src/main/java/DNA/Implementations/Wallets/SQLite/Transaction.java deleted file mode 100644 index fd997af..0000000 --- a/src/main/java/DNA/Implementations/Wallets/SQLite/Transaction.java +++ /dev/null @@ -1,11 +0,0 @@ -package DNA.Implementations.Wallets.SQLite; - -import java.sql.Date; - -class Transaction { - public byte[] hash; - public byte type; - public byte[] rawData; - public int height; - public Date time; -} diff --git a/src/main/java/DNA/Implementations/Wallets/SQLite/TransactionInfo.java b/src/main/java/DNA/Implementations/Wallets/SQLite/TransactionInfo.java deleted file mode 100644 index 8fa7e8b..0000000 --- a/src/main/java/DNA/Implementations/Wallets/SQLite/TransactionInfo.java +++ /dev/null @@ -1,9 +0,0 @@ -package DNA.Implementations.Wallets.SQLite; - -import java.util.Date; - -public class TransactionInfo { - public DNA.Core.Transaction Transaction; - public Integer Height; - public Date Time; -} diff --git a/src/main/java/DNA/Implementations/Wallets/SQLite/UserWallet.java b/src/main/java/DNA/Implementations/Wallets/SQLite/UserWallet.java deleted file mode 100644 index af1845a..0000000 --- a/src/main/java/DNA/Implementations/Wallets/SQLite/UserWallet.java +++ /dev/null @@ -1,321 +0,0 @@ -package DNA.Implementations.Wallets.SQLite; - -import java.io.File; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.sql.Date; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; - -import javax.crypto.BadPaddingException; -import javax.crypto.IllegalBlockSizeException; - -import DNA.Fixed8; -import DNA.UInt160; -import DNA.UInt256; -import DNA.Core.Block; -import DNA.Core.TransactionInput; -import DNA.Core.TransactionType; -import DNA.IO.Serializable; -import DNA.Implementations.Wallets.IUserManager; -import DNA.Wallets.CoinState; -import DNA.Wallets.Wallet; - -public class UserWallet extends Wallet implements IUserManager { - - protected UserWallet(String path, String password, boolean create) throws BadPaddingException, IllegalBlockSizeException { - super(path, password, create); - } - - /** - * 创建/打开钱包 - */ - public static UserWallet create(String path, String password) { - UserWallet wallet; - try { - wallet = new UserWallet(path, password, true); - } catch (BadPaddingException | IllegalBlockSizeException ex) { - throw new RuntimeException(ex); - } - wallet.createAccount(); // 创建账户、合约 - return wallet; - } - - public static UserWallet open(String path, String password) { - UserWallet wallet; - try { - wallet = new UserWallet(path, password, false); - } catch (BadPaddingException | IllegalBlockSizeException ex) { - throw new RuntimeException(ex); - } - return wallet; - } - - @Override - protected void buildDatabase() { - File file = new File(dbPath()); - file.delete(); - } - - /** - * 创建账户/合约 - */ - @Override - public DNA.Wallets.Account createAccount(byte[] privateKey) { - // account - DNA.Wallets.Account account = super.createAccount(privateKey); - onCreateAccount(account); - // contract - addContract(DNA.Wallets.Contract.createSignatureContract(account.publicKey)); - return account; - } - - private void onCreateAccount(DNA.Wallets.Account account) { - byte[] decryptedPrivateKey = new byte[96]; - System.arraycopy(account.publicKey.getEncoded(false), 1, decryptedPrivateKey, 0, 64); - System.arraycopy(account.privateKey, 0, decryptedPrivateKey, 64, 32); - Account entity = new Account(); - entity.privateKeyEncrypted = encryptPrivateKey(decryptedPrivateKey); - entity.publicKeyHash = account.publicKeyHash.toArray(); - - try (WalletDataContext ctx = new WalletDataContext(dbPath())) { - ctx.insertOrUpdate(entity); - } - Arrays.fill(decryptedPrivateKey, (byte)0); - } - - @Override - public void addContract(DNA.Wallets.Contract contract) { - super.addContract(contract); - try (WalletDataContext ctx = new WalletDataContext(dbPath())) { - Contract entity = new Contract(); - entity.scriptHash = contract.scriptHash().toArray(); - entity.publicKeyHash = contract.publicKeyHash.toArray(); - entity.rawData = contract.toArray(); - ctx.insertOrUpdate(entity); - } - } - - @Override - public boolean deleteAccount(UInt160 publicKeyHash) { - boolean flag = super.deleteAccount(publicKeyHash); - if (flag) { - try (WalletDataContext ctx = new WalletDataContext(dbPath())) { - ctx.deleteAccount(publicKeyHash); - } - } - return flag; - } - - @Override - public boolean deleteContract(UInt160 scriptHash) { - boolean flag = super.deleteContract(scriptHash); - if (flag) { - try (WalletDataContext ctx = new WalletDataContext(dbPath())) { - ctx.deleteContract(scriptHash); - } - } - return flag; - } - - @Override - public DNA.Wallets.Coin[] findUnspentCoins(UInt256 asset_id, Fixed8 amount) { - DNA.Wallets.Coin[] coins = findUnspentCoins(Arrays.stream(findUnspentCoins()).filter(p -> getContract(p.scriptHash).isStandard()), asset_id, amount); - if (coins == null) coins = super.findUnspentCoins(asset_id, amount); - return coins; - } - - @Override - protected DNA.Wallets.Account[] loadAccounts() { - try (WalletDataContext ctx = new WalletDataContext(dbPath())) { - Account[] entities = ctx.getAccounts(); - DNA.Wallets.Account[] accounts = new DNA.Wallets.Account[entities.length]; - for (int i = 0; i < accounts.length; i++) { - byte[] decryptedPrivateKey = decryptPrivateKey(entities[i].privateKeyEncrypted); - accounts[i] = new DNA.Wallets.Account(decryptedPrivateKey); - Arrays.fill(decryptedPrivateKey, (byte)0); - } - return accounts; - } catch (IllegalBlockSizeException | BadPaddingException ex) { - throw new RuntimeException(ex); - } - } - - @Override - public DNA.Wallets.Contract[] loadContracts() { - try (WalletDataContext ctx = new WalletDataContext(dbPath())) { - Contract[] entities = ctx.getContracts(); - DNA.Wallets.Contract[] contracts = new DNA.Wallets.Contract[entities.length]; - for (int i = 0; i < contracts.length; i++) { - contracts[i] = Serializable.from(entities[i].rawData, DNA.Wallets.Contract.class); - } - return contracts; - } catch (InstantiationException | IllegalAccessException ex) { - throw new RuntimeException(ex); - } - } - - @Override - protected DNA.Wallets.Coin[] loadCoins() { - try (WalletDataContext ctx = new WalletDataContext(dbPath())) { - Coin[] entities = ctx.getCoins(); - DNA.Wallets.Coin[] coins = new DNA.Wallets.Coin[entities.length]; - for (int i = 0; i < coins.length; i++) { - coins[i] = new DNA.Wallets.Coin(); - coins[i].input = new TransactionInput(); - coins[i].input.prevHash = new UInt256(entities[i].txid); - coins[i].input.prevIndex = (short)entities[i].index; - coins[i].assetId = new UInt256(entities[i].assetId); - coins[i].value = new Fixed8(entities[i].value); - coins[i].scriptHash = new UInt160(entities[i].scriptHash); - coins[i].setState(CoinState.values()[entities[i].state]); - } - return coins; - } - } - - @Override - protected byte[] loadStoredData(String name) { - try (WalletDataContext ctx = new WalletDataContext(dbPath())) { - Key entity = ctx.getKey(name); - if (entity == null) return null; - return entity.value; - } - } - - public Map LoadTransactions() { - Map txMap = new HashMap(); - try (WalletDataContext ctx = new WalletDataContext(dbPath())) { - Transaction[] trans = ctx.getTransaction(); - for (int i = 0; i < trans.length; i++) { - try { - byte type = trans[i].type; - if(TransactionType.RegisterTransaction.value() == type) { - DNA.Core.Transaction tx = Serializable.from(trans[i].rawData, DNA.Core.RegisterTransaction.class); - txMap.put(tx, trans[i].height); - } else if(TransactionType.IssueTransaction.value() == type) { - DNA.Core.Transaction tx = Serializable.from(trans[i].rawData, DNA.Core.IssueTransaction.class); - txMap.put(tx, trans[i].height); - } else if(TransactionType.TransferTransaction.value() == type) { - DNA.Core.Transaction tx = Serializable.from(trans[i].rawData, DNA.Core.TransferTransaction.class); - txMap.put(tx, trans[i].height); - } - } catch (Exception e) { - String errMsg = String.format("Failed to LoadTx,tx.type:%s,height:%s,errMsg:%s",trans[i].type,trans[i].height,e.getMessage()); - throw new RuntimeException(errMsg, e); - } - } - return txMap; - } - } - - private void onCoinsChanged(WalletDataContext ctx, DNA.Wallets.Coin[] added, DNA.Wallets.Coin[] changed, DNA.Wallets.Coin[] deleted) { - ctx.insert(Arrays.stream(added).map(p -> { - Coin entity = new Coin(); - entity.txid = p.input.prevHash.toArray(); - entity.index = Short.toUnsignedInt(p.input.prevIndex); - entity.assetId = p.assetId.toArray(); - entity.value = p.value.getData(); - entity.scriptHash = p.scriptHash.toArray(); -// entity.state = CoinState.Unspent.ordinal(); - entity.state = p.getState().ordinal(); - return entity; - }).toArray(Coin[]::new)); - ctx.update(Arrays.stream(changed).map(p -> { - Coin entity = new Coin(); - entity.txid = p.input.prevHash.toArray(); - entity.index = Short.toUnsignedInt(p.input.prevIndex); - entity.state = p.getState().ordinal(); - return entity; - }).toArray(Coin[]::new)); - ctx.delete(Arrays.stream(deleted).map(p -> { - Coin entity = new Coin(); - entity.txid = p.input.prevHash.toArray(); - entity.index = Short.toUnsignedInt(p.input.prevIndex); - return entity; - }).toArray(Coin[]::new)); - } - - @Override - protected void onProcessNewBlock(Block block, DNA.Wallets.Coin[] added, DNA.Wallets.Coin[] changed, DNA.Wallets.Coin[] deleted) { - ArrayList tx_changed = new ArrayList(); - try (WalletDataContext ctx = new WalletDataContext(dbPath())) { - ctx.beginTransaction(); - // 更新入库tx - for (DNA.Core.Transaction tx : block.transactions) { - if (isWalletTransaction(tx)) { - tx_changed.add(tx); - Transaction entity = new Transaction(); - entity.hash = tx.hash().toArray(); - entity.type = tx.type.value(); - entity.rawData = tx.toArray(); - entity.height = block.height; - entity.time = new Date(block.timestamp * 1000); - ctx.insertOrUpdate(entity); - } - } - // 更新入库coin - onCoinsChanged(ctx, added, changed, deleted); - // 更新入库height - if (tx_changed.size() > 0 || added.length > 0 || changed.length > 0 || deleted.length > 0) { - saveStoredData(ctx, "Height", ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(getWalletHeight()).array()); - ctx.commit(); - } - } - } - - @Override - protected void onSaveTransaction(DNA.Core.Transaction tx, DNA.Wallets.Coin[] added, DNA.Wallets.Coin[] changed) { - Transaction tx_changed = null; - try (WalletDataContext ctx = new WalletDataContext(dbPath())) { - // 更新入库tx - ctx.beginTransaction(); - if(tx != null) { - tx_changed = new Transaction(); - tx_changed.hash = tx.hash().toArray(); - tx_changed.type = tx.type.value(); - tx_changed.rawData = tx.toArray(); - tx_changed.height = -1; - tx_changed.time = new Date(System.currentTimeMillis()); - ctx.insertOrUpdate(tx_changed); - } - // 更新入库coin - onCoinsChanged(ctx, added, changed, new DNA.Wallets.Coin[0]); - ctx.commit(); - } - } - - @Override - public void rebuild() { - synchronized (locker) { - super.rebuild(); - } - } - - @Override - protected void saveStoredData(String name, byte[] value) { - try (WalletDataContext ctx = new WalletDataContext(dbPath())) { - saveStoredData(ctx, name, value); - } - } - - private static void saveStoredData(WalletDataContext ctx, String name, byte[] value) { - Key entity = new Key(); - entity.name = name; - entity.value = value; - ctx.insertOrUpdate(entity); - } - - public String getWalletPath() { - return dbPath(); - } - - public boolean hasFinishedSyncBlock() throws Exception { - int bHH = getBlockHeight(); - int cHH = getWalletHeight(); - System.out.println("blockHH:"+bHH + "---------------currentHH:"+cHH); - return bHH+1 <= cHH; - } -} diff --git a/src/main/java/DNA/Implementations/Wallets/SQLite/WalletDataContext.java b/src/main/java/DNA/Implementations/Wallets/SQLite/WalletDataContext.java deleted file mode 100644 index c8cbd2b..0000000 --- a/src/main/java/DNA/Implementations/Wallets/SQLite/WalletDataContext.java +++ /dev/null @@ -1,302 +0,0 @@ -package DNA.Implementations.Wallets.SQLite; - -import java.io.File; -import java.sql.*; -import java.util.*; - -import DNA.UInt160; - -class WalletDataContext implements AutoCloseable { - private Connection connection; - - static { - try { - Class.forName("org.sqlite.JDBC"); - } catch (ClassNotFoundException ex) { - throw new RuntimeException(ex); - } - } - - public WalletDataContext(String filename) { - File file = new File(filename); - boolean creating = !file.exists(); - filename = filename.replace('\\', '/'); - try { - connection = DriverManager.getConnection("jdbc:sqlite:" + filename); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } - if (creating) { - createModel(); - } - } - - public void beginTransaction() { - try { - connection.setAutoCommit(false); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } - } - - @Override - public void close() { - try { - connection.close(); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } - } - - public void commit() { - try { - connection.commit(); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } - } - - private void createModel() { - try { - Statement statement = connection.createStatement(); - statement.executeUpdate("CREATE TABLE [Key] ([Name] VarChar NOT NULL CONSTRAINT [PK_Key] PRIMARY KEY, [Value] VarBinary NOT NULL)"); - statement.executeUpdate("CREATE TABLE [Account] ([PrivateKeyEncrypted] VarBinary NOT NULL, [PublicKeyHash] Binary NOT NULL CONSTRAINT [PK_Account] PRIMARY KEY)"); - statement.executeUpdate("CREATE TABLE [Contract] ([ScriptHash] Binary NOT NULL CONSTRAINT [PK_Contract] PRIMARY KEY, [PublicKeyHash] Binary NOT NULL, [RawData] VarBinary NOT NULL, CONSTRAINT [FK_Contract_Account_PublicKeyHash] FOREIGN KEY ([PublicKeyHash]) REFERENCES [Account] ([PublicKeyHash]) ON DELETE CASCADE)"); - statement.executeUpdate("CREATE TABLE [Coin] ([TxId] Binary NOT NULL, [Index] INTEGER NOT NULL, [AssetId] Binary NOT NULL, [ScriptHash] Binary NOT NULL, [State] INTEGER NOT NULL, [Value] INTEGER NOT NULL, CONSTRAINT [PK_Coin] PRIMARY KEY ([TxId], [Index]), CONSTRAINT [FK_Coin_Contract_ScriptHash] FOREIGN KEY ([ScriptHash]) REFERENCES [Contract] ([ScriptHash]) ON DELETE CASCADE)"); - statement.executeUpdate("CREATE TABLE [Transaction] ([Hash] Binary NOT NULL CONSTRAINT [PK_Transaction] PRIMARY KEY, [Height] INTEGER, [RawData] VarBinary NOT NULL, [Time] TEXT NOT NULL, [Type] INTEGER NOT NULL)"); - statement.executeUpdate("CREATE INDEX [IX_Coin_AssetId] ON [Coin] ([AssetId])"); - statement.executeUpdate("CREATE INDEX [IX_Coin_ScriptHash] ON [Coin] ([ScriptHash])"); - statement.executeUpdate("CREATE INDEX [IX_Contract_PublicKeyHash] ON [Contract] ([PublicKeyHash])"); - statement.executeUpdate("CREATE INDEX [IX_Transaction_Height] ON [Transaction] ([Height])"); - statement.executeUpdate("CREATE INDEX [IX_Transaction_Type] ON [Transaction] ([Type])"); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } - } - - public void delete(Coin[] coins) { - if (coins.length == 0) { - return; - } - try { - PreparedStatement statement = connection.prepareStatement("DELETE FROM [Coin] WHERE [TxId] = ? AND [Index] = ?"); - for (Coin coin : coins) { - statement.setBytes(1, coin.txid); - statement.setInt(2, coin.index); - statement.addBatch(); - } - statement.executeBatch(); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } - } - - public void deleteAccount(UInt160 publicKeyHash) { - try { - PreparedStatement statement = connection.prepareStatement("DELETE FROM [Account] WHERE [PublicKeyHash] = ?"); - statement.setBytes(1, publicKeyHash.toArray()); - statement.executeUpdate(); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } - } - - public void deleteContract(UInt160 scriptHash) { - try { - PreparedStatement statement = connection.prepareStatement("DELETE FROM [Contract] WHERE [ScriptHash] = ?"); - statement.setBytes(1, scriptHash.toArray()); - statement.executeUpdate(); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } - } - - public Account[] getAccounts() { - try { - ArrayList accounts = new ArrayList(); - Statement statement = connection.createStatement(); - ResultSet result = statement.executeQuery("SELECT * FROM [Account]"); - while (result.next()) { - Account account = new Account(); - account.privateKeyEncrypted = result.getBytes("PrivateKeyEncrypted"); - account.publicKeyHash = result.getBytes("PublicKeyHash"); - accounts.add(account); - } - return accounts.toArray(new Account[accounts.size()]); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } - } - - public Coin[] getCoins() { - try { - ArrayList coins = new ArrayList(); - Statement statement = connection.createStatement(); - ResultSet result = statement.executeQuery("SELECT * FROM [Coin]"); - while (result.next()) { - Coin coin = new Coin(); - coin.txid = result.getBytes("TxId"); - coin.index = result.getInt("Index"); - coin.assetId = result.getBytes("AssetId"); - coin.scriptHash = result.getBytes("ScriptHash"); - coin.state = result.getInt("State"); - coin.value = result.getLong("Value"); - coins.add(coin); - } - return coins.toArray(new Coin[coins.size()]); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } - } - - public Contract[] getContracts() { - try { - ArrayList contracts = new ArrayList(); - Statement statement = connection.createStatement(); - ResultSet result = statement.executeQuery("SELECT * FROM [Contract]"); - while (result.next()) { - Contract contract = new Contract(); - contract.scriptHash = result.getBytes("ScriptHash"); - contract.publicKeyHash = result.getBytes("PublicKeyHash"); - contract.rawData = result.getBytes("RawData"); - contracts.add(contract); - } - return contracts.toArray(new Contract[contracts.size()]); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } - } - - public Key getKey(String name) { - try { - PreparedStatement statement = connection.prepareStatement("SELECT * FROM [Key] WHERE [Name] = ?"); - statement.setString(1, name); - ResultSet result = statement.executeQuery(); - if (!result.next()) return null; - Key key = new Key(); - key.name = result.getString("Name"); - key.value = result.getBytes("Value"); - return key; - } catch (SQLException ex) { - throw new RuntimeException(ex); - } - } - - public Transaction[] getTransaction() { - try { - ArrayList trans = new ArrayList(); - Statement statement = connection.createStatement(); - ResultSet result = statement.executeQuery("SELECT * FROM [Transaction]"); - while (result.next()) { - Transaction tran = new Transaction(); - tran.hash = result.getBytes("Hash"); - tran.height = result.getInt("Height"); - tran.rawData = result.getBytes("RawData"); -// tran.time = result.getDate("Time"); - tran.type = result.getByte("Type"); - trans.add(tran); - } - return trans.toArray(new Transaction[trans.size()]); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } - } - - public void insert(Coin[] coins) { - if (coins.length == 0) { - return; - } - try { - PreparedStatement statement = connection.prepareStatement("INSERT INTO [Coin] ([TxId], [Index], [AssetId], [ScriptHash], [State], [Value]) VALUES (?, ?, ?, ?, ?, ?)"); - for (Coin coin : coins) { - statement.setBytes(1, coin.txid); - statement.setInt(2, coin.index); - statement.setBytes(3, coin.assetId); - statement.setBytes(4, coin.scriptHash); - statement.setInt(5, coin.state); - statement.setLong(6, coin.value); - statement.addBatch(); - } - statement.executeBatch(); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } - } - - public void insertOrUpdate(Account account) { - try { - PreparedStatement statement = connection.prepareStatement("INSERT OR REPLACE INTO [Account] ([PublicKeyHash], [PrivateKeyEncrypted]) VALUES (?, ?)"); - statement.setBytes(1, account.publicKeyHash); - statement.setBytes(2, account.privateKeyEncrypted); - statement.executeUpdate(); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } - } - - public void insertOrUpdate(Contract contract) { - try { - PreparedStatement statement = connection.prepareStatement("INSERT OR REPLACE INTO [Contract] ([ScriptHash], [PublicKeyHash], [RawData]) VALUES (?, ?, ?)"); - statement.setBytes(1, contract.scriptHash); - statement.setBytes(2, contract.publicKeyHash); - statement.setBytes(3, contract.rawData); - statement.executeUpdate(); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } - } - - public void insertOrUpdate(Key key) { - try { - PreparedStatement statement = connection.prepareStatement("INSERT OR REPLACE INTO [Key] ([Name], [Value]) VALUES (?, ?)"); - statement.setString(1, key.name); - statement.setBytes(2, key.value); - statement.executeUpdate(); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } - } - - public void insertOrUpdate(Transaction transaction) { - try { - PreparedStatement statement = connection.prepareStatement("INSERT OR REPLACE INTO [Transaction] ([Hash], [Height], [RawData], [Time], [Type]) VALUES (?, ?, ?, ?, ?)"); - statement.setBytes(1, transaction.hash); - if (transaction.height == -1) - statement.setNull(2, Types.INTEGER); - else - statement.setInt(2, transaction.height); - statement.setBytes(3, transaction.rawData); - statement.setDate(4, transaction.time); - statement.setByte(5, transaction.type); - statement.executeUpdate(); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } - } - - public void rollback() { - try { - connection.rollback(); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } - } - - public void update(Coin[] coins) { - if (coins.length == 0) { - return; - } - try { - PreparedStatement statement = connection.prepareStatement("UPDATE [Coin] SET [State] = ? WHERE [TxId] = ? AND [Index] = ?"); - for (Coin coin : coins) { - statement.setInt(1, coin.state); - statement.setBytes(2, coin.txid); - statement.setInt(3, coin.index); - statement.addBatch(); - } - statement.executeBatch(); - } catch (SQLException ex) { - throw new RuntimeException(ex); - } - } -} diff --git a/src/main/java/DNA/Implementations/Wallets/UserManagerFactory.java b/src/main/java/DNA/Implementations/Wallets/UserManagerFactory.java deleted file mode 100644 index 5d56179..0000000 --- a/src/main/java/DNA/Implementations/Wallets/UserManagerFactory.java +++ /dev/null @@ -1,7 +0,0 @@ -package DNA.Implementations.Wallets; - - -public class UserManagerFactory { - - -} diff --git a/src/main/java/DNA/Network/Inventory.java b/src/main/java/DNA/Network/Inventory.java deleted file mode 100644 index e97f773..0000000 --- a/src/main/java/DNA/Network/Inventory.java +++ /dev/null @@ -1,21 +0,0 @@ -package DNA.Network; - -import DNA.UInt256; -import DNA.Core.Signable; -import DNA.Cryptography.Digest; - -public abstract class Inventory implements Signable { - //[NonSerialized] - private UInt256 _hash = null; - - public UInt256 hash() { - if (_hash == null) { - _hash = new UInt256(Digest.hash256(getHashData())); - } - return _hash; - } - - public abstract InventoryType inventoryType(); - - public abstract boolean verify(); -} diff --git a/src/main/java/DNA/Network/InventoryType.java b/src/main/java/DNA/Network/InventoryType.java deleted file mode 100644 index 948ac51..0000000 --- a/src/main/java/DNA/Network/InventoryType.java +++ /dev/null @@ -1,38 +0,0 @@ -package DNA.Network; - -/** - * 定义清单中的对象类型 - */ -public enum InventoryType { - /** - * 交易 - */ - TX(0x01), - /** - * 区块 - */ - Block(0x02), - /** - * 共识数据 - */ - Consensus(0xe0), - - ; - private byte value; - private InventoryType(int v) { - value = (byte)v; - } - public int value() { - return value; - } - - public static InventoryType from(byte b) { - for(InventoryType t: InventoryType.values()) { - if(t.value() == b) { - return t; - } - } - throw new IllegalArgumentException(); - } -} - diff --git a/src/main/java/DNA/Network/Rest/RestClient.java b/src/main/java/DNA/Network/Rest/RestClient.java deleted file mode 100644 index 665e25a..0000000 --- a/src/main/java/DNA/Network/Rest/RestClient.java +++ /dev/null @@ -1,253 +0,0 @@ -package DNA.Network.Rest; - -import java.io.IOException; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.util.HashMap; -import java.util.Map; - - -public class RestClient { - private String url; - public RestClient(String url) { -// Consts.setRestUrl(url); - this.url = url; - } - - public String sendTransaction(String authType, String accessToken, String action, String version, String type, String data) throws RestException { - Map params = new HashMap(); - params.put("auth_type", authType); - params.put("access_token", accessToken); - Map body = new HashMap(); - body.put("Action", action); - body.put("Version", version); - body.put("Type", type); - body.put("Data", data); - try { - return RestHttp.post(url + Consts.Url_send_transaction, params, body); - } catch (KeyManagementException | NoSuchAlgorithmException - | NoSuchProviderException | IOException e) { - e.printStackTrace(); - throw new RestException("Invalid url:"+e.getMessage()); - } - } - - public String getTransaction(String authType, String accessToken, String txid) throws RestException { - Map params = new HashMap(); - params.put("auth_type", authType); - params.put("access_token", accessToken); - params.put("raw", "1"); - try { - return RestHttp.get(url + Consts.Url_get_transaction + txid, params); - } catch (KeyManagementException | NoSuchAlgorithmException - | NoSuchProviderException | IOException e) { - throw new RestException("Invalid url:"+e.getMessage()); - } - } - - public String getAsset(String authType, String accessToken, String assetid) throws RestException { - Map params = new HashMap(); - params.put("auth_type", authType); - params.put("access_token", accessToken); - try { - return RestHttp.get(url + Consts.Url_get_asset + assetid, params); - } catch (KeyManagementException | NoSuchAlgorithmException - | NoSuchProviderException | IOException e) { - throw new RestException("Invalid url:"+e.getMessage()); - } - } - - public String getBlockHeight(String authType, String accessToken) throws RestException { - Map params = new HashMap(); - params.put("auth_type", authType); - params.put("access_token", accessToken); - try { - return RestHttp.get(url + Consts.Url_get_block_height, params); - } catch (KeyManagementException | NoSuchAlgorithmException - | NoSuchProviderException | IOException e) { - throw new RestException("Invalid url:"+e.getMessage()); - } - } - - public String getBlock(String authType, String accessToken, int height) throws RestException { - Map params = new HashMap(); - params.put("auth_type", authType); - params.put("access_token", accessToken); - params.put("raw", "1"); - try { - return RestHttp.get(url + Consts.Url_get_block_By_Height + height, params); - } catch (KeyManagementException | NoSuchAlgorithmException - | NoSuchProviderException | IOException e) { - throw new RestException("Invalid url:"+e.getMessage()); - } - } - - public String getBlock(String authType, String accessToken, String hash) throws RestException { - Map params = new HashMap(); - params.put("auth_type", authType); - params.put("access_token", accessToken); - params.put("raw", "1"); - try { - return RestHttp.get(url + Consts.Url_get_block_By_Hash + hash, params); - } catch (KeyManagementException | NoSuchAlgorithmException - | NoSuchProviderException | IOException e) { - throw new RestException("Invalid url:"+e.getMessage()); - } - } - - public String getUTXOs(String authType, String accessToken, String address, String assetid) throws RestException { - Map params = new HashMap(); - params.put("auth_type", authType); - params.put("access_token", accessToken); - try { - return RestHttp.get(url + Consts.Url_get_UTXO_By_address_assetid + address + "/" + assetid, params); - } catch (KeyManagementException | NoSuchAlgorithmException - | NoSuchProviderException | IOException e) { - throw new RestException("Invalid url:"+e.getMessage()); - } - } - public String getUTXO(String authType, String accessToken, String address) throws RestException { - Map params = new HashMap(); - params.put("auth_type", authType); - params.put("access_token", accessToken); - try { - return RestHttp.get(url + Consts.Url_get_UTXO_By_address + address, params); - } catch (KeyManagementException | NoSuchAlgorithmException - | NoSuchProviderException | IOException e) { - throw new RestException("Invalid url:"+e.getMessage()); - } - } - - public String getBalance(String authType, String accessToken, String address) throws RestException { - Map params = new HashMap(); - params.put("auth_type", authType); - params.put("access_token", accessToken); - try { - return RestHttp.get(url + Consts.Url_get_account_balance + address, params); - } catch (KeyManagementException | NoSuchAlgorithmException - | NoSuchProviderException | IOException e) { - throw new RestException("Invalid url:"+e.getMessage()); - } - } - - public String getStateUpdate(String authType, String accessToken, String namespace, String key) throws RestException { - Map params = new HashMap(); - params.put("auth_type", authType); - params.put("access_token", accessToken); - try { - return RestHttp.get(url + Consts.Url_get_StateUpdate + namespace + "/" + key, params); - } catch (KeyManagementException | NoSuchAlgorithmException - | NoSuchProviderException | IOException e) { - throw new RestException("Invalid url:"+e.getMessage()); - } - } - - public String getBlockHeightFromDb() throws RestException { - try { - return RestHttp.get(url + Consts.Url_get_block_height_db); - } catch (KeyManagementException | NoSuchAlgorithmException - | NoSuchProviderException | IOException e) { - e.printStackTrace(); - throw new RestException("Invalid url:"+e.getMessage()); - } - } - public String getBlockFromDb(int height) throws RestException { - try { - return RestHttp.get(url + Consts.Url_get_block + height); - } catch (KeyManagementException | NoSuchAlgorithmException - | NoSuchProviderException | IOException e) { - e.printStackTrace(); - throw new RestException("Invalid url:"+e.getMessage()); - } - } - - - public String sendToIssService(String data) throws RestException { - try { - return RestHttp.post(url + Consts.Url_send_to_issService, data); - } catch (KeyManagementException | NoSuchAlgorithmException - | NoSuchProviderException | IOException e) { - e.printStackTrace(); - throw new RestException("Invalid url:"+e.getMessage()); - } - } - - public String sendToTrfService(String data) throws RestException { - try { - return RestHttp.post(url + Consts.Url_send_to_trfService, data); - } catch (KeyManagementException | NoSuchAlgorithmException - | NoSuchProviderException | IOException e) { - e.printStackTrace(); - throw new RestException("Invalid url:"+e.getMessage()); - } - } - - // ****************************************************************************************************8 - public String getTransactionJson(String authType, String accessToken, String txid) throws RestException { - Map params = new HashMap(); - params.put("auth_type", authType); - params.put("access_token", accessToken); - try { - return RestHttp.get(url + Consts.Url_get_transaction + txid, params); - } catch (KeyManagementException | NoSuchAlgorithmException - | NoSuchProviderException | IOException e) { - throw new RestException("Invalid url:"+e.getMessage()); - } - } - public String getBlockJson(String authType, String accessToken, int height) throws RestException { - Map params = new HashMap(); - params.put("auth_type", authType); - params.put("access_token", accessToken); - try { - return RestHttp.get(url + Consts.Url_get_block_By_Height + height, params); - } catch (KeyManagementException | NoSuchAlgorithmException - | NoSuchProviderException | IOException e) { - throw new RestException("Invalid url:"+e.getMessage()); - } - } - - public String getBlockJson(String authType, String accessToken, String hash) throws RestException { - Map params = new HashMap(); - params.put("auth_type", authType); - params.put("access_token", accessToken); - try { - return RestHttp.get(url + Consts.Url_get_block_By_Hash + hash, params); - } catch (KeyManagementException | NoSuchAlgorithmException - | NoSuchProviderException | IOException e) { - throw new RestException("Invalid url:"+e.getMessage()); - } - } -} - -class Consts { - public static void setRestUrl(String url) { - Url_send_transaction = url + "/api/v1/transaction"; - Url_get_transaction = url + "/api/v1/transaction/"; - Url_get_asset = url + "/api/v1/asset/"; - Url_get_block_height = url + "/api/v1/block/height"; - Url_get_block_By_Height = url + "/api/v1/block/details/height/"; - Url_get_block_By_Hash = url + "/api/v1/block/details/hash/"; - Url_get_UTXO_By_address_assetid = url + "/api/v1/asset/utxo/"; - Url_get_UTXO_By_address = url + "/api/v1/asset/utxo/"; - Url_get_account_balance = url + "/api/v1/asset/balance/"; - Url_get_block_height_db = url + "/blocks/service/blockHeight"; - Url_get_block = url + "/blocks/service/oneBlockInfo/"; - Url_get_StateUpdate = url + "/api/v1/stateupdate/"; - } - - public static String Url_send_transaction = "/api/v1/transaction"; - public static String Url_get_transaction = "/api/v1/transaction/"; - public static String Url_get_asset = "/api/v1/asset/"; - public static String Url_get_block_height = "/api/v1/block/height"; - public static String Url_get_block_By_Height = "/api/v1/block/details/height/"; - public static String Url_get_block_By_Hash = "/api/v1/block/details/hash/"; - public static String Url_get_account_balance = "/api/v1/asset/balance/"; - public static String Url_get_UTXO_By_address_assetid = "/api/v1/asset/utxo/"; - public static String Url_get_UTXO_By_address = "/api/v1/asset/utxo/"; - public static String Url_get_block_height_db = "/blocks/service/blockHeight"; - public static String Url_get_block = "/blocks/service/oneBlockInfo/"; - public static String Url_get_StateUpdate = "/api/v1/stateupdate/"; - public static String Url_send_to_issService = "/api/transaction/assetIssue"; - public static String Url_send_to_trfService = "/api/transaction/assetTrans"; -} diff --git a/src/main/java/DNA/Network/Rest/RestException.java b/src/main/java/DNA/Network/Rest/RestException.java deleted file mode 100644 index 675a048..0000000 --- a/src/main/java/DNA/Network/Rest/RestException.java +++ /dev/null @@ -1,9 +0,0 @@ -package DNA.Network.Rest; - -public class RestException extends Exception { - private static final long serialVersionUID = -8558006777817318117L; - - public RestException(String message) { - super(message); - } -} \ No newline at end of file diff --git a/src/main/java/DNA/Network/Rest/RestHttp.java b/src/main/java/DNA/Network/Rest/RestHttp.java deleted file mode 100644 index d7a693d..0000000 --- a/src/main/java/DNA/Network/Rest/RestHttp.java +++ /dev/null @@ -1,215 +0,0 @@ -package DNA.Network.Rest; - -import java.io.BufferedReader; -import java.io.Closeable; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLEncoder; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.SecureRandom; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.Map; -import java.util.Map.Entry; - -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; -import javax.net.ssl.X509TrustManager; - -import com.alibaba.fastjson.JSON; - -/** - * Rest Http 连接类 - * - * @author 12146 - * - */ -public class RestHttp { - private static final String DEFAULT_CHARSET = "UTF-8"; - - /** - * Post请求 - * - * @param url - * @param params - * @param https - * @return - * @throws IOException - * @throws NoSuchAlgorithmException - * @throws NoSuchProviderException - * @throws KeyManagementException - */ - public static String post(String url, String body, boolean https) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException { - // 创建链接 - URL u = new URL(url); - HttpURLConnection http = (HttpURLConnection) u.openConnection(); - // 连接超时 - http.setConnectTimeout(10000); - http.setReadTimeout(10000); - http.setRequestMethod("POST"); - http.setRequestProperty("Content-Type","application/json"); - if(https) { - SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); - sslContext.init(null, new TrustManager[]{new MyX509TrustManager()}, new SecureRandom()); - SSLSocketFactory ssf = sslContext.getSocketFactory(); - ((HttpsURLConnection)http).setSSLSocketFactory(ssf); - } - http.setDoOutput(true); - http.setDoInput(true); - http.connect(); - // 写入参数 - try (OutputStream out = http.getOutputStream()) { - out.write(body.getBytes(DEFAULT_CHARSET)); - out.flush(); - } - // 获取返回 - StringBuilder sb = new StringBuilder(); - try (InputStream is = http.getInputStream()) { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, DEFAULT_CHARSET))) { - String str = null; - while((str = reader.readLine()) != null) { - sb.append(str);str = null; - } - } - } - // 关闭链接 - if (http != null) { - http.disconnect(); - } - return sb.toString(); - } - - public static String post(String url, String body) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException { -// System.out.println(String.format("POST url=%s, body=%s", url, body)); - if(url.startsWith("https")){ - return post(url, body, true); - }else{ - return post(url, body, false); - } - } - public static String post(String url, Map params, Map body) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException { - return post(url+initParams(params), JSON.toJSONString(body)); - } - - /** - * Get请求 - * - * @param url - * @param https - * @return - * @throws NoSuchAlgorithmException - * @throws NoSuchProviderException - * @throws IOException - * @throws KeyManagementException - */ - private static String get(String url /*,String body*/ ,boolean https) throws NoSuchAlgorithmException, NoSuchProviderException, IOException, KeyManagementException { - // 创建链接 - URL u = new URL(url); - HttpURLConnection http = (HttpURLConnection) u.openConnection(); - // 连接超时 - http.setConnectTimeout(50000); - http.setReadTimeout(50000); - http.setRequestMethod("GET"); - http.setRequestProperty("Content-Type","application/json"); - if(https) { - SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); - sslContext.init(null, new TrustManager[]{new MyX509TrustManager()}, new SecureRandom()); - SSLSocketFactory ssf = sslContext.getSocketFactory(); - ((HttpsURLConnection)http).setSSLSocketFactory(ssf); - } - http.setDoOutput(true); - http.setDoInput(true); - http.connect(); - // 获取返回 - StringBuilder sb = new StringBuilder(); - try (InputStream is = http.getInputStream()) { - try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, DEFAULT_CHARSET))) { - String str = null; - while((str = reader.readLine()) != null) { - sb.append(str);str = null; - } - } - } - // 关闭链接 - if (http != null) { - http.disconnect(); - } - return sb.toString(); - } - public static String get(String url/*,String body*/) throws KeyManagementException, NoSuchAlgorithmException, NoSuchProviderException, IOException { -// System.out.println(String.format(" GET url=%s, params=%s", url, null)); - if(url.startsWith("https")){ - return get(url, true); - }else{ - return get(url, false); - } - } - - public static String get(String url, Map params/*, Map body*/) throws KeyManagementException, NoSuchAlgorithmException, NoSuchProviderException, IOException { - return get(url+initParams(params)); - } - - /** - * 拼接Get参数 - * - * @param url - * @param params - * @return - */ - private static String initParams( Map params){ - if (params == null || params.isEmpty()) { - return ""; - } - StringBuilder sb = new StringBuilder(); - for (Entry entry : params.entrySet()) { - String key = entry.getKey(); - String value = entry.getValue(); - try { - value = value == null ? value:URLEncoder.encode(value, DEFAULT_CHARSET); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - sb.append("&").append(key).append("=").append(value); - } - return "?"+sb.toString().substring(1); - } - - /** - * 关闭链接 - * - * @param objs - * @throws IOException - */ - public static void close(Closeable... objs) throws IOException { - if(objs != null && objs.length > 0) { - Arrays.stream(objs).forEach(p -> {try {p.close(); } catch(Exception e){}}); - } - } -} -/** - * 证书管理 - */ -class MyX509TrustManager implements X509TrustManager { - - public X509Certificate[] getAcceptedIssuers() { - return null; - } - - public void checkClientTrusted(X509Certificate[] chain, String authType) - throws CertificateException { - } - - public void checkServerTrusted(X509Certificate[] chain, String authType) - throws CertificateException { - } -} diff --git a/src/main/java/DNA/Network/Rest/RestNode.java b/src/main/java/DNA/Network/Rest/RestNode.java deleted file mode 100644 index 3d379bc..0000000 --- a/src/main/java/DNA/Network/Rest/RestNode.java +++ /dev/null @@ -1,255 +0,0 @@ -package DNA.Network.Rest; - -import java.io.IOException; -import java.util.List; - -import DNA.Helper; -import DNA.Core.Block; -import DNA.Core.Transaction; -import DNA.IO.Serializable; -import DNA.sdk.info.asset.UTXO2Info; -import DNA.sdk.info.asset.UTXOInfo; - -import com.alibaba.fastjson.JSON; - -public class RestNode { - private RestClient restClient; - private String accessToken="token001", authType="OAuth2.0"; - private String action = "sendrawtransaction",version = "v001",type = "t001"; - - - public RestNode(String restUrl) { - restClient = new RestClient(restUrl); - setAccessToken(accessToken); - } - - public RestNode(String restUrl, String accessToken) { - restClient = new RestClient(restUrl); - setAccessToken(accessToken); - } - - public void setAccessToken(String accessToken) { - this.accessToken = accessToken; - } - - public void setAuthType(String authType) { - this.authType = authType; - } - - public boolean sendRawTransaction(String data) throws RestException { - String rs = restClient.sendTransaction(authType, accessToken, action, version, type, data); - Result rr = JSON.parseObject(rs, Result.class); - if(rr.Error == 0) { - return true; - } - throw new RestRuntimeException(rr.toString()); - } - - public Transaction getRawTransaction(String txid) throws RestException { - String rs = restClient.getTransaction(authType, accessToken, txid); // DNA-195 - Result rr = JSON.parseObject(rs, Result.class); - if(rr.Error == 0) { - try { - return Transaction.deserializeFrom(Helper.hexToBytes(rr.Result)); - } catch (IOException e) { - throw new RestRuntimeException("Transaction.fromJsonD(txid) failed", e); - } - } - throw new RestRuntimeException(rr.toString()); - } - - public String getAsset(String assetid) throws RestException { - String rs = restClient.getAsset(authType, accessToken, assetid); // DNA-195 - Result rr = JSON.parseObject(rs, Result.class); - if(rr.Error != 0) { - throw new RestRuntimeException(rr.toString()); - } - return rr.Result; - } - - public int getBlockHeight() throws RestException { - String rs = restClient.getBlockHeight(authType, accessToken); - Result rr = JSON.parseObject(rs, Result.class); - if(rr.Error != 0) { - throw new RestRuntimeException(rr.toString()); - } - return Integer.valueOf(rr.Result).intValue(); - - } - public Block getBlock(int height) throws RestException { - String rs = restClient.getBlock(authType, accessToken, height); - Result rr = JSON.parseObject(rs, Result.class); - if(rr.Error != 0) { - throw new RestRuntimeException(rr.toString()); - } - try { - return Serializable.from(DNA.Helper.hexToBytes(rr.Result), Block.class); - } catch (InstantiationException | IllegalAccessException e) { - throw new RestRuntimeException("Block.deserialize(height) failed", e); - } - } - - public Block getBlock(String hash) throws RestException { - String rs = restClient.getBlock(authType, accessToken, hash); - Result rr = JSON.parseObject(rs, Result.class); - if(rr.Error != 0) { - throw new RestRuntimeException(rr.toString()); - } - try { - return Serializable.from(DNA.Helper.hexToBytes(rr.Result), Block.class); - } catch (InstantiationException | IllegalAccessException e) { - throw new RestRuntimeException("Block.deserialize(hash) failed", e); - } - - } - - public List getUTXOs(String address, String assetid) throws RestException { - String rs = restClient.getUTXOs(authType, accessToken, address, assetid); - Result rr = JSON.parseObject(rs, Result.class); - if(rr.Error == 0) { - return JSON.parseArray(rr.Result, UTXOInfo.class); - } - throw new RestRuntimeException(rr.toString()); - } - public List getUTXO(String address) throws RestException { - String rs = restClient.getUTXO(authType, accessToken, address); - Result rr = JSON.parseObject(rs, Result.class); - if(rr.Error == 0) { - return JSON.parseArray(rr.Result, UTXO2Info.class); - } - throw new RestRuntimeException(rr.toString()); - } - - public long getBalance(String address) throws RestException { - String rs = restClient.getBalance(address, address, address); - Result rr = JSON.parseObject(rs, Result.class); - if(rr.Error == 0) { - return Long.parseLong(rr.Result); - } - throw new RestRuntimeException(rr.toString()); - } - - public String getStateUpdate(String namespace, String key) throws RestException { - String rs = restClient.getStateUpdate(authType, accessToken, namespace, key); - Result rr = JSON.parseObject(rs, Result.class); - if(rr.Error != 0) { - throw new RestRuntimeException(rr.toString()); - } - return rr.Result; - } - - - public int getBlockHeightFromDb() throws RestException { - String rs = restClient.getBlockHeightFromDb(); - Result4Block rr = JSON.parseObject(rs, Result4Block.class); - if(rr.Error == 0) { - return Integer.parseInt(rr.Result); - } - throw new RestRuntimeException(rr.toString()); - } - public Block getBlockFromDb(int height) throws RestException { - String rs = restClient.getBlockFromDb(height); - Result4Block rr = JSON.parseObject(rs, Result4Block.class); - if(rr.Error != 0) { - throw new RestRuntimeException(rr.toString()); - } - try { - return Serializable.from(DNA.Helper.hexToBytes(rr.Result), Block.class); - } catch (InstantiationException | IllegalAccessException e) { - throw new RestRuntimeException("Block.deserialize(hash) failed", e); - } - } - - // ******************************************************************************** - public Transaction getRawTransactionJson(String txid) throws RestException { - String rs = restClient.getTransaction(authType, accessToken, txid); - Result rr = JSON.parseObject(rs, Result.class); -// if(rr.Error == 0) { -// try { -// return Transaction.fromJsonD(new JsonReader(JObject.parse(rr.Result))); -// } catch (Exception e) { -// throw new RestRuntimeException("Transaction.fromJsonD(txid) failed", e); -// } -// } - throw new RestRuntimeException(rr.toString()); - } - public Block getBlockJson(int height) throws RestException { - String rs = restClient.getBlock(authType, accessToken, height); - Result rr = JSON.parseObject(rs, Result.class); -// if(rr.Error == 0) { -// try { -// return JsonSerializable.from(JObject.parse(rr.Result), Block.class); -// } catch (InstantiationException | IllegalAccessException e) { -// throw new RestRuntimeException("Block.deserialize(height) failed", e); -// } -// } - throw new RestRuntimeException(rr.toString()); - } - - public Block getBlockJson(String hash) throws RestException { - String rs = restClient.getBlock(authType, accessToken, hash); - Result rr = JSON.parseObject(rs, Result.class); - if(rr.Error != 0) { - throw new RestRuntimeException(rr.toString()); - } -// try { -// return JsonSerializable.from(JObject.parse(rr.Result), Block.class); -// } catch (InstantiationException | IllegalAccessException e) { -// throw new RestRuntimeException("Block.deserialize(hash) failed", e); -// } - return null; - } - - public boolean sendToIssService(String data) throws RestException { - String rs = restClient.sendToIssService(data); - Result rr = JSON.parseObject(rs, Result.class); - if(rr.Error != 0) { - throw new RestRuntimeException(rr.toString()); - } - return true; - } - - public boolean sendToTrfService(String data) throws RestException { - String rs = restClient.sendToTrfService(data); - Result rr = JSON.parseObject(rs, Result.class); - if(rr.Error != 0) { - throw new RestRuntimeException(rr.toString()); - } - return true; - } -} -class Result { - public String Action; - public long Error; - public String Desc; - public String Result; - public String Version; - - @Override - public String toString() { - return "Result [Action=" + Action + ", Error=" + Error + ", Desc=" - + Desc + ", Result=" + Result + ", Version=" + Version + "]"; - } -} -class Result4Block { - public String Desc; - public long Error; - public String Result; - - @Override - public String toString() { - return "Result4Block [Desc=" + Desc + ", Error=" + Error + ", Result=" - + Result + "]"; - } -} -class Result4IssService { - public String Desc; - public long Error; - - @Override - public String toString() { - return "Result4IssService [Desc=" + Desc + ", Error=" + Error + "]"; - } -} - - diff --git a/src/main/java/DNA/Network/Rest/RestRuntimeException.java b/src/main/java/DNA/Network/Rest/RestRuntimeException.java deleted file mode 100644 index eedfdad..0000000 --- a/src/main/java/DNA/Network/Rest/RestRuntimeException.java +++ /dev/null @@ -1,17 +0,0 @@ -package DNA.Network.Rest; - -public class RestRuntimeException extends RuntimeException{ - - /** - * - */ - private static final long serialVersionUID = 1L; - - public RestRuntimeException(String message) { - super(message); - } - - public RestRuntimeException(String message, Throwable thr) { - super(message, thr); - } -} diff --git a/src/main/java/DNA/Out.java b/src/main/java/DNA/Out.java deleted file mode 100644 index 357d7d0..0000000 --- a/src/main/java/DNA/Out.java +++ /dev/null @@ -1,16 +0,0 @@ -package DNA; - -/** - * To simulate out keyword in c# - */ -public class Out { - private T obj; - - public T get() { - return obj; - } - - public void set(T obj) { - this.obj = obj; - } -} diff --git a/src/main/java/DNA/UInt160.java b/src/main/java/DNA/UInt160.java deleted file mode 100644 index ae3193a..0000000 --- a/src/main/java/DNA/UInt160.java +++ /dev/null @@ -1,58 +0,0 @@ -package DNA; - -/** - * Custom type which inherits base class defines 20-bit data, - * it mostly used to defined contract address - * - * @author 12146 - * @since JDK1.8 - * - */ -public class UInt160 extends UIntBase implements Comparable { - public static final UInt160 ZERO = new UInt160(); - - public UInt160() { - this(null); - } - - public UInt160(byte[] value) { - super(20, value); - } - - @Override - public int compareTo(UInt160 other) { - byte[] x = this.data_bytes; - byte[] y = other.data_bytes; - for (int i = x.length - 1; i >= 0; i--) { - int r = Byte.toUnsignedInt(x[i]) - Byte.toUnsignedInt(y[i]); - if (r != 0) { - return r; - } - } - return 0; - } - - public static UInt160 parse(String value) { - if (value == null) { - throw new NullPointerException(); - } - if (value.startsWith("0x")) { - value = value.substring(2); - } - if (value.length() != 40) { - throw new IllegalArgumentException(); - } - byte[] v = Helper.hexToBytes(value); - return new UInt160(Helper.reverse(v)); - } - - public static boolean tryParse(String s, UInt160 result) { - try { - UInt160 v = parse(s); - result.data_bytes = v.data_bytes; - return true; - } catch (Exception e) { - return false; - } - } -} \ No newline at end of file diff --git a/src/main/java/DNA/UInt256.java b/src/main/java/DNA/UInt256.java deleted file mode 100644 index 894d68b..0000000 --- a/src/main/java/DNA/UInt256.java +++ /dev/null @@ -1,58 +0,0 @@ -package DNA; - -/** - * Custom type which inherits base class defines 32-bit data, - * it mostly used to defined transaction identity - * - * @author 12146 - * @since JDK1.8 - * - */ -public class UInt256 extends UIntBase implements Comparable { - public static final UInt256 ZERO = new UInt256(); - - public UInt256() { - this(null); - } - - public UInt256(byte[] value) { - super(32, value); - } - - @Override - public int compareTo(UInt256 other) { - byte[] x = this.data_bytes; - byte[] y = other.data_bytes; - for (int i = x.length - 1; i >= 0; i--) { - int r = Byte.toUnsignedInt(x[i]) - Byte.toUnsignedInt(y[i]); - if (r != 0) { - return r; - } - } - return 0; - } - - public static UInt256 parse(String s) { - if (s == null) { - throw new NullPointerException(); - } - if (s.startsWith("0x")) { - s = s.substring(2); - } - if (s.length() != 64) { - throw new IllegalArgumentException(String.format("字符串\"{0}\"无法识别为正确的UInt256。", s)); - } - byte[] v = Helper.hexToBytes(s); - return new UInt256(Helper.reverse(v)); - } - - public static boolean tryParse(String s, UInt256 result) { - try { - UInt256 v = parse(s); - result.data_bytes = v.data_bytes; - return true; - } catch (Exception e) { - return false; - } - } -} \ No newline at end of file diff --git a/src/main/java/DNA/Wallets/Account.java b/src/main/java/DNA/Wallets/Account.java deleted file mode 100644 index fafb7fe..0000000 --- a/src/main/java/DNA/Wallets/Account.java +++ /dev/null @@ -1,78 +0,0 @@ -package DNA.Wallets; - -import java.math.BigInteger; -import java.util.Arrays; - -import org.bouncycastle.math.ec.ECPoint; - -import DNA.UInt160; -import DNA.Core.Scripts.Program; -import DNA.Cryptography.Base58; -import DNA.Cryptography.Digest; -import DNA.Cryptography.ECC; - -/** - * account info, including privatekey/publicKey and publicHash - */ -public class Account { - - /** - * privateKey, used for signing transaction - */ - public final byte[] privateKey; - - /** - * publickey, used for verifying signature info - */ - public final ECPoint publicKey; - - /** - * publiekeyHash, used for identifing which account the contract belongs to - */ - public final UInt160 publicKeyHash; - - public Account(byte[] privateKey) { - if (privateKey.length != 32 && privateKey.length != 96 && privateKey.length != 104) { - throw new IllegalArgumentException(); - } - this.privateKey = new byte[32]; - System.arraycopy(privateKey, privateKey.length - 32, this.privateKey, 0, 32); - if (privateKey.length == 32) { - this.publicKey = ECC.secp256r1.getG().multiply(new BigInteger(1, privateKey)).normalize(); - } else { - byte[] encoded = new byte[65]; - encoded[0] = 0x04; - System.arraycopy(privateKey, 0, encoded, 1, 64); - this.publicKey = ECC.secp256r1.getCurve().decodePoint(encoded); - } - this.publicKeyHash = Program.toScriptHash(publicKey.getEncoded(true)); - } - - public String export() { - byte[] data = new byte[38]; - data[0] = (byte) 0x80; - System.arraycopy(privateKey, 0, data, 1, 32); - data[33] = (byte) 0x01; - byte[] checksum = Digest.sha256(Digest.sha256(data, 0, data.length - 4)); - System.arraycopy(checksum, 0, data, data.length - 4, 4); - String wif = Base58.encode(data); - Arrays.fill(data, (byte) 0); - return wif; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof Account)) { - return false; - } - return publicKeyHash.equals(((Account) obj).publicKeyHash); - } - - @Override - public int hashCode(){ - return publicKeyHash.hashCode(); - } -} diff --git a/src/main/java/DNA/Wallets/Coin.java b/src/main/java/DNA/Wallets/Coin.java deleted file mode 100644 index ea666fd..0000000 --- a/src/main/java/DNA/Wallets/Coin.java +++ /dev/null @@ -1,78 +0,0 @@ -package DNA.Wallets; - -import DNA.Fixed8; -import DNA.UInt160; -import DNA.UInt256; -import DNA.Core.TransactionInput; -import DNA.IO.Caching.ITrackable; -import DNA.IO.Caching.TrackState; - -/** - * Account's change, used to pay for the transaction - * - * @author 12146 - * - */ -public class Coin implements ITrackable { - public TransactionInput input; - public UInt256 assetId; - public Fixed8 value; - public UInt160 scriptHash; - - //[NonSerialized] - private String _address = null; - public String address() { - if (_address == null) { - _address = Wallet.toAddress(scriptHash); - } - return _address; - } - - //[NonSerialized] - private CoinState state; - public CoinState getState() { - return state; - } - - public void setState(CoinState value) { - if (state != value) { - state = value; - ITrackable _this = this; - if (_this.getTrackState() == TrackState.None) { - _this.setTrackState(TrackState.Changed); - } - } - } - - private TrackState trackState; - @Override - public TrackState getTrackState() { - return trackState; - } - - @Override - public void setTrackState(TrackState state) { - trackState = state; - } - - @Override - public TransactionInput key() { - return input; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof Coin)) { - return false; - } - return input.equals(((Coin) obj).input); - } - - @Override - public int hashCode() { - return input.hashCode(); - } -} diff --git a/src/main/java/DNA/Wallets/CoinException.java b/src/main/java/DNA/Wallets/CoinException.java deleted file mode 100644 index 61e9284..0000000 --- a/src/main/java/DNA/Wallets/CoinException.java +++ /dev/null @@ -1,13 +0,0 @@ -package DNA.Wallets; - -public class CoinException extends Exception { - private static final long serialVersionUID = 3406743448316144201L; - - public CoinException(String message) { - super(message); - } - - public CoinException(String message, Throwable ex) { - super(message, ex); - } -} diff --git a/src/main/java/DNA/Wallets/CoinRuntimeException.java b/src/main/java/DNA/Wallets/CoinRuntimeException.java deleted file mode 100644 index 6191edd..0000000 --- a/src/main/java/DNA/Wallets/CoinRuntimeException.java +++ /dev/null @@ -1,13 +0,0 @@ -package DNA.Wallets; - -public class CoinRuntimeException extends RuntimeException { - private static final long serialVersionUID = 3406743448316144201L; - - public CoinRuntimeException(String message) { - super(message); - } - - public CoinRuntimeException(String message, Throwable ex) { - super(message, ex); - } -} diff --git a/src/main/java/DNA/Wallets/CoinState.java b/src/main/java/DNA/Wallets/CoinState.java deleted file mode 100644 index c20f536..0000000 --- a/src/main/java/DNA/Wallets/CoinState.java +++ /dev/null @@ -1,9 +0,0 @@ -package DNA.Wallets; - -public enum CoinState { - Unconfirmed, - Unspent, - Spending, - Spent, - SpentAndClaimed -} \ No newline at end of file diff --git a/src/main/java/DNA/Wallets/Contract.java b/src/main/java/DNA/Wallets/Contract.java deleted file mode 100644 index 9cec09f..0000000 --- a/src/main/java/DNA/Wallets/Contract.java +++ /dev/null @@ -1,161 +0,0 @@ -package DNA.Wallets; - -import java.io.IOException; -import java.math.BigInteger; -import java.util.Arrays; -import java.util.stream.Stream; - -import org.bouncycastle.math.ec.ECPoint; - -import DNA.UInt160; -import DNA.Core.Scripts.Program; -import DNA.Core.Scripts.ScriptBuilder; -import DNA.Core.Scripts.ScriptOp; -import DNA.IO.BinaryReader; -import DNA.IO.BinaryWriter; -import DNA.IO.Serializable; - -/** - * 所有合约的基类 - */ -public class Contract implements Serializable { - /** - * 合约脚本代码 - */ - public byte[] redeemScript; - /** - * 合约类型 - */ - public ContractParameterType[] parameterList; - /** - * 公钥散列值,用于标识该合约在钱包中隶属于哪一个账户 - */ - public UInt160 publicKeyHash; - - /** - * 合约地址 - */ - private String _address; - public String address() { - if (_address == null) { - _address = Wallet.toAddress(scriptHash()); - } - return _address; - } - - /** - * 脚本散列值 - */ - private UInt160 _scriptHash; - public UInt160 scriptHash() { - if (_scriptHash == null) { - _scriptHash = Program.toScriptHash(redeemScript); - } - return _scriptHash; - } - - public boolean isStandard() { - if (redeemScript.length != 35) { - return false; - } - if (redeemScript[0] != 33 || redeemScript[34] != ScriptOp.OP_CHECKSIG.getByte()) { - return false; - } - return true; - } - - public static Contract create(UInt160 publicKeyHash, ContractParameterType[] parameterList, byte[] redeemScript) { - Contract contract = new Contract(); - contract.redeemScript = redeemScript; - contract.parameterList = parameterList; - contract.publicKeyHash = publicKeyHash; - return contract; - } - - public static Contract createSignatureContract(ECPoint publicKey) { - Contract contract = new Contract(); - contract.redeemScript = createSignatureRedeemScript(publicKey); - contract.parameterList = new ContractParameterType[] { ContractParameterType.Signature }; - contract.publicKeyHash = Program.toScriptHash(publicKey.getEncoded(true)); - return contract; - } - - public static byte[] createSignatureRedeemScript(ECPoint publicKey) { - try (ScriptBuilder sb = new ScriptBuilder()) { - sb.push(publicKey.getEncoded(true)); - sb.add(ScriptOp.OP_CHECKSIG); - return sb.toArray(); - } - } - - public static Contract createMultiSigContract(UInt160 publicKeyHash, int m, ECPoint ...publicKeys) { - Contract contract = new Contract(); - contract.redeemScript = createMultiSigRedeemScript(m, publicKeys); - contract.parameterList = Stream.generate(() -> ContractParameterType.Signature).limit(m).toArray(ContractParameterType[]::new); - contract.publicKeyHash = publicKeyHash; - return contract; - } - - public static byte[] createMultiSigRedeemScript(int m, ECPoint ...publicKeys) { - if (!(1 <= m && m <= publicKeys.length && publicKeys.length <= 1024)) - throw new IllegalArgumentException(); - try (ScriptBuilder sb = new ScriptBuilder()) { - sb.push(BigInteger.valueOf(m)); - ECPoint[] ecPoint = Arrays.stream(publicKeys).sorted((o1,o2) -> { - if(o1.getYCoord().toString().compareTo(o2.getYCoord().toString()) == 0) { - return o1.getXCoord().toString().compareTo(o2.getXCoord().toString()); - } - return o1.getYCoord().toString().compareTo(o2.getYCoord().toString()); - }).toArray(ECPoint[]::new); - - for (ECPoint publicKey : ecPoint) { - sb.push(publicKey.getEncoded(true)); - } - sb.push(BigInteger.valueOf(publicKeys.length)); - sb.add(ScriptOp.OP_CHECKMULTISIG); - return sb.toArray(); - } - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (!(obj instanceof Contract)) { - return false; - } - return scriptHash().equals(((Contract) obj).scriptHash()); - } - - @Override - public int hashCode() { - return scriptHash().hashCode(); - } - - @Override - public void deserialize(BinaryReader reader) throws IOException { - try { - publicKeyHash = reader.readSerializable(UInt160.class); - } catch (InstantiationException | IllegalAccessException ex) { - throw new RuntimeException(ex); - } - byte[] buffer = reader.readVarBytes(); - parameterList = new ContractParameterType[buffer.length]; - for (int i = 0; i < parameterList.length; i++) { - parameterList[i] = ContractParameterType.values()[buffer[i]]; - } - redeemScript = reader.readVarBytes(); - } - - @Override - public void serialize(BinaryWriter writer) throws IOException { - writer.writeSerializable(publicKeyHash); - byte[] buffer = new byte[parameterList.length]; - for (int i = 0; i < buffer.length; i++) { - buffer[i] = (byte)parameterList[i].ordinal(); - } - writer.writeVarBytes(buffer); - writer.writeVarBytes(redeemScript); - } -} diff --git a/src/main/java/DNA/Wallets/ContractParameterType.java b/src/main/java/DNA/Wallets/ContractParameterType.java deleted file mode 100644 index 459cf49..0000000 --- a/src/main/java/DNA/Wallets/ContractParameterType.java +++ /dev/null @@ -1,31 +0,0 @@ -package DNA.Wallets; - -/** - * 表示智能合约的参数类型 - */ -public enum ContractParameterType { - /** - * 签名 - */ - Signature, - /** - * 布尔 - */ - Boolean, - /** - * 整数 - */ - Integer, - /** - * 160位散列值 - */ - Hash160, - /** - * 256位散列值 - */ - Hash256, - /** - * 字节数组 - */ - ByteArray -} \ No newline at end of file diff --git a/src/main/java/DNA/Wallets/Wallet.java b/src/main/java/DNA/Wallets/Wallet.java deleted file mode 100644 index 4f653bc..0000000 --- a/src/main/java/DNA/Wallets/Wallet.java +++ /dev/null @@ -1,707 +0,0 @@ -package DNA.Wallets; - -import java.lang.Thread.State; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import javax.crypto.BadPaddingException; -import javax.crypto.IllegalBlockSizeException; - -import org.bouncycastle.math.ec.ECPoint; - -import DNA.Fixed8; -import DNA.UInt160; -import DNA.UInt256; -import DNA.Core.Block; -import DNA.Core.Blockchain; -import DNA.Core.IssueTransaction; -import DNA.Core.SignatureContext; -import DNA.Core.Transaction; -import DNA.Core.TransactionAttribute; -import DNA.Core.TransactionInput; -import DNA.Core.TransactionOutput; -import DNA.Core.Scripts.Program; -import DNA.Cryptography.AES; -import DNA.Cryptography.Base58; -import DNA.Cryptography.Digest; -import DNA.Cryptography.ECC; -import DNA.IO.Serializable; -import DNA.IO.Caching.TrackState; -import DNA.IO.Caching.TrackableCollection; -import DNA.Network.Rest.RestRuntimeException; -import DNA.sdk.helper.DataFormat; - -public abstract class Wallet implements AutoCloseable { - - public static final byte COIN_VERSION = 0x17; - private byte[] iv; - private byte[] masterKey; - private Map accounts; - private Map contracts; - private TrackableCollection coins; - private int current_height; - - private String path; - private Thread thread; - private boolean isrunning = false; - - protected final Object locker = new Object(); - - private Wallet(String path, byte[] passwordKey, boolean create) throws BadPaddingException, IllegalBlockSizeException { - this.path = path; - if (create) { - this.iv = AES.generateIV(); - this.masterKey = AES.generateKey(); - this.accounts = new HashMap(); - this.contracts = new HashMap(); - this.coins = new TrackableCollection(); - try { - this.current_height = Blockchain.current() != null ? Blockchain.current().headerHeight() + 1 : 1; - } catch (Exception ex) { - this.current_height = 1; - } - buildDatabase(); - saveStoredData("PasswordHash", Digest.sha256(passwordKey)); - saveStoredData("IV", iv); - saveStoredData("MasterKey", AES.encrypt(masterKey, passwordKey, iv)); - saveStoredData("Version", new byte[] { 0, 7, 0, 13 }); - saveStoredData("Height", ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(current_height).array()); - } else { - byte[] passwordHash = loadStoredData("PasswordHash"); - if (passwordHash != null && !Arrays.equals(passwordHash, Digest.sha256(passwordKey))) { - throw new BadPaddingException(); - } - this.iv = loadStoredData("IV"); - this.masterKey = AES.decrypt(loadStoredData("MasterKey"), passwordKey, iv); - this.accounts = Arrays.stream(loadAccounts()).collect(Collectors.toMap(p -> p.publicKeyHash, p -> p)); - this.contracts = Arrays.stream(loadContracts()).collect(Collectors.toMap(p -> p.scriptHash(), p -> p)); - this.coins = new TrackableCollection(loadCoins()); - this.current_height = ByteBuffer.wrap(loadStoredData("Height")).order(ByteOrder.LITTLE_ENDIAN).getInt(); -// checkCoinState(); - } - Arrays.fill(passwordKey, (byte) 0); - } - - public void checkCoinState() { - Coin[] spending = findSpendingCoins(); - if(spending == null || spending.length == 0) { - return; - } - Arrays.stream(spending).filter(p -> { - Transaction tx = null; - try { - tx = Blockchain.current().getTransaction(p.input.prevHash); - } catch (Exception e) { - tx = null; - } - return tx == null; - }).forEach(p -> coins.get(p.input).setState(CoinState.Unspent)); - Coin[] changeset = coins.getChangeSet(Coin[]::new); - onSaveTransaction(null, new Coin[0], changeset); - coins.commit(); - } - - /** - * 启动同步线程 - */ - public void start() { - if(!isrunning) { - isrunning = true; - this.thread = new Thread(this::processBlocks); - this.thread.setDaemon(true); - this.thread.setName("Wallet.ProcessBlocks"); - this.thread.start(); - } - } - - /** - * 关闭同步线程 - */ - @Override - public void close() { - isrunning = false; - if (thread.getState() != State.NEW) { - try { - thread.join(); - } catch (InterruptedException ex) { - } - } - } - - - protected Wallet(String path, String password, boolean create) throws BadPaddingException, IllegalBlockSizeException { - this(path, AES.generateKey(password), create); - } - - protected void buildDatabase() { - } - - public static Fixed8 calculateClaimAmount(Iterable inputs) { - return Fixed8.ZERO; - } - - public boolean changePassword(String password_old, String password_new) { - byte[] passwordHash = loadStoredData("PasswordHash"); - if (!Arrays.equals(passwordHash, Digest.sha256(AES.generateKey(password_old)))) { - return false; - } - byte[] passwordKey = AES.generateKey(password_new); - try { - saveStoredData("MasterKey", AES.encrypt(masterKey, passwordKey, iv)); - return true; - } finally { - Arrays.fill(passwordKey, (byte)0); - } - } - - /** - * 账户/合约 - */ - public Account createAccount() { - byte[] privateKey = ECC.generateKey(); - Account account = createAccount(privateKey); - Arrays.fill(privateKey, (byte) 0); - return account; - } - - public Account createAccount(byte[] privateKey) { - Account account = new Account(privateKey); - synchronized (accounts) { - accounts.put(account.publicKeyHash, account); - } - return account; - } - - public void addContract(Contract contract) { - synchronized (accounts) { - if (!accounts.containsKey(contract.publicKeyHash)) { - throw new RuntimeException(); - } - synchronized(contracts) { - contracts.put(contract.scriptHash(), contract); - } - } - } - - public boolean containsAccount(ECPoint publicKey) { - return containsAccount(Program.toScriptHash(publicKey.getEncoded(true))); - } - - public boolean containsAccount(UInt160 publicKeyHash) { - synchronized (accounts) { - return accounts.containsKey(publicKeyHash); - } - } - - public boolean containsAddress(String address) { - return containsAddress(Wallet.toScriptHash(address)); - } - - public boolean containsAddress(UInt160 scriptHash) { - synchronized (contracts) { - return contracts.containsKey(scriptHash); - } - } - - public boolean deleteAccount(UInt160 publicKeyHash) { - synchronized (accounts) { - synchronized (contracts) { - for (Contract contract : contracts.values().stream().filter(p -> p.publicKeyHash == publicKeyHash).toArray(Contract[]::new)) { - deleteContract(contract.scriptHash()); - } - } - return accounts.remove(publicKeyHash) != null; - } - } - - public boolean deleteContract(UInt160 scriptHash) { - synchronized (contracts) { - synchronized (coins) { - Iterator iterator = coins.iterator(); - while (iterator.hasNext()) { - if (iterator.next().scriptHash.equals(scriptHash)) { - iterator.remove(); - } - } - coins.commit(); - return contracts.remove(scriptHash) != null; - } - } - } - - protected byte[] decryptPrivateKey(byte[] encryptedPrivateKey) throws IllegalBlockSizeException, BadPaddingException { - if (encryptedPrivateKey == null) { - throw new NullPointerException("encryptedPrivateKey"); - } - if (encryptedPrivateKey.length != 112) { - throw new IllegalArgumentException(); - } - return AES.decrypt(encryptedPrivateKey, masterKey, iv); - } - - protected byte[] encryptPrivateKey(byte[] decryptedPrivateKey) { - return AES.encrypt(decryptedPrivateKey, masterKey, iv); - } - - /** - * 小蚁币相关信息接口 - */ - public Coin[] findCoins() { - synchronized (coins) { - return coins.stream().filter(p -> p.getState() == CoinState.Unconfirmed || p.getState() == CoinState.Unspent).toArray(Coin[]::new); - } - } - - public Coin[] getCoin() { - return coins.stream().toArray(Coin[]::new); - } - - public Coin[] findSpendingCoins() { - synchronized (coins) { - return coins.stream().filter(p -> p.getState() == CoinState.Spending).toArray(Coin[]::new); - } - } - - public Coin[] findUnconfirmedCoins() { - synchronized (coins) { - return coins.stream().filter(p -> p.getState() == CoinState.Unconfirmed).toArray(Coin[]::new); - } - } - - public Coin[] findUnspentCoins() { - synchronized (coins) { - return coins.stream().filter(p -> p.getState() == CoinState.Unspent).toArray(Coin[]::new); - } - } - - public Coin[] findUnspentCoins(UInt256 asset_id, Fixed8 amount) { - return findUnspentCoins(asset_id, amount, null); - } - - public Coin[] findUnspentCoins(UInt256 asset_id, Fixed8 amount, UInt160 from) { - synchronized (coins) { - Stream unspents = coins.stream().filter(p -> p.getState() == CoinState.Unspent); - if (from != null) { - unspents = unspents.filter(p -> p.scriptHash.equals(from)); - } - return findUnspentCoins(unspents, asset_id, amount); - } - } - - protected static Coin[] findUnspentCoins(Stream unspents, UInt256 asset_id, Fixed8 amount) { - Coin[] unspents_asset = unspents.filter(p -> p.assetId.equals(asset_id)).toArray(Coin[]::new); - Fixed8 sum = Fixed8.sum(unspents_asset, p -> p.value); - if (sum.compareTo(amount) < 0) throw new RuntimeException(DataFormat.getErrorDesc4NoBalance(String.format("insuficient balance, sum=%s, amount=%s", sum, amount))); - if (sum.equals(amount)) return unspents_asset; - Arrays.sort(unspents_asset, (a, b) -> -a.value.compareTo(b.value)); - int i = 0; - while (unspents_asset[i].value.compareTo(amount) <= 0) - amount = amount.subtract(unspents_asset[i++].value); - if (amount.equals(Fixed8.ZERO)) { - return Arrays.stream(unspents_asset).limit(i).toArray(Coin[]::new); - } else { - Coin[] result = new Coin[i + 1]; - System.arraycopy(unspents_asset, 0, result, 0, i); - for (int j = unspents_asset.length - 1; j >= 0; j--) - if (unspents_asset[j].value.compareTo(amount) >= 0) { - result[i] = unspents_asset[j]; - break; - } - return result; - } - } - - public Coin[] getUnclaimedCoins() { - synchronized (coins) { - return coins.stream().filter(p -> p.getState() == CoinState.Spent).toArray(Coin[]::new); - } - } - - public Fixed8 getAvailable(UInt256 asset_id) { - synchronized (coins) { - return Fixed8.sum(coins.stream().filter(p -> p.getState() == CoinState.Unspent && p.assetId.equals(asset_id)).toArray(Coin[]::new), p -> p.value); - } - } - - public Fixed8 getBalance(UInt256 asset_id) { - synchronized (coins) { - return Fixed8.sum(coins.stream().filter(p -> (p.getState() == CoinState.Unconfirmed || p.getState() == CoinState.Unspent) && p.assetId.equals(asset_id)).toArray(Coin[]::new), p -> p.value); - } - } - - public UInt160 getChangeAddress() { - synchronized (contracts) { - return contracts.values().stream().filter(p -> p.isStandard()).findAny().map(p -> p.scriptHash()).orElse(contracts.keySet().stream().findAny().get()); - } - } - - /** - * 账户相关信息接口 - */ - public Account getAccount(ECPoint publicKey) { - return getAccount(Program.toScriptHash(publicKey.getEncoded(true))); - } - - public Account getAccount(UInt160 publicKeyHash) { - synchronized (accounts) { - if (!accounts.containsKey(publicKeyHash)) - return null; - return accounts.get(publicKeyHash); - } - } - - public Account getAccountByScriptHash(UInt160 scriptHash) { - synchronized (accounts) { - synchronized (contracts) { - if (!contracts.containsKey(scriptHash)) - return null; - return accounts.get(contracts.get(scriptHash).publicKeyHash); - } - } - } - - public Account[] getAccounts() { - synchronized (accounts) { - return accounts.values().toArray(new Account[accounts.size()]); - } - } - - /** - * 合约相关信息接口 - */ - public Contract getContract(String address) { - return getContract(toScriptHash(address)); - } - - public Contract getContract(UInt160 scriptHash) { - synchronized (contracts) { - if (!contracts.containsKey(scriptHash)) - return null; - return contracts.get(scriptHash); - } - } - - public Contract[] getContracts() { - synchronized (contracts) { - return contracts.values().toArray(new Contract[contracts.size()]); - } - } - - public Contract[] getContracts(UInt160 publicKeyHash) { // 多签名合约:一个公钥和可以创建多个合约 - synchronized (contracts) { - return contracts.values().stream().filter(p -> p.publicKeyHash.equals(publicKeyHash)).toArray(Contract[]::new); - } - } - - /** - * 地址(全称:合约地址)-账户-合约 - */ - public UInt160[] getAddresses() { - synchronized (contracts) { - return contracts.keySet().toArray(new UInt160[contracts.size()]); - } - } - public String getAddressByPubKeyHash(UInt160 publicKeyHash) {// 一个公钥可以创建多个合约 - Contract[] cons = getContracts(publicKeyHash); - if(cons.length != 1) { - throw new RuntimeException("Multi address"); - } - return cons[0].address(); - } - - public static byte[] getPrivateKeyFromWIF(String wif) { - if (wif == null) throw new NullPointerException(); - byte[] data = Base58.decode(wif); - if (data.length != 38 || data[0] != (byte)0x80 || data[33] != 0x01) - throw new IllegalArgumentException(); - byte[] checksum = Digest.sha256(Digest.sha256(data, 0, data.length - 4)); - for (int i = 0; i < 4; i++) - if (data[data.length - 4 + i] != checksum[i]) - throw new IllegalArgumentException(); - byte[] privateKey = new byte[32]; - System.arraycopy(data, 1, privateKey, 0, privateKey.length); - Arrays.fill(data, (byte) 0); - return privateKey; - } - - public Account importAccount(String wif) { - byte[] privateKey = getPrivateKeyFromWIF(wif); - Account account = createAccount(privateKey); - Arrays.fill(privateKey, (byte) 0); - return account; - } - - protected boolean isWalletTransaction(Transaction tx) { - synchronized (contracts) { - if (Arrays.stream(tx.outputs).anyMatch(p -> contracts.containsKey(p.scriptHash))) { - return true; - } - if (Arrays.stream(tx.scripts).anyMatch(p -> contracts.containsKey(Program.toScriptHash(p.parameter)))) { - return true; - } - } - return false; - } - - protected abstract Account[] loadAccounts(); - - protected abstract Contract[] loadContracts(); - - protected abstract Coin[] loadCoins(); - - protected abstract byte[] loadStoredData(String name); - - protected abstract void saveStoredData(String name, byte[] value); - - public Map LoadTransactions() { return null;} - - public T makeTransaction(T tx, Fixed8 fee) throws CoinException { - return makeTransaction(tx, fee, null); - } - - public T makeTransaction(T tx, Fixed8 fee, UInt160 from) throws CoinException{ - if (tx.outputs == null) throw new IllegalArgumentException("tx.output is null"); - if (tx.attributes == null) tx.attributes = new TransactionAttribute[0]; - fee = fee.add(tx.systemFee()); - Map pay_total = Arrays.stream(tx instanceof IssueTransaction ? new TransactionOutput[0] : tx.outputs).collect(Collectors.groupingBy(p -> p.assetId)).entrySet().stream().collect(Collectors.toMap(p -> p.getKey(), p -> Fixed8.sum(p.getValue().toArray(new TransactionOutput[0]), o -> o.value))); - Map pay_coins = null; - try { - pay_coins = pay_total.entrySet().stream().collect(Collectors.toMap(p -> p.getKey(), p -> findUnspentCoins(p.getKey(), p.getValue(), from))); - } catch (CoinRuntimeException ex) { - throw new CoinException(ex.getMessage(), ex); - } - if (pay_coins.values().stream().anyMatch(p -> p == null)) throw new CoinException(DataFormat.getErrorDesc4NoBalance("insuficient balance")); - Map input_sum = pay_coins.entrySet().stream().collect(Collectors.toMap(p -> p.getKey(), p -> Fixed8.sum(p.getValue(), c -> c.value))); - UInt160 change_address = from == null ? getChangeAddress() : from; - List outputs_new = new ArrayList(Arrays.asList(tx.outputs)); - for (Entry entry : input_sum.entrySet()) { - Fixed8 pay = pay_total.get(entry.getKey()); - if (entry.getValue().compareTo(pay) > 0) { - TransactionOutput output = new TransactionOutput(); - output.assetId = entry.getKey(); - output.value = entry.getValue().subtract(pay); - output.scriptHash = change_address; - outputs_new.add(output); - } - } - tx.inputs = pay_coins.values().stream().flatMap(p -> Arrays.stream(p)).map(p -> p.input).toArray(TransactionInput[]::new); - tx.outputs = outputs_new.toArray(new TransactionOutput[outputs_new.size()]); - return tx; - } - - protected abstract void onProcessNewBlock(Block block, Coin[] added, Coin[] changed, Coin[] deleted); // for synchronize - protected abstract void onSaveTransaction(Transaction tx, Coin[] added, Coin[] changed); // for wallet - - private void processBlocks() { - while (isrunning) { - Blockchain blockchain = Blockchain.current(); - while (true) { - int height; - try { - height = blockchain == null ? 0 : blockchain.height(); - } catch (Exception ex) { - break; - } - if (current_height > height || !isrunning) { - break; - } - synchronized (locker) { - Block block; - try { - block = blockchain.getBlock(current_height); - } catch (Exception ex) { - ex.printStackTrace(); - break; - } - if (block != null) { - processNewBlock(block); - } - } - } - try { - for (int i = 0; i < 20 && isrunning; i++) { - Thread.sleep(100); - } - } catch (InterruptedException ex) { - break; - } - } - } - private void processNewBlock(Block block) { - Coin[] changeset; - synchronized (contracts) { - synchronized (coins) { - // 1. 更新内存coin - // tx.output - for (Transaction tx : block.transactions) { - for (int index = 0; index < tx.outputs.length; ++index) { - TransactionOutput output = tx.outputs[index]; - if (contracts.containsKey(output.scriptHash)) { - TransactionInput key = new TransactionInput(); - key.prevHash = tx.hash(); - key.prevIndex = (short)index; - if (coins.containsKey(key)) { - coins.get(key).setState(CoinState.Unspent); // change Unconfimed to Unspent - } else { - Coin coin = new Coin(); - coin.input = key; - coin.assetId = output.assetId; - coin.value = output.value; - coin.scriptHash = output.scriptHash; - coin.setState(CoinState.Unspent); // add unspent coin - coins.add(coin); - } - } - } - } - // tx.input - for (Transaction tx : block.transactions) { - for (TransactionInput input : tx.getAllInputs().toArray(TransactionInput[]::new)) { - if (coins.containsKey(input)) { - coins.get(input).setState(CoinState.Spent); // change spending to spent - } - } - } - // 2. 更新入库coin/tx/height - changeset = coins.getChangeSet(Coin[]::new); - Coin[] added = Arrays.stream(changeset).filter(p -> p.getTrackState() == TrackState.Added).toArray(Coin[]::new); - Coin[] changed = Arrays.stream(changeset).filter(p -> p.getTrackState() == TrackState.Changed).toArray(Coin[]::new); - Coin[] deleted = Arrays.stream(changeset).filter(p -> p.getTrackState() == TrackState.Deleted).toArray(Coin[]::new); - onProcessNewBlock(block, added, changed, deleted); - coins.commit(); - current_height++; - } - } - } - - public void rebuild() { - synchronized (locker) { - synchronized (coins) { - coins.clear(); - coins.commit(); - current_height = 1; - } - } - } - - /** - * UserWallet发送交易前,存储Tx - * @param tx - * @return - */ - public boolean saveTransaction(Transaction tx) { - Coin[] changeset; - synchronized (contracts) { - synchronized (coins) { - if (tx.getAllInputs().anyMatch(p -> !coins.containsKey(p) - || coins.get(p).getState() != CoinState.Unspent)) { - return false; - } - // 更新内存coin - for (TransactionInput input : tx.getAllInputs().toArray(TransactionInput[]::new)) { - coins.get(input).setState(CoinState.Spending); - } - for (int i = 0; i < tx.outputs.length; i++) { - if (contracts.containsKey(tx.outputs[i].scriptHash)) { - Coin coin = new Coin(); - coin.input = new TransactionInput(); - coin.input.prevHash = tx.hash(); - coin.input.prevIndex = (short)i; - coin.assetId = tx.outputs[i].assetId; - coin.value = tx.outputs[i].value; - coin.scriptHash = tx.outputs[i].scriptHash; - coin.setState(CoinState.Unconfirmed); - coins.add(coin); - } - } - // 更新入库coin/tx - changeset = coins.getChangeSet(Coin[]::new); - if (changeset.length > 0) { - Coin[] added = Arrays.stream(changeset).filter(p -> p.getTrackState() == TrackState.Added).toArray(Coin[]::new); - Coin[] changed = Arrays.stream(changeset).filter(p -> p.getTrackState() == TrackState.Changed).toArray(Coin[]::new); - onSaveTransaction(tx, added, changed); - coins.commit(); - } - } - } - return true; - } - - public boolean sign(SignatureContext context) { - boolean fSuccess = false; - for (UInt160 scriptHash : context.scriptHashes) { - Contract contract = getContract(scriptHash); - if (contract == null) { - continue; - } - Account account = getAccountByScriptHash(scriptHash); - if (account == null) { - continue; - } - byte[] signature = context.signable.sign(account); - fSuccess |= context.add(contract, account.publicKey, signature); - } - return fSuccess; - } - - public static String toAddress(UInt160 scriptHash) { - byte[] data = new byte[25]; - data[0] = COIN_VERSION; - System.arraycopy(scriptHash.toArray(), 0, data, 1, 20); - byte[] checksum = Digest.sha256(Digest.sha256(data, 0, 21)); - System.arraycopy(checksum, 0, data, 21, 4); - return Base58.encode(data); - } - - public static UInt160 toScriptHash(String address) { - byte[] data = Base58.decode(address); - if (data.length != 25) { - throw new IllegalArgumentException(); - } - if (data[0] != COIN_VERSION) { - throw new IllegalArgumentException(); - } - byte[] checksum = Digest.sha256(Digest.sha256(data, 0, 21)); - for (int i = 0; i < 4; i++) { - if (data[data.length - 4 + i] != checksum[i]) { - throw new IllegalArgumentException(); - } - } - byte[] buffer = new byte[20]; - System.arraycopy(data, 1, buffer, 0, 20); - return new UInt160(buffer); - } - - public String dbPath() { - return path; - } - - - public int getBlockHeight(){ - try { - return Blockchain.current().height(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - public int getWalletHeight() { - return current_height; - } - - static Block from(String ss) { - try { - return Serializable.from(DNA.Helper.hexToBytes(ss), Block.class); - } catch (InstantiationException | IllegalAccessException e) { - throw new RestRuntimeException("Block.deserialize(height) failed", e); - } - } -} diff --git a/src/main/java/DNA/Websocket/Utils/GetBlockTransactionUtils.java b/src/main/java/DNA/Websocket/Utils/GetBlockTransactionUtils.java deleted file mode 100644 index e2a1d6b..0000000 --- a/src/main/java/DNA/Websocket/Utils/GetBlockTransactionUtils.java +++ /dev/null @@ -1,29 +0,0 @@ -package DNA.Websocket.Utils; - -import DNA.Core.Block; -import DNA.IO.JsonSerializable; -import DNA.IO.Json.JObject; - -/** - * Parsing tool class - * - * @author 12146 - * - */ -public class GetBlockTransactionUtils { - - /** - * Parse block for transaction - * - * @param ss json data obtained from websocket server - * @return transaction list - */ - public static Block from(String ss) { -// try { -// return JsonSerializable.from(JObject.parse(ss), Block.class); -// } catch (InstantiationException | IllegalAccessException e) { -// throw new RuntimeException("Block Parsing exception"); -// } - return null; - } -} \ No newline at end of file diff --git a/src/main/java/DNA/Websocket/WebSocketClient.java b/src/main/java/DNA/Websocket/WebSocketClient.java deleted file mode 100644 index 6341494..0000000 --- a/src/main/java/DNA/Websocket/WebSocketClient.java +++ /dev/null @@ -1,6 +0,0 @@ -package DNA.Websocket; - - -public class WebSocketClient { - -} diff --git a/src/main/java/DNA/sdk/dbpool/ConnectionManager.java b/src/main/java/DNA/sdk/dbpool/ConnectionManager.java deleted file mode 100644 index ea6b8c4..0000000 --- a/src/main/java/DNA/sdk/dbpool/ConnectionManager.java +++ /dev/null @@ -1,78 +0,0 @@ -package DNA.sdk.dbpool; - -import java.sql.Connection; -import java.sql.SQLException; -import java.sql.Statement; - -/** - * 连接管理器 - * - * @author 12146 - * - */ -class ConnectionManager { - String sql = "select count(*) from dual"; - private int interval = 1000; - private static int count = 1; - public boolean isBusy = false; - private Connection conn; - private DBPool pool; - private boolean stop = false; - public ConnectionManager(DBPool pool, Connection conn) { - this.conn = conn; - this.pool = pool; - Thread tt = new Thread(this::run, "ConnPool_"+(++count)); - tt.setDaemon(true); - tt.start(); - } - - private void run() { - while(!stop) { - try { - ping(); - Thread.sleep(interval); -// PrintHelper.printDebug(Thread.currentThread().getName() + " conn is running......"); - } catch (SQLException e) { -// PrintHelper.printError(Thread.currentThread().getName() + "conn is disconnected, start to reOpen."); - reOpenConn(); - break; - } catch (InterruptedException e) { - } - } - } - private void ping() throws SQLException { - Statement stmt = null; - try { - stmt = conn.createStatement(); - stmt.execute(sql); - } catch (SQLException e) { - throw e; - } finally { - if(stmt != null) { - try { - stmt.close(); - } catch (SQLException e) { - } - stmt = null; - } - } - } - - private void reOpenConn() { - pool.reOpen(conn); - } - - public Connection getConn() { - return conn; - } - - public void close() { - stop = true; - if(conn != null) { - try { - conn.close(); - } catch (SQLException e) { - } - } - } -} \ No newline at end of file diff --git a/src/main/java/DNA/sdk/dbpool/DBConsts.java b/src/main/java/DNA/sdk/dbpool/DBConsts.java deleted file mode 100644 index 9b1039b..0000000 --- a/src/main/java/DNA/sdk/dbpool/DBConsts.java +++ /dev/null @@ -1,9 +0,0 @@ -package DNA.sdk.dbpool; - -public class DBConsts { - public static String dbUrl; - public static String dbDriver; - public static String dbUser; - public static String dbPassword; - public static int dbPoolCount; -} diff --git a/src/main/java/DNA/sdk/dbpool/DBParamInitailer.java b/src/main/java/DNA/sdk/dbpool/DBParamInitailer.java deleted file mode 100644 index 6f09538..0000000 --- a/src/main/java/DNA/sdk/dbpool/DBParamInitailer.java +++ /dev/null @@ -1,71 +0,0 @@ -package DNA.sdk.dbpool; - -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.Properties; - -public class DBParamInitailer { - private static final String dbName = "db.name"; - private static String dbUrl = "db.${}.url"; - private static String dbDriver = "db.${}.driver"; - private static String dbUser = "db.${}.user"; - private static String dbPswd = "db.${}.password"; - private static String dbPool = "db.${}.dbpool"; - - public static void init(String dbUrl, String dbDriver, String dbUser, String dbPswd, int dbPool) { - DBConsts.dbUrl = dbUrl; - DBConsts.dbDriver = dbDriver; - DBConsts.dbUser = dbUser; - DBConsts.dbPassword = dbPswd; - DBConsts.dbPoolCount = dbPool; - } - public static void init(String config) { - initCfg(config); - } - private static void initCfg(String cfg) { - Properties prop=new Properties(); - try(InputStreamReader reader = new InputStreamReader(new FileInputStream(cfg))) { - prop.load(reader); - initDbPool(prop); - } catch (IOException e ) { - e.printStackTrace(); - } - } - private static void initDbPool(Properties prop) { - String rr = prop.getProperty(dbName); - - DBConsts.dbUrl = prop.getProperty(replace(dbUrl, rr)); - DBConsts.dbDriver = prop.getProperty(replace(dbDriver, rr)); - DBConsts.dbUser = prop.getProperty(replace(dbUser, rr)); - DBConsts.dbPassword = prop.getProperty(replace(dbPswd, rr)); - String dbPoolCount = prop.getProperty(replace(dbPool, rr)); - int numInt = 1; - try { - numInt = Integer.parseInt(dbPoolCount); - } catch (Exception e) { - numInt = 3; - } - DBConsts.dbPoolCount = numInt; - } - - private static String replace(String ss, String rr) { -// return ss.replace("${}", rr); - String r = ss.replace("${}", rr); - System.out.println(r); - return r; - } - - public static void main(String[] args) { - init("./control/db.ini"); - DBResource.getInstance(); - while(true) { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - } -} diff --git a/src/main/java/DNA/sdk/dbpool/DBPool.java b/src/main/java/DNA/sdk/dbpool/DBPool.java deleted file mode 100644 index 01eadb0..0000000 --- a/src/main/java/DNA/sdk/dbpool/DBPool.java +++ /dev/null @@ -1,116 +0,0 @@ -package DNA.sdk.dbpool; - -import java.io.Closeable; -import java.sql.Connection; -import java.sql.Driver; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -public class DBPool implements Closeable{ - public static final String url = DBConsts.dbUrl; - public static final String driver = DBConsts.dbDriver; - public static final String user = DBConsts.dbUser; - public static final String password = DBConsts.dbPassword; - private static final int connCount = DBConsts.dbPoolCount; - private Map connMap = new ConcurrentHashMap(); - - public DBPool() { - init(); - } - - private void init() { - if (loadDriver()) { - createPool(); - PrintHelper.printDebug("dbpool init finished"); - return; - } - PrintHelper.printError("Load database driver failed, please to check your db'driver..."); - } - - private boolean loadDriver() { - try { - DriverManager.registerDriver((Driver) Class.forName(driver).newInstance()); - return true; - } catch (Exception e) { - PrintHelper.printError(" Load Database driver fail : " + e); - } - return false; - } - private void createPool() { - for(int i=0; i !p.isBusy).findAny().orElse(null); - if(connMgr != null) { - connMgr.isBusy = true; - break; - } - PrintHelper.printError("Not find spare conn, please wait 1(s)....."); - sleep(); - } - return connMgr.getConn(); - } - public void freeConnection(Connection conn) { - if(connMap.containsKey(conn.toString())) { - ConnectionManager connMgr = connMap.get(conn.toString()); - connMgr.isBusy = false; - connMap.put(conn.toString(), connMgr); - } - } - public void close() { - connMap.values().stream().forEach(p -> p.close()); - } - -} \ No newline at end of file diff --git a/src/main/java/DNA/sdk/dbpool/DBResource.java b/src/main/java/DNA/sdk/dbpool/DBResource.java deleted file mode 100644 index aa66006..0000000 --- a/src/main/java/DNA/sdk/dbpool/DBResource.java +++ /dev/null @@ -1,31 +0,0 @@ -package DNA.sdk.dbpool; - -import java.sql.Connection; - -public class DBResource { - private static DBResource _instance = null; - public static DBResource getInstance() { - if(_instance == null) { - initInstance(); - } - return _instance; - } - private static synchronized void initInstance() { - if(_instance == null) { - _instance = new DBResource(); - } - } - private DBResource() { - if(dbpool == null) { - dbpool = new DBPool(); - } - } - - private DBPool dbpool = new DBPool(); - public Connection getConnection() { - return dbpool.getConnection(); - } - public void freeConnection(Connection conn) { - dbpool.freeConnection(conn); - } -} diff --git a/src/main/java/DNA/sdk/dbpool/DBSQLException.java b/src/main/java/DNA/sdk/dbpool/DBSQLException.java deleted file mode 100644 index dc639ff..0000000 --- a/src/main/java/DNA/sdk/dbpool/DBSQLException.java +++ /dev/null @@ -1,22 +0,0 @@ -package DNA.sdk.dbpool; - -public class DBSQLException extends RuntimeException { - - /** - * - */ - private static final long serialVersionUID = 1L; - - public DBSQLException(String msg) { - super(msg); - } - - public DBSQLException(String msg, Throwable t) { - super(msg, t); - } - - public DBSQLException(Throwable t) { - super(t); - } - -} \ No newline at end of file diff --git a/src/main/java/DNA/sdk/dbpool/PrintHelper.java b/src/main/java/DNA/sdk/dbpool/PrintHelper.java deleted file mode 100644 index 4b2cad7..0000000 --- a/src/main/java/DNA/sdk/dbpool/PrintHelper.java +++ /dev/null @@ -1,35 +0,0 @@ -package DNA.sdk.dbpool; - -import java.text.SimpleDateFormat; -import java.util.Date; - -class PrintHelper { - static String sdf = "yyyy-MM-dd HH:mm:ss.SSS"; - - static void printErrorConsole(String str) { - print(str, false); - } - static void printDebugConsole(String str) { - print(str, true); - } - static void print(String str, boolean isDebug) { - if(isDebug) - System.out.println(getNow() + str); - else - System.err.println(getNow() + str); - } - static void print() { - System.out.println(); - } - static String getNow() { - return new SimpleDateFormat(sdf).format(new Date()) + " "; - } - - public static void printError(String str) { - printErrorConsole(str); - } - public static void printDebug(String str) { - printDebugConsole(str); - } - -} \ No newline at end of file diff --git a/src/main/java/DNA/sdk/helper/DataFormat.java b/src/main/java/DNA/sdk/helper/DataFormat.java deleted file mode 100644 index 42dd34d..0000000 --- a/src/main/java/DNA/sdk/helper/DataFormat.java +++ /dev/null @@ -1,112 +0,0 @@ -package DNA.sdk.helper; - -import com.alibaba.fastjson.JSON; - -public class DataFormat { - public static String getCodeMsg(String code, String message) { - return ExceptionConst.Json_CodeMessage.replace(ExceptionConst.Flag_Code, code).replace(ExceptionConst.Flag_Message, message); - } - - public static String getErrorDesc4ComposeTrfTransaction(String message) { - return getErrorDesc(ExceptionConst.Code_getErrorDesc4ComposeTrfTransaction, message); - } - public static String getErrorDesc4ComposeIssTransaction(String message) { - return getErrorDesc(ExceptionConst.Code_getErrorDesc4ComposeIssTransaction, message); - } - public static String getErrorDesc4DeserializeTransaction(String message) { - return getErrorDesc(ExceptionConst.Code_Deserialize_err_Transaction, message); - } - public static String getErrorDesc4DeserializeBlock(String message) { - return getErrorDesc(ExceptionConst.Code_Deserialize_err_Block, message); - } - public static String getErrorDesc4Encrypto(String message) { - return getErrorDesc(ExceptionConst.Code_Encrypto, message); - } - public static String getErrorDesc4Decrypto(String message) { - return getErrorDesc(ExceptionConst.Code_Decrypto, message); - } - public static String getErrorDesc4NoBalance(String message) { - return getErrorDesc(ExceptionConst.Code_NoBalance, message); - } - public static String getErrorDesc4DatabaseErr(String message) { - return getErrorDesc(ExceptionConst.Code_DatabaseErr, message); - } - public static String getErrorDesc4NetworkErr(String message) { - return getErrorDesc(ExceptionConst.Code_NetWorkErr, message); - } - public static String getErrorDesc(long error, String message) { - return String.format(ExceptionConst.Json_ErrorDesc, error, message); - } - - public static void main(String[] args) { - String ss = getCodeMsg("60001", "No available balance"); - CM cm = JSON.parseObject(ss, CM.class); - System.out.println(cm); - ss = getErrorDesc4ComposeIssTransaction("failed to send issvervice"); - ED ed = JSON.parseObject(ss, ED.class); - System.out.println(ed); - - } -} -class CM { - public String Code; - public String Message; - @Override - public String toString() { - return "CM [Code=" + Code + ", Message=" + Message + "]"; - } -} -class ED { - public long Error; - public String Desc; - @Override - public String toString() { - return "ED [Error=" + Error + ", Desc=" + Desc + "]"; - } -} -class ExceptionConst { - public static final String Flag_Code = "CCC"; - public static final String Flag_Message = "MMM"; - public static final String Json_CodeMessage = "{\"Code\":\"CCC\",\"Message\":\"MMM\"}"; - public static final String Json_ErrorDesc = "{\"Error\":%s,\"Desc\":\"%s\"}"; - public static final long Code_NetWorkErr = 60000; - public static final long Code_DatabaseErr = 60001; - public static final long Code_NoBalance = 60002; - public static final long Code_Decrypto = 60003; - public static final long Code_Encrypto = 60004; - public static final long Code_Deserialize_err_Block = 60005; - public static final long Code_Deserialize_err_Transaction = 60006; - public static final long Code_getErrorDesc4ComposeIssTransaction = 60007; - public static final long Code_getErrorDesc4ComposeTrfTransaction = 60008; -} - -/** - -异常代码: -60000 网络错误 -60001 数据库操作错误 -60002 余额不足 -60003 解密错误 -60004 加密错误 -60005 反序列化Block错误 -60006 反序列化Transaction错误 -60007 分发组合交易错误 -60008 资产注销交易错误 - - -捕获到的异常可以通过获取异常信息查看异常代码及说明,异常信息为json格式,eg: -try { - -} catch (CoinException ex) { - String exMsg = ex.getMessage(); - ExMsg rr = JSON.parseObject(exMsg, ExMsg.class); - // 判断异常代码 -} -class ExMsg { - public long Error; - public String Desc; -} - - - - */ diff --git a/src/main/java/DNA/sdk/helper/OnChainSDKHelper.java b/src/main/java/DNA/sdk/helper/OnChainSDKHelper.java deleted file mode 100644 index 5e927bf..0000000 --- a/src/main/java/DNA/sdk/helper/OnChainSDKHelper.java +++ /dev/null @@ -1,382 +0,0 @@ -package DNA.sdk.helper; - -import java.util.Arrays; -import java.util.Date; - -import org.bouncycastle.math.ec.ECPoint; - -import DNA.UInt256; -import DNA.Core.Block; -import DNA.Core.Blockchain; -import DNA.Core.RecordTransaction; -import DNA.Core.RegisterTransaction; -import DNA.Core.Transaction; -import DNA.Core.TransactionAttribute; -import DNA.Core.TransactionInput; -import DNA.Core.TransactionOutput; -import DNA.Core.Scripts.Program; -import DNA.IO.Caching.TrackableCollection; -import DNA.Implementations.Wallets.SQLite.UserWallet; -import DNA.Wallets.Account; -import DNA.Wallets.Coin; -import DNA.Wallets.Contract; -import DNA.Wallets.Wallet; - -/** - * SDK帮助类 - * - * @author 12146 - * - */ -public class OnChainSDKHelper { - - public static String byte2str(byte[] bt) { - if(bt == null || bt.length == 0) { - return ""; - } - StringBuilder sb = new StringBuilder(); - for(int i=0; i 0) { - Arrays.stream(bb.transactions).forEach(p -> print(p)); - Arrays.stream(bb.transactions).forEach(p -> { - sb.append("\n\t").append("type:"+ p.type.toString()); - sb.append("\n\t").append("version:"+p.version); - sb.append("\n\t").append("nonce:"+p.nonce); - sb.append("\n\t").append("attrs:"+p.attributes.length); - if(p.attributes.length > 0) { - Arrays.stream(p.attributes).forEach(i -> { - sb.append("\n\t\t").append("usage:"+i.usage.toString()); - sb.append("\n\t\t").append("data:"+toHexString(i.data)); - }); - } - sb.append("\n\t").append("inputs:"+p.inputs.length); - if(p.inputs.length > 0) { - Arrays.stream(p.inputs).forEach(j -> { - sb.append("\n\t\t").append("prevHash:"+j.prevHash.toString()); - sb.append("\n\t\t").append("prevIndx:"+j.prevIndex); - }); - } - sb.append("\n\t").append("outputs:"+p.outputs.length); - if(p.outputs.length > 0) { - Arrays.stream(p.outputs).forEach(k -> { - sb.append("\n\t\t").append("assetId:"+k.assetId.toString()); - sb.append("\n\t\t").append("amount:"+k.value.toLong()); - sb.append("\n\t\t").append("scriptHash:"+k.scriptHash.toString()); - }); - } - sb.append("\n\t").append("scripts:"+p.scripts.length); - if(p.inputs.length > 0) { - Arrays.stream(p.scripts).forEach(i -> { - sb.append("\n\t\t").append("redeemScript:"+toHexString(i.parameter)); - sb.append("\n\t\t").append("redeemScript:"+toHexString(i.parameter)); - }); - } - }); - } - return sb.toString(); - } - private static void print(Block blk) { - print("Height:"+blk.height); - print("nonce :"+blk.nonce); - print("versio:"+blk.version); - print("hash :"+blk.hash()); - print("nextM :"+blk.nextMiner); - print("prevB :"+blk.prevBlock); - print("prevB :"+blk.timestamp); - print("prevB :"+System.currentTimeMillis()); - print("bkTm :"+new Date(blk.timestamp * 1000L)); - print("sc.toS:\n\t"+toHexString(blk.script.parameter) + "\n\t"+toHexString(blk.script.code)); - print("bk.mer:"+blk.merkleRoot); - print("blk.tx.len:"+blk.transactions.length); - for(Transaction tx: blk.transactions) { - print(tx); - } - } - - public static void printWallet(UserWallet userWallet) { - print(userWallet); - } - private static void print(UserWallet userWallet) { - print("\nts.printWallet.......................................................................[st]"); - print("path:"+userWallet.getWalletPath()); - int c = 0; - - // 1 - print("accs.......................start");c = 0; - for(Account acc: userWallet.getAccounts()) { - print("acc......................."+(++c)); - print(acc); - } - print(); - // 2 - print("contracts.......................start");c = 0; - for(Contract con: userWallet.getContracts()) { - print("contract......................."+(++c)); - print(con); - } - print(); - // 3 - print("trans....................start");c = 0; - for(Transaction tx: userWallet.LoadTransactions().keySet()) { - print("tran...................."+(++c)); - print(tx); - } - print(); - // 4 - long amount = 0L; - print("findCoins........................start"); c=0; - for(Coin coin: userWallet.findCoins()) { - print("coin............."+(++c)); - print(coin); - amount += coin.value.toLong(); - } - print("SpentAmount:"+amount); - print(); - // 5 - amount = 0L; - print("findUnspentCoins.................start");c=0; - for(Coin coin: userWallet.findUnspentCoins()) { - print("unspent........."+(++c)); - print(coin); - amount += coin.value.toLong(); - print(coin.value + "----" + amount); - } - - // 5 - amount = 0L; - print("getCoin.................start");c=0; - for(Coin coin: userWallet.getCoin()) { - print("getCoin........."+(++c)); - print(coin); - } - print(); - - print("\nts.printWallet.......................................................................[ed]"); - - } - - public static String getbyteStr(byte[] bs) { - StringBuilder sb = new StringBuilder(); - for(byte b: bs) { - sb.append(" ").append(Byte.toUnsignedInt(b)); - - } - return sb.substring(1); - } - - public static void print(Account acc) { - // addr - print("acc..................st"); - print("acc.addr:"+Wallet.toAddress(Program.toScriptHash(Contract.createSignatureRedeemScript(acc.publicKey)))); - print("acc.uint:"+Program.toScriptHash(Contract.createSignatureRedeemScript(acc.publicKey)).toString()); - print("acc.uint(byte):"+getbyteStr(Program.toScriptHash(Contract.createSignatureRedeemScript(acc.publicKey)).toArray())); - print("acc.uint(hex):"+toHexString(Program.toScriptHash(Contract.createSignatureRedeemScript(acc.publicKey)).toArray())); - // pubKey - ECPoint pubKey = acc.publicKey; - String pubKeyStr = toHexString(acc.publicKey.getEncoded(true)); - print(String.format("acc.PubKey:\n\tECPoint: %s\n\tPubKStr:%s", pubKey, pubKeyStr)); - - // priKey - String priKey = toHexString(acc.privateKey); - print(String.format("acc.PriKey:\n\tHEX:%s", priKey)); - - String wif = acc.export(); - print(String.format("\tWIF:%s", wif)); - - // pubKeyHash - print("acc.PubKeyHash:"+acc.publicKeyHash.toString()); - print("acc..................ed"); - } - - public static void print(Contract con) { - print("contract.address:"+con.address()); - print("contract.publicKey:"+con.publicKeyHash.toString()); - } - - public static void print(Coin coin) { - print("coin.addr:"+coin.address()); - print("coin.toSt:"+coin.toString()); - print("coin.assetId:"+coin.assetId.toString()); - print("coin.scriptHash:"+coin.scriptHash); - print("coin.value:"+coin.value.toString()); - print("coin.state:"+coin.getState()); - print("coin.TrackState:"+coin.getTrackState()); - print("coin.input.prevHash:"+coin.input.prevHash); - } - - public static void print(TrackableCollection coins, String key) { - print("Wallet.print.coins.......................[start]............."+key); - coins.forEach(p -> { - print("1:"+p.assetId); - print("2:"+p.input.prevHash.toString()); - print("3:"+p.scriptHash.toString()); - print("4:"+p.value); - print("5:"+p.address()); - print("6:"+p.getState()); - print("7:"+p.getTrackState()); - print("8:"+p.key().prevHash); - }); - print("Wallet.print.coins.......................[end]................"+key); - } - - - - public static void print(String str) { - System.out.println(str); - } - public static void print() { - System.out.println(); - } -} diff --git a/src/main/java/DNA/sdk/info/account/AccountAsset.java b/src/main/java/DNA/sdk/info/account/AccountAsset.java deleted file mode 100644 index d260d55..0000000 --- a/src/main/java/DNA/sdk/info/account/AccountAsset.java +++ /dev/null @@ -1,22 +0,0 @@ -package DNA.sdk.info.account; - -import java.util.List; - -/** - * 账户资产 - * - * @author 12146 - * - */ -public class AccountAsset { - public String address; - public List canUseAssets; // 可用资产 - public List freezeAssets; // 冻结资产 - @Override - public String toString() { - return "AccountAsset [address=" + address + ", canUseAssets=" - + canUseAssets + ", freezeAssets=" + freezeAssets + "]"; - } - - -} \ No newline at end of file diff --git a/src/main/java/DNA/sdk/info/account/AccountInfo.java b/src/main/java/DNA/sdk/info/account/AccountInfo.java deleted file mode 100644 index 2c6c285..0000000 --- a/src/main/java/DNA/sdk/info/account/AccountInfo.java +++ /dev/null @@ -1,23 +0,0 @@ -package DNA.sdk.info.account; - -/** - * 账户信息 - * - * @author 12146 - * - */ -public class AccountInfo { - public String address; // 合约地址 - public String pubkey; // 公钥 - public String prikey; // 私钥 - public String priwif; // 私钥wif - public String pkhash; // 公钥hash - @Override - public String toString() { - return "AccountInfo [address=" + address + ", pubkey=" + pubkey - + ", prikey=" + prikey + ", priwif=" + priwif + ", pkhash=" - + pkhash + "]"; - } - - -} \ No newline at end of file diff --git a/src/main/java/DNA/sdk/info/account/Asset.java b/src/main/java/DNA/sdk/info/account/Asset.java deleted file mode 100644 index 83117da..0000000 --- a/src/main/java/DNA/sdk/info/account/Asset.java +++ /dev/null @@ -1,18 +0,0 @@ -package DNA.sdk.info.account; - -/** - * 账户资产 - * - * @author 12146 - * - */ -public class Asset { - public String assetid; // 资产编号 - public long amount; // 资产数量 - @Override - public String toString() { - return "Asset [assetid=" + assetid + ", amount=" + amount + "]"; - } - - -} \ No newline at end of file diff --git a/src/main/java/DNA/sdk/info/asset/AssetInfo.java b/src/main/java/DNA/sdk/info/asset/AssetInfo.java deleted file mode 100644 index c48defe..0000000 --- a/src/main/java/DNA/sdk/info/asset/AssetInfo.java +++ /dev/null @@ -1,28 +0,0 @@ -package DNA.sdk.info.asset; - -/** - * 资产信息 - * - * @author 12146 - * - */ -public class AssetInfo { -// public String assetid; // 资产编号 -// public String assetname; // 资产名称 -// public long regAmount; // 注册数量 -// public String register; // 注册人地址 -// public String controller; // 控制人地址 - public String Name; - public int Precision; - public int AssetType; - public int RecordType; -// "Result":{"Name":"Token001","Precision":0,"AssetType":17,"RecordType":0} - @Override - public String toString() { - return "AssetInfo [Name=" + Name + ", Precision=" + Precision - + ", AssetType=" + AssetType + ", RecordType=" + RecordType - + "]"; - } - - -} \ No newline at end of file diff --git a/src/main/java/DNA/sdk/info/asset/UTXO2Info.java b/src/main/java/DNA/sdk/info/asset/UTXO2Info.java deleted file mode 100644 index 895d2ee..0000000 --- a/src/main/java/DNA/sdk/info/asset/UTXO2Info.java +++ /dev/null @@ -1,15 +0,0 @@ -package DNA.sdk.info.asset; - -import java.util.List; - -public class UTXO2Info { - public String AssetId; - public String AssetNme; - public List Utxo; - - @Override - public String toString() { - return "UTXO2Info [AssetId=" + AssetId + ", AssetNme=" + AssetNme - + ", Utxo=" + Utxo + "]"; - } -} diff --git a/src/main/java/DNA/sdk/info/asset/UTXOInfo.java b/src/main/java/DNA/sdk/info/asset/UTXOInfo.java deleted file mode 100644 index 7f6f010..0000000 --- a/src/main/java/DNA/sdk/info/asset/UTXOInfo.java +++ /dev/null @@ -1,13 +0,0 @@ -package DNA.sdk.info.asset; - -public class UTXOInfo { - public String Txid; - public String Index; - public long Value; - - @Override - public String toString() { - return "UTXOInfo [Txid=" + Txid + ", Index=" + Index + ", Value=" - + Value + "]"; - } -} diff --git a/src/main/java/DNA/sdk/info/mutil/TxJoiner.java b/src/main/java/DNA/sdk/info/mutil/TxJoiner.java deleted file mode 100644 index 0238c9f..0000000 --- a/src/main/java/DNA/sdk/info/mutil/TxJoiner.java +++ /dev/null @@ -1,14 +0,0 @@ -package DNA.sdk.info.mutil; - -/** - * Transaction Joiner, which mostly used to be ouputs of transaction, named recver - * and it includes receiver'address,assetid,and asset amount - * - * @author 12146 - * - */ -public class TxJoiner { - public String address; - public String assetid; - public long value; -} \ No newline at end of file diff --git a/src/main/java/DNA/sdk/info/transaction/TransactionInfo.java b/src/main/java/DNA/sdk/info/transaction/TransactionInfo.java deleted file mode 100644 index 1d8bf70..0000000 --- a/src/main/java/DNA/sdk/info/transaction/TransactionInfo.java +++ /dev/null @@ -1,24 +0,0 @@ -package DNA.sdk.info.transaction; - -import java.util.List; - -/** - * 交易信息 - * - * @author 12146 - * - */ -public class TransactionInfo { - public String txid; // 交易编号 - public String type; // 交易类型 - public List inputs; // 交易输入 - public List outputs; // 交易输出 - public String attrs; // 描述 - - - @Override - public String toString() { - return "TransactionInfo [txid=" + txid + ", type=" + type + ", inputs=" - + inputs + ", outputs=" + outputs + ", attrs=" + attrs + "]"; - } -} \ No newline at end of file diff --git a/src/main/java/DNA/sdk/info/transaction/TxInputInfo.java b/src/main/java/DNA/sdk/info/transaction/TxInputInfo.java deleted file mode 100644 index 69522f5..0000000 --- a/src/main/java/DNA/sdk/info/transaction/TxInputInfo.java +++ /dev/null @@ -1,19 +0,0 @@ -package DNA.sdk.info.transaction; - -/** - * 交易输入 - * - * @author 12146 - * - */ -public class TxInputInfo { - public String address; // 地址 - public String assetid; // 资产编号 - public long amount; // 资产数量 - - @Override - public String toString() { - return "TxInputInfo [address=" + address + ", assetid=" + assetid - + ", amount=" + amount + "]"; - } -} \ No newline at end of file diff --git a/src/main/java/DNA/sdk/info/transaction/TxOutputInfo.java b/src/main/java/DNA/sdk/info/transaction/TxOutputInfo.java deleted file mode 100644 index 5c287a7..0000000 --- a/src/main/java/DNA/sdk/info/transaction/TxOutputInfo.java +++ /dev/null @@ -1,19 +0,0 @@ -package DNA.sdk.info.transaction; - -/** - * 交易输出 - * - * @author 12146 - * - */ -public class TxOutputInfo { - public String address; // 地址 - public String assetid; // 资产编号 - public long amount; // 资产数量 - - @Override - public String toString() { - return "TxOutputInfo [address=" + address + ", assetid=" + assetid - + ", amount=" + amount + "]"; - } -} \ No newline at end of file diff --git a/src/main/java/DNA/sdk/wallet/AccountManager.java b/src/main/java/DNA/sdk/wallet/AccountManager.java deleted file mode 100644 index d2f2068..0000000 --- a/src/main/java/DNA/sdk/wallet/AccountManager.java +++ /dev/null @@ -1,812 +0,0 @@ -package DNA.sdk.wallet; - -import java.io.File; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import DNA.Fixed8; -import DNA.Helper; -import DNA.UInt160; -import DNA.UInt256; -import DNA.Core.AssetType; -import DNA.Core.Blockchain; -import DNA.Core.DestroyTransaction; -import DNA.Core.IssueTransaction; -import DNA.Core.RecordTransaction; -import DNA.Core.RecordType; -import DNA.Core.RegisterTransaction; -import DNA.Core.SignatureContext; -import DNA.Core.Transaction; -import DNA.Core.TransactionAttribute; -import DNA.Core.TransactionAttributeUsage; -import DNA.Core.TransactionInput; -import DNA.Core.TransactionOutput; -import DNA.Core.TransferTransaction; -import DNA.Core.Scripts.Program; -import DNA.Cryptography.ECC; -import DNA.Implementations.Blockchains.Rest.RestBlockchain; -import DNA.Implementations.Wallets.IUserManager; -import DNA.Implementations.Wallets.SQLite.UserWallet; -import DNA.Network.Rest.RestException; -import DNA.Network.Rest.RestNode; -import DNA.Wallets.Account; -import DNA.Wallets.Coin; -import DNA.Wallets.Contract; -import DNA.Wallets.Wallet; -import DNA.sdk.helper.OnChainSDKHelper; -import DNA.sdk.info.account.AccountAsset; -import DNA.sdk.info.account.AccountInfo; -import DNA.sdk.info.account.Asset; -import DNA.sdk.info.asset.AssetInfo; -import DNA.sdk.info.mutil.TxJoiner; -import DNA.sdk.info.transaction.TransactionInfo; -import DNA.sdk.info.transaction.TxInputInfo; -import DNA.sdk.info.transaction.TxOutputInfo; - -import com.alibaba.fastjson.JSON; - - -/** - * 账户管理器 - * - * 1. 账户类操作 - * 创建账户/查询账户 - * - * 2. 资产类操作 - * 注册资产/分发资产/转移资产/注销资产 - * - * 3. 存证取证 - * - * 4. 查询类操作 - * 查询账户信息 - * 查询账户资产 - * 查询资产信息 - * 查询交易信息 - * - */ -public class AccountManager { - private IUserManager uw; - private RestNode restNode; - private boolean isWaitSync = true; - - public void setWaitSync(boolean isWaitSync) { - this.isWaitSync = isWaitSync; - } - - public static void setPKGenerateAlgorithm(String algorithm) { - // ECC or SM2 - } - - public static void main(String[] args) { - - } - - public static AccountManager getWallet(String path, String url, String accessToken) { - AccountManager wm = new AccountManager(); - wm.initBlockRestNode(url, accessToken); - wm.initRestNode(url, accessToken); - wm.initWallet(path); - return wm; - } - - - public static AccountManager getWallet(String path, String password, String url, String accessToken) { - AccountManager wm = new AccountManager(); - wm.initBlockRestNode(url, accessToken); - wm.initRestNode(url, accessToken); - wm.initWallet(path); - return wm; - } - - public static AccountManager getWallet(String url, String accessToken) { - AccountManager wm = new AccountManager(); - wm.initRestNode(url, accessToken); - return wm; - } - - public static AccountManager getWallet(String path) { - AccountManager wm = new AccountManager(); - wm.initWallet(path); - return wm; - } - - private AccountManager() { - } - - private void initBlockRestNode(String url, String token) { - Blockchain.register(new RestBlockchain(new RestNode(url, token))); - } - - private void initRestNode(String url, String token) { - this.restNode = new RestNode(url, token); - } - - public void setRestNode(String url, String token) { - this.restNode = new RestNode(url, token); - } - - private void initWallet(String path) { - initWallet(path, "0x123456"); - } - private void initWallet(String path, String password) { - if(new File(path).exists() && new File(path).isFile()) { - uw = UserWallet.open(path, password); - } else { - uw = UserWallet.create(path, password); - } - } - - /** - * 启动同步线程 - */ - public void startSyncBlock() { - uw.start(); - } - - public void stopSyncBlock() { - uw.close(); - } - - public boolean hasFinishedSyncBlock() { - try { - return uw.hasFinishedSyncBlock(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - public int getBlockHeight() { - return uw.getBlockHeight(); - } - public int getWalletHeight() { - return uw.getWalletHeight(); - } - - public void rebuild() { - uw.rebuild(); - } - - /** - * 更新访问令牌 - * - * @param accessToken - */ - public void updateToken(String accessToken) { - restNode.setAccessToken(accessToken); - } - - - /** - * 创建单个账户 - */ - public String createAccount() { - return createAddress(); - } - - /** - * 创建多个账户 - */ - public List createAccount(int n) { - return Stream.generate(() -> createAddress()).limit(n).collect(Collectors.toList()); - } - // - private String createAddress() { - return uw.getContract(Contract.createSignatureContract(uw.createAccount().publicKey).address()).address(); - } - - /** - * 根据私钥创建账户 - * - * @param prikey - * @return - */ - public String createAccountsFromPrivateKey(String prikey) { - Account acc = uw.createAccount(Helper.hexToBytes(prikey)); - return uw.getContract(Contract.createSignatureContract(acc.publicKey).address()).address(); - } - - /** - * 导出所有账户地址 - * - * @return - */ - public List listAccount() { - return Arrays.stream(uw.getContracts()).map(p -> p.address()).collect(Collectors.toList()); - } - - public String address2UInt160(String address) { - return Wallet.toScriptHash(address).toString(); - } - - public String uint1602Address(String uint160) { - return Wallet.toAddress(UInt160.parse(uint160)); - } - - public void setAuthType(String authType) { - this.restNode.setAuthType(authType); - } - - public void setAccessToken(String accessToken) { - this.restNode.setAccessToken(accessToken); - } - - /** - * 注册资产 - * @throws Exception - */ - public String reg() throws Exception {// in-null,out-null - throw new UnsupportedOperationException(); - } - /** - * 注册资产 - * - * @param issuer 资产发行者地址 - * @param name 资产名称 - * @param amount 资产数量 - * @param desc 描述 - * @param controller 资产控制者地址 - * @return 交易编号 - * @throws Exception - */ - public String reg(String issuer, String name, long amount, String desc, String controller) throws Exception { - return reg(issuer, name, amount, desc, controller, 8); - } - public String reg(String issuer, String name, long amount, String desc, String controller, int precision) throws Exception { - return regToken(issuer, name, amount, desc, controller, precision); - } - /** - * 注册Token资产 - * - * @param issuer 资产发行者地址 - * @param name 资产名称 - * @param amount 资产数量 - * @param desc 描述 - * @param controller 资产控制者地址 - * @param precision 精度 - * @return 交易编号 - * @throws Exception - */ - public String regToken(String issuer, String name, long amount, String desc, String controller, int precision) throws Exception { - return regToken(getAccount(issuer), name, amount, desc, controller, precision); - } - public String regToken(Account acc, String assetName, long assetAmount, String txDesc, String controller, int precision) throws Exception { - return reg(getRegTx(acc, assetName, assetAmount, txDesc, AssetType.Token, controller, precision)); - } - /** - * 注册Share资产 - * - * @param issuer 资产发行者地址 - * @param name 资产名称 - * @param amount 资产数量 - * @param desc 描述 - * @param controller 资产控制者地址 - * @param precision 精度 - * @return 交易编号 - * @throws Exception - */ - public String regShare(String issuer, String name, long amount, String desc, String controller, int precision) throws Exception { - return regShare(getAccount(issuer), name, amount, desc, controller, precision); - } - public String regShare(Account acc, String assetName, long assetAmount, String txDesc, String controller, int precision) throws Exception { - return reg(getRegTx(acc, assetName, assetAmount, txDesc, AssetType.Share, controller, precision)); - } - private String reg(RegisterTransaction regTx) throws Exception { - RegisterTransaction signedTx4Reg = uw.makeTransaction(regTx, Fixed8.ZERO); - SignatureContext context = new SignatureContext(signedTx4Reg); - boolean f1 = uw.sign(context); - if(context.isCompleted()){ - signedTx4Reg.scripts = context.getScripts(); - } - String txHex = Helper.toHexString(signedTx4Reg.toArray()); - boolean f2 = restNode.sendRawTransaction(txHex); - String txid = signedTx4Reg.hash().toString(); - print("send reg tx.sign:"+f1+",rst:"+f2+",txid:"+ txid); -// if(f2 && isWaitSync) { -// uw.saveTransaction(signedTx4Reg); -// wait(uw,txid); // 等待生效 -// } - Thread.sleep(1000*6); - return txid; - } - - /** - * 分发资产 - * @throws Exception - */ - public String iss() {//in-null - throw new UnsupportedOperationException(); - } - /** - * 分发资产 - * - * @param sendAddr 资产控制者地址 - * @param assetid 资产编号 - * @param amount 资产数量 - * @param recvAddr 接收者地址 - * @param desc 描述 - * @return 交易编号 - * @throws Exception - */ - public String iss(String sendAddr, String assetid, long amount, String recvAddr, String desc) throws Exception { - return iss(getIssTx(assetid, amount, recvAddr, desc), getAddress(sendAddr)); - } - private String iss(IssueTransaction issueTx, UInt160 from) throws Exception { - IssueTransaction signedTx4Iss = uw.makeTransaction(issueTx, Fixed8.ZERO, from); - SignatureContext context4Iss = new SignatureContext(signedTx4Iss); - boolean f3 = uw.sign(context4Iss); - if(context4Iss.isCompleted()){ - signedTx4Iss.scripts = context4Iss.getScripts(); - } - uw.saveTransaction(signedTx4Iss); - String txHex = Helper.toHexString(signedTx4Iss.toArray());; - boolean f4 = restNode.sendRawTransaction(txHex); - - String txid4Iss = signedTx4Iss.hash().toString(); - print("send iss tx.sign:"+f3+",rst:"+f4+",txid:"+ txid4Iss); - if(f4 && isWaitSync) { - wait(uw,txid4Iss); // 等待生效 - } - return txid4Iss; - } - /** - * 分发给多个接收者 - * - * @param recvlist 接收者列表 - * @param sendAddr 发送者地址 - * @param desc 描述 - * @return - * @throws Exception - */ - public String iss(List recvlist, String sendAddr, String desc) throws Exception { - return iss(getIssTx(recvlist, desc), getAddress(sendAddr)); - } - - /** - * 转账 - */ - public String trf() { - throw new UnsupportedOperationException(); - } - /** - * 转移资产 - * - * @param sendAddr 资产控制者地址 - * @param assetid 资产编号 - * @param amount 资产数量 - * @param recvAddr 接收者地址 - * @param desc 描述 - * @return 交易编号 - * @throws Exception - */ - public String trf(String sendAddr, String assetid, long amount, String recvAddr, String desc) throws Exception { - return trf(getTrfTx(assetid, amount, recvAddr, desc), getAddress(sendAddr)); - } - private String trf(TransferTransaction trfTx, UInt160 from) throws Exception { - TransferTransaction signedTx4Trf = uw.makeTransaction(trfTx, Fixed8.ZERO, from); - SignatureContext context4Trf = new SignatureContext(signedTx4Trf); - boolean f5 = uw.sign(context4Trf); - if(context4Trf.isCompleted()){ - signedTx4Trf.scripts = context4Trf.getScripts(); - } - uw.saveTransaction(signedTx4Trf); - String txHex = Helper.toHexString(signedTx4Trf.toArray());; - boolean f6 = restNode.sendRawTransaction(txHex); - - String txid4Trf = signedTx4Trf.hash().toString(); - print("send trf tx.sign:"+f5+",rst:"+f6+",txid:"+ txid4Trf); - if(f6 && isWaitSync) { - wait(uw,txid4Trf); // 等待生效 - } - return txid4Trf; - } - /** - * 转账给多个接收者 - * - * @param recvlist 接收者列表 - * @param sendAddr 发送者地址 - * @param desc 描述 - * @return - * @throws Exception - */ - public String trf(List recvlist, String sendAddr, String desc) throws Exception { - return trf(getTrfTx(recvlist, desc), getAddress(sendAddr)); - } - - /** - * 注销资产 - * - * @param issuer 资产发行者 - * @param assetId 资产编号 - * @param txDesc 描述 - * @return - * @throws Exception - */ - public String des(String issuer, String assetId, String txDesc) throws Exception { - return des(getDesTx(issuer, assetId, txDesc), null); - } - public String des(DestroyTransaction desTx, UInt160 from) throws Exception { - DestroyTransaction signedTx4Des = desTx;//uw.makeTransaction(trfTx, Fixed8.ZERO, from); - SignatureContext context4Trf = new SignatureContext(signedTx4Des); - boolean f7 = uw.sign(context4Trf); - if(context4Trf.isCompleted()){ - signedTx4Des.scripts = context4Trf.getScripts(); - } - uw.saveTransaction(signedTx4Des); - String txHex = Helper.toHexString(signedTx4Des.toArray());; - OnChainSDKHelper.printTransaction(signedTx4Des); - System.out.println("tx.a:"+Helper.getbyteStr(Helper.hexToBytes(txHex))); - System.out.println("tx.s:"+txHex); - System.out.println("txHex:"+txHex); - boolean f8 = false;//restNode.sendRawTransaction(txHex); - - String txid4Des = signedTx4Des.hash().toString(); - print("send des tx.sign:"+f7+",rst:"+f8+",txid:"+ txid4Des); - if(f7 && isWaitSync) { - wait(uw,txid4Des); // 等待生效 - } - return txid4Des; - } - private DestroyTransaction getDesTx(String issuer, String assetId, String txDesc) { - DestroyTransaction tx = new DestroyTransaction(); - tx.inputs = Arrays.stream(uw.getCoin()).filter(p -> Wallet.toAddress(p.scriptHash).equals(issuer)).filter(p -> p.assetId.toString().equals(assetId)).map(p -> p.input).toArray(TransactionInput[]::new); - tx.outputs = new TransactionOutput[0]; - if(txDesc != null && txDesc.length() > 0) { - tx.attributes = new TransactionAttribute[1]; - tx.attributes[0] = new TransactionAttribute(); - tx.attributes[0].usage = TransactionAttributeUsage.Description; - tx.attributes[0].data = (txDesc+new Date().toString()).getBytes(); - } else { - tx.attributes = new TransactionAttribute[0]; - } - return tx; - } - - /** - * 存证 - * - * @param data 存证内容 - * @param desc 描述 - * @return 交易编号 - * @throws Exception - */ - public String storeCert(String data, String desc) throws Exception { - RecordTransaction tx = getRcdTx(data, desc); - String txHex = Helper.toHexString(tx.toArray());; - boolean f = restNode.sendRawTransaction(txHex); - - String txid = tx.hash().toString(); - print("rcd.sign:null, rst:"+f+",txid:"+txid); - return txid; - } - /** - * 取证 - * - * @param txid 交易编号 - * @return 存证内容 - * @throws Exception - */ - public String queryCert(String txid) throws Exception { - Transaction tx = restNode.getRawTransaction(txid); - if(tx instanceof RecordTransaction) { - RecordTransaction rr = (RecordTransaction) tx; - return new String(rr.recordData); - } - return null; - } - - - // 获取账户 - public Account getAccount(String address) { - return uw.getAccount(uw.getContract(address).publicKeyHash); - } - // 获取地址 - private UInt160 getAddress(String address) { - return Wallet.toScriptHash(address); - } - - /** - * 等待该笔交易同步至账户管理器中 - * - * @param txid - */ - public void wait(String txid) { - wait(uw, txid); - } - // 等待Tx生效 - private void wait(IUserManager uw, String txid) { - int count = 3; // 最长等待1分钟 - while(--count > 0) { - Map txs = uw.LoadTransactions(); - if(txs != null && txs.keySet().stream().filter(p -> txs.get(p).intValue() > 1).filter(p -> p.hash().toString().equals(txid)).count() == 1) { - print("sync finish, txid:"+txid); - return; - } - try { - Thread.sleep(1000*5); - } catch (InterruptedException e) { - } - print("sleep.....5s"); - } - print("sync timeout,txid:"+txid); - } - - private RegisterTransaction getRegTx(Account acc, String assetName, long assetAmount, String txDesc, AssetType assetType, String controller, int precision) { - RegisterTransaction tx = new RegisterTransaction(); - - tx.precision = (byte) precision; // 精度 - tx.assetType = AssetType.Token; // 资产类型 - tx.recordType = RecordType.UTXO; // 记账模式 - tx.nonce = (int)Math.random()*10; // 随机数 - - tx.assetType = assetType ; - tx.name = assetName; - tx.description = txDesc; - tx.amount = Fixed8.parse(String.valueOf(assetAmount)); - tx.issuer = acc.publicKey; - tx.admin = Wallet.toScriptHash(controller); - tx.outputs = new TransactionOutput[0]; - if(txDesc != null && txDesc.length() > 0) { - tx.attributes = new TransactionAttribute[1]; - tx.attributes[0] = new TransactionAttribute(); - tx.attributes[0].usage = TransactionAttributeUsage.Description; - tx.attributes[0].data = toAttr(txDesc); - } - return tx; - } - private byte[] generateKey64Bit() { - return ECC.generateKey(64); - } - private IssueTransaction getIssTx(String assetId, long assetAmount, String recvAddr, String txDesc) { - IssueTransaction tx = new IssueTransaction(); - tx.outputs = new TransactionOutput[1]; - tx.outputs[0] = new TransactionOutput(); - tx.outputs[0].assetId = UInt256.parse(assetId); - tx.outputs[0].value = Fixed8.parse(String.valueOf(assetAmount)); - tx.outputs[0].scriptHash = Wallet.toScriptHash(recvAddr); - int len = txDesc != null && txDesc.length() > 0 ? 2:1; - tx.attributes = new TransactionAttribute[len]; - tx.attributes[0] = new TransactionAttribute(); - tx.attributes[0].usage = TransactionAttributeUsage.Description; - tx.attributes[0].data = generateKey64Bit(); // 标识区分不同txid - for(int i=1; i recvlist, String txDesc) { - int size = recvlist.size(); - IssueTransaction tx = new IssueTransaction(); - tx.outputs = new TransactionOutput[1]; - tx.outputs = new TransactionOutput[size]; - for(int i=0; i 0 ? 2:1; - tx.attributes = new TransactionAttribute[len]; - tx.attributes[0] = new TransactionAttribute(); - tx.attributes[0].usage = TransactionAttributeUsage.Description; - tx.attributes[0].data = generateKey64Bit(); // 标识区分不同txid - for(int i=1; i 0) { - tx.attributes = new TransactionAttribute[1]; - tx.attributes[0] = new TransactionAttribute(); - tx.attributes[0].usage = TransactionAttributeUsage.Description; - tx.attributes[0].data = toAttr(txDesc); - } else { - tx.attributes = new TransactionAttribute[0]; - } - return tx; - } - - private TransferTransaction getTrfTx(List recvList, String txDesc) { - int size = recvList.size(); - TransferTransaction tx = new TransferTransaction(); - tx.outputs = new TransactionOutput[size]; - for(int i=0; i 0) { - tx.attributes = new TransactionAttribute[1]; - tx.attributes[0] = new TransactionAttribute(); - tx.attributes[0].usage = TransactionAttributeUsage.Description; - tx.attributes[0].data = toAttr(txDesc); - } else { - tx.attributes = new TransactionAttribute[0]; - } - return tx; - } - - private RecordTransaction getRcdTx(String data, String txDesc) { - RecordTransaction rcdTx = new RecordTransaction(); - rcdTx.recordType = ""; - rcdTx.recordData = data.getBytes(); - rcdTx.outputs = new TransactionOutput[0]; - rcdTx.inputs = new TransactionInput[0]; - rcdTx.attributes = new TransactionAttribute[0]; - if(txDesc != null && txDesc.length() > 0) { - rcdTx.attributes = new TransactionAttribute[1]; - rcdTx.attributes[0] = new TransactionAttribute(); - rcdTx.attributes[0].usage = TransactionAttributeUsage.Description; - rcdTx.attributes[0].data = toAttr(txDesc); - } else { - rcdTx.attributes = new TransactionAttribute[0]; - } - rcdTx.scripts = new Program[0]; - return rcdTx; - } - - /** - * 获取账户信息 - * - * @param address - * @return - */ - public AccountInfo getAccountInfo(String address) { - AccountInfo info = new AccountInfo(); - Contract con = uw.getContract(address); - Account acc = uw.getAccountByScriptHash(Wallet.toScriptHash(address)); - info.address = con.address(); - info.pubkey = Helper.toHexString(acc.publicKey.getEncoded(true)); - info.prikey = Helper.toHexString(acc.privateKey); - info.priwif = acc.export(); - info.pkhash = acc.publicKeyHash.toString(); - return info; - } - - /** - * 获取账户资产 - * - * @param address - * @return - */ - public AccountAsset getAccountAsset(String address) { - AccountAsset asset = new AccountAsset(); - Contract con = uw.getContract(address); - asset.address = con.address(); - asset.canUseAssets = new ArrayList(); - asset.freezeAssets = new ArrayList(); - Arrays.stream(uw.findUnspentCoins()).filter(p -> address.equals(Wallet.toAddress(p.scriptHash))).forEach(p -> { - Asset as = new Asset(); - as.assetid = p.assetId.toString(); - as.amount = p.value.toLong(); - asset.canUseAssets.add(as); - }); - Arrays.stream(uw.findUnconfirmedCoins()).filter(p -> address.equals(Wallet.toAddress(p.scriptHash))).forEach(p -> { - Asset as = new Asset(); - as.assetid = p.assetId.toString(); - as.amount = p.value.toLong(); - asset.freezeAssets.add(as); - }); - return asset; - } - public void print() { - Arrays.stream(uw.getCoin()).forEach(p -> { - System.out.println("-----------------------------------------------"); - System.out.println("coin.input.prevHash:"+p.input.prevHash.toString()); - System.out.println("coin.input.prevIndex:"+p.input.prevIndex); - System.out.println("coin.assetid:"+p.assetId.toString()); - System.out.println("coin.value:"+p.value); - System.out.println("coin.scripthash:"+Wallet.toAddress(p.scriptHash)); - System.out.println("coin.state:"+p.getState()); - }); - } - public Coin[] getCoin() { - return uw.getCoin(); - } - - /** - * 获取资产信息 - * - * @param assetid - * @return - * @throws RestException - */ - public AssetInfo getAssetInfo(String assetid) throws RestException { - String ss = restNode.getAsset(assetid); - return JSON.parseObject(ss, AssetInfo.class); - } - - /** - * 获取交易信息 - * - * @param txid - * @return - * @throws RestException - */ - public TransactionInfo getTransactionInfo(String txid) throws RestException { - TransactionInfo info = new TransactionInfo(); - info.txid = txid; - Transaction tx = restNode.getRawTransaction(txid); - if(tx instanceof RegisterTransaction) { - info.type = RegisterTransaction.class.getSimpleName(); - } else if(tx instanceof IssueTransaction) { - info.type = IssueTransaction.class.getSimpleName(); - } else if(tx instanceof TransferTransaction) { - info.type = TransferTransaction.class.getSimpleName(); - } else if(tx instanceof RecordTransaction) { - info.type = RecordTransaction.class.getSimpleName(); - } - - info.inputs = new ArrayList(); - Arrays.stream(tx.inputs).map(p -> getTxByNextTxInput(p)).forEach(p -> { - TxInputInfo in = new TxInputInfo(); - in.address = Wallet.toAddress(p.scriptHash); - in.assetid = p.assetId.toString(); - in.amount = p.value.toLong(); - info.inputs.add(in); - }); - info.outputs = new ArrayList(); - Arrays.stream(tx.outputs).forEach(p -> { - TxOutputInfo out = new TxOutputInfo(); - out.address = Wallet.toAddress(p.scriptHash); - out.assetid = p.assetId.toString(); - out.amount = p.value.toLong(); - info.outputs.add(out); - }); - StringBuilder sb = new StringBuilder(); - for(TransactionAttribute attr: tx.attributes) { - sb.append(Helper.toHexString(attr.data)); - } - if(sb.toString().length() > 0) { - info.attrs = new String(Helper.hexToBytes(sb.toString())); - } - return info; - } - private TransactionOutput getTxByNextTxInput(TransactionInput input){ - Transaction tx; - try { - tx = restNode.getRawTransaction(input.prevHash.toString()); - } catch (RestException e) { - throw new RuntimeException("Not find tx by next txInput"); - } - return tx.outputs[input.prevIndex]; - } - - public String getStateUpdate(String namespace, String key) { - try { - return restNode.getStateUpdate(namespace, key); - } catch (RestException e) { - throw new RuntimeException(e); - } - } - - public static void print(String ss) { - System.out.println(now() + ss); - } - private byte[] toAttr(String txDesc) { - return (now() + " " + txDesc).getBytes(); - } - public static String now() { - return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()) + " "; - } -} diff --git a/src/main/java/TestMain4CLI.java b/src/main/java/TestMain4CLI.java deleted file mode 100644 index 5c49d47..0000000 --- a/src/main/java/TestMain4CLI.java +++ /dev/null @@ -1,257 +0,0 @@ -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; - -import DNA.Network.Rest.RestException; -import DNA.sdk.info.account.AccountAsset; -import DNA.sdk.info.account.AccountInfo; -import DNA.sdk.info.asset.AssetInfo; -import DNA.sdk.info.mutil.TxJoiner; -import DNA.sdk.info.transaction.TransactionInfo; -import DNA.sdk.wallet.AccountManager; - - -/** - * DNA sdk 测试Demo - * - * @author 12146 - * - */ -public class TestMain4CLI { - - public static void main(String[] args) throws Exception { - boolean flag = true; - - // 实例化账户管理类 - AccountManager wm = getAccountManager(); - - // 启动同步 - wm.startSyncBlock(); - - // 等待同步完成 - while(!wm.hasFinishedSyncBlock()) { - Thread.sleep(1000*1); - } - - // 创建多个账户 - List list = wm.createAccount(3); - String addr1 = list.get(0); - String addr2 = list.get(1); - String addr3 = list.get(2); - print("user1:"+addr1 + ","+wm.address2UInt160(addr1) + ",addr.len="+addr1.length()+",uint160.len="+wm.address2UInt160(addr1).length()); - print("user2:"+addr2 + ","+wm.address2UInt160(addr2)); - print("user3:"+addr3 + ","+wm.address2UInt160(addr3)); - - String txid = null,assetid = null; - if(flag) { - // 注册资产(资产控制者为addr1) - print("test regAsset..............................................[st]"); - txid = wm.reg(addr1, "Token001", 10000, "用户1注册资产S01", addr1); - print("test regAsset..............................................[ed],txid="+txid); - - assetid = txid; - - // 分发资产(账户addr1分发资产给addr2) - print("test issAsset..............................................[st]"); - txid = wm.iss(addr1, assetid, 100, addr2, "用户1 分发给 用户2"); - print("test issAsset..............................................[ed],txid="+txid); - - // 转移资产(账户addr2转移资产只addr3) - print("test trfAsset..............................................[st]"); - txid = wm.trf(addr2, assetid, 11, addr3, "用户2转账给用户3"); - print("test trfAsset..............................................[ed],txid="+txid); - - - - // 存证 - String content = "ts_"+new Date(); - print("test storeCert..............................................[st]"); - txid = wm.storeCert(content, "存证交易test"); - print("test storeCert..............................................[ed],txid="+txid+",len="+txid.length()); - - Thread.sleep(1000*10); - - // 取证 - print("test queryCert..............................................[st]"); - String newContent = wm.queryCert(txid); - print(String.format("\n\told=%s\n\tnew=%s", content, newContent)); - print("test queryCert..............................................[ed],txid=end"); - - - // 分发给多个接收者 - List tlist = new ArrayList(); - tlist.add(newTxJoiner(addr2, assetid, 45)); - tlist.add(newTxJoiner(addr3, assetid, 55)); - txid = wm.iss(tlist, addr1, "u1 转账给 u2 和 u3"); - - // 转账给多个接收者 - tlist.clear(); - tlist.add(newTxJoiner(addr1, assetid, 1)); - tlist.add(newTxJoiner(addr2, assetid, 2)); - txid = wm.trf(tlist, addr3, "u3 转账给 u1 和 u2"); - - - // 查询所有账户地址 - List addrList = wm.listAccount(); - System.out.println("Query All Account:-------------------------\n"+addrList); - - // 查询账户信息 - AccountInfo accountInfo = wm.getAccountInfo(addr1); - System.out.println("Query Account info:-------------------------\n"+accountInfo); - - // 查询账户资产 - AccountAsset accountAsset = wm.getAccountAsset(addr1); - System.out.println("Query Account asset:-------------------------\n"+accountAsset); - - // 查询资产信息 - AssetInfo assetInfo = wm.getAssetInfo(assetid); - System.out.println("Query Asset info:-------------------------\n"+assetInfo); - - // 查询交易信息 - TransactionInfo transactionInfo = wm.getTransactionInfo(txid); - System.out.println("Query Transaction info:-------------------------\n"+transactionInfo); - - // 查询所有账户资产 - wm.listAccount().forEach(p -> { - print("query acc.asset:"+wm.getAccountAsset(p)); - }); - // 账户管理器 - System.out.println("#######################################################################################"); - } - } - - private static void print(String ss) { - System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()) + " " + ss); - } - - private static TxJoiner newTxJoiner(String address, String assetid, long value) { - TxJoiner tt = new TxJoiner(); - tt.address = address; - tt.assetid = assetid; - tt.value = value; - return tt; - } - - public void testCreateAccount() { - // 打开账户管理器 - AccountManager wm = getAccountManager(); - // 创建账户 - String user01 = wm.createAccount(); // 创建单个账户 - List list = wm.createAccount(10); // 批量创建10个账户 - System.out.println("user:"+user01); - System.out.println("list:"+list); - } - public void testRegAsset() throws Exception { - // 打开账户管理器 - AccountManager wm = getAccountManager(); - // 注册资产 - String issuer= ""; // 资产发行者地址 - String name = ""; // 资产名称 - long amount = 10000; // 资产数量 - String desc = ""; // 描述 - String controller = ""; // 资产控制者地址 - String assetid = wm.reg(issuer, name, amount , desc, controller); - System.out.println("rs:"+assetid); - } - public void testIssAsset() throws Exception { - // 打开账户管理器 - AccountManager wm = getAccountManager(); - // 分发资产 - String controller= ""; // 资产控制者地址 - String assetid = ""; // 资产编号(由注册资产产生) - long amount = 100; // 分发数量 - String recver = ""; // 分发资产接收者地址 - String desc = ""; // 描述 - String txid = wm.iss(controller, assetid, amount , recver , desc ); - System.out.println("rs:"+txid); - } - public void testTrfAsset() throws Exception { - // 打开账户管理器 - AccountManager wm = getAccountManager(); - // 转移资产 - String controller= ""; // 资产控制者地址 - String assetid = ""; // 资产编号(由注册资产产生) - long amount = 100; // 转移数量 - String recver = ""; // 转移资产接收者地址 - String desc = ""; // 描述 - String txid = wm.trf(controller, assetid, amount , recver , desc ); - System.out.println("rs:"+txid); - } - - public static void testStoreCert() throws Exception { - // 打开账户管理器 - AccountManager wm = getAccountManager(); - // 存证 - String content = "ts"; // 待存储的信息 - String desc = "dd"; // 描述 - String txid = wm.storeCert(content, desc); - System.out.println("rs:"+txid); - } - - public void testQueryCert() throws Exception { - // 打开账户管理器 - AccountManager wm = getAccountManager(); - // 取证 - String txid = ""; // 存证编号 - String contetn= wm.queryCert(txid); - System.out.println("rs:"+contetn); - } - - public static void testAccountInfo() { - // 打开账户管理器 - AccountManager wm = getAccountManager(); - // 查询账户信息 - String userAddr = "AZg3vyDawyHtET8tNhs1odKPa6yy8qFgxK"; // 账户地址 - AccountInfo info = wm.getAccountInfo(userAddr); - System.out.println("rs:"+info); - } - public static void testAccountAsset() { - // 打开账户管理器 - AccountManager wm = getAccountManager(); - // 查询账户资产 - String userAddr = "AZsbZYCFh9Xat2HdBwniZKDFfau4WWy9Sg"; - AccountAsset info = wm.getAccountAsset(userAddr); - System.out.println("rs:"+info); - } - public static void testAssetInfo() throws RestException { - // 打开账户管理器 - AccountManager wm = getAccountManager(); - // 查询账户资产 - String assetid = "c35d2195b197f8f75a2fb0367d667d2f63a02ba9e1929ab6378ffe91218f0446"; - AssetInfo info = wm.getAssetInfo(assetid); - System.out.println("rs:"+info); - } - public static void testTransactionInfo() throws Exception { - // 打开账户管理器 - AccountManager wm = getAccountManager(); - // 查询账户资产 - String txid = "05eee614559bf42dbedb2b062a6d5ef6b813abcc130ed3f55b3d0cdfec8c86ad"; - TransactionInfo info = wm.getTransactionInfo(txid); - System.out.println("rs:"+info); - } - - public static void testListAccount() { - AccountManager wm = getAccountManager(); - - wm.listAccount().forEach(p -> System.out.println(p)); - } - - public static AccountManager getAccountManager() { - // 打开账户管理器 - // v1.0 -// String path = "./dat/tsGo_01.db3"; -// String url = "http://localhost:20334"; -// String accessToken = ""; // 从认证服务器获取该访问令牌 -// UserWalletManager wm = UserWalletManager.getWallet(path, url, accessToken); - - // v1.1 - String dnaUrl = "http://127.0.0.1:20334"; - String dnaToken = ""; - String path = "./4.db3"; - AccountManager wm = AccountManager.getWallet(path, dnaUrl, dnaToken); - print(String.format("[param=%s,%s]", dnaUrl, path)); - print(String.format("start to test....hh:%s", wm.getBlockHeight())); - return wm; - } -} diff --git a/src/main/java/com/github/DNAProject/account/Account.java b/src/main/java/com/github/DNAProject/account/Account.java new file mode 100644 index 0000000..924eba6 --- /dev/null +++ b/src/main/java/com/github/DNAProject/account/Account.java @@ -0,0 +1,606 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.account; + + +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.crypto.*; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.crypto.Base58; +import com.github.DNAProject.crypto.Signature; +import com.github.DNAProject.crypto.Digest; +import com.github.DNAProject.sdk.exception.SDKException; +import org.bouncycastle.crypto.generators.SCrypt; +import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey; +import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; +import org.bouncycastle.jcajce.spec.SM2ParameterSpec; +import org.bouncycastle.jce.ECNamedCurveTable; +import org.bouncycastle.jce.ECPointUtil; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; +import org.bouncycastle.jce.spec.ECNamedCurveSpec; +import org.bouncycastle.util.Strings; + +import javax.crypto.Cipher; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.security.*; +import java.security.spec.*; +import java.util.Arrays; +import java.util.Base64; + + +public class Account { + private KeyType keyType; + private Object[] curveParams; + private PrivateKey privateKey; + private PublicKey publicKey; + private Address addressU160; + private SignatureScheme signatureScheme; + + // create an account with the specified key type + public Account(SignatureScheme scheme) throws Exception { + Security.addProvider(new BouncyCastleProvider()); + KeyPairGenerator gen; + AlgorithmParameterSpec paramSpec; + signatureScheme = scheme; + + if (scheme == SignatureScheme.SHA256WITHECDSA) { + this.keyType = KeyType.ECDSA; + this.curveParams = new Object[]{Curve.P256.toString()}; + } else if (scheme == SignatureScheme.SM3WITHSM2) { + this.keyType = KeyType.SM2; + this.curveParams = new Object[]{Curve.SM2P256V1.toString()}; + } + + switch (scheme) { + case SHA256WITHECDSA: + case SM3WITHSM2: + if (!(curveParams[0] instanceof String)) { + throw new Exception(ErrorCode.InvalidParams); + } + String curveName = (String) curveParams[0]; + paramSpec = new ECGenParameterSpec(curveName); + gen = KeyPairGenerator.getInstance("EC", "BC"); + break; + default: + //should not reach here + throw new Exception(ErrorCode.UnsupportedKeyType); + } + gen.initialize(paramSpec, new SecureRandom()); + KeyPair keyPair = gen.generateKeyPair(); + this.privateKey = keyPair.getPrivate(); + this.publicKey = keyPair.getPublic(); + this.addressU160 = Address.addressFromPubKey(serializePublicKey()); + } + + public Account(byte[] prikey, SignatureScheme scheme) throws Exception { + Security.addProvider(new BouncyCastleProvider()); + signatureScheme = scheme; + + if (scheme == SignatureScheme.SM3WITHSM2) { + this.keyType = KeyType.SM2; + this.curveParams = new Object[]{Curve.SM2P256V1.toString()}; + } else if (scheme == SignatureScheme.SHA256WITHECDSA) { + this.keyType = KeyType.ECDSA; + this.curveParams = new Object[]{Curve.P256.toString()}; + } + + switch (scheme) { + case SHA256WITHECDSA: + case SM3WITHSM2: + BigInteger d = new BigInteger(1, prikey); + ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec((String) this.curveParams[0]); + ECParameterSpec paramSpec = new ECNamedCurveSpec(spec.getName(), spec.getCurve(), spec.getG(), spec.getN()); + ECPrivateKeySpec priSpec = new ECPrivateKeySpec(d, paramSpec); + KeyFactory kf = KeyFactory.getInstance("EC", "BC"); + this.privateKey = kf.generatePrivate(priSpec); + + org.bouncycastle.math.ec.ECPoint Q = spec.getG().multiply(d).normalize(); + if (Q == null || Q.getAffineXCoord() == null || Q.getAffineYCoord() == null) { + throw new SDKException(ErrorCode.OtherError("normalize error")); + } + ECPublicKeySpec pubSpec = new ECPublicKeySpec( + new ECPoint(Q.getAffineXCoord().toBigInteger(), Q.getAffineYCoord().toBigInteger()), + paramSpec); + this.publicKey = kf.generatePublic(pubSpec); + this.addressU160 = Address.addressFromPubKey(serializePublicKey()); + break; + default: + throw new Exception(ErrorCode.UnsupportedKeyType); + } + } + + // construct an account from a serialized pubic key or private key + public Account(boolean fromPrivate, byte[] pubkey) throws Exception { + Security.addProvider(new BouncyCastleProvider()); + if (fromPrivate) { + //parsePrivateKey(data); + } else { + parsePublicKey(pubkey); + } + } + + /** + * Private Key From WIF + * + * @param wif get private from wif + * @return + */ + public static byte[] getPrivateKeyFromWIF(String wif) { + if (wif == null) { + throw new NullPointerException(); + } + byte[] data = Base58.decode(wif); + if (data.length != 38 || data[0] != (byte) 0x80 || data[33] != 0x01) { + throw new IllegalArgumentException(); + } + byte[] checksum = Digest.hash256(data, 0, data.length - 4); + for (int i = 0; i < 4; i++) { + if (data[data.length - 4 + i] != checksum[i]) { + throw new IllegalArgumentException(); + } + } + byte[] privateKey = new byte[32]; + System.arraycopy(data, 1, privateKey, 0, privateKey.length); + Arrays.fill(data, (byte) 0); + return privateKey; + } + public SignatureScheme getSignatureScheme(){ + return signatureScheme; + } + public KeyType getKeyType() { + return keyType; + } + + public Object[] getCurveParams() { + return curveParams; + } + + /** + * @param encryptedPriKey encryptedPriKey + * @param passphrase passphrase + * @return + * @throws Exception + */ + public static String getEcbDecodedPrivateKey(String encryptedPriKey, String passphrase, int n, SignatureScheme scheme) throws Exception { + if (encryptedPriKey == null) { + throw new SDKException(ErrorCode.ParamError); + } + byte[] decoded = Base58.decodeChecked(encryptedPriKey); + if (decoded.length != 43 || decoded[0] != (byte) 0x01 || decoded[1] != (byte) 0x42 || decoded[2] != (byte) 0xe0) { + throw new SDKException(ErrorCode.Decoded3bytesError); + } + byte[] data = Arrays.copyOfRange(decoded, 0, decoded.length - 4); + return decode(passphrase, data, n, scheme); + } + + private static String decode(String passphrase, byte[] input, int n, SignatureScheme scheme) throws Exception { + int N = n; + int r = 8; + int p = 8; + int dkLen = 64; + byte[] addresshash = new byte[4]; + byte[] encryptedkey = new byte[32]; + System.arraycopy(input, 3, addresshash, 0, 4); + System.arraycopy(input, 7, encryptedkey, 0, 32); + + byte[] derivedkey = SCrypt.generate(passphrase.getBytes(StandardCharsets.UTF_8), addresshash, N, r, p, dkLen); + byte[] derivedhalf1 = new byte[32]; + byte[] derivedhalf2 = new byte[32]; + System.arraycopy(derivedkey, 0, derivedhalf1, 0, 32); + System.arraycopy(derivedkey, 32, derivedhalf2, 0, 32); + + SecretKeySpec skeySpec = new SecretKeySpec(derivedhalf2, "AES"); + Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");// AES/ECB/NoPadding + cipher.init(Cipher.DECRYPT_MODE, skeySpec); + byte[] rawkey = cipher.doFinal(encryptedkey); + + String priKey = Helper.toHexString(XOR(rawkey, derivedhalf1)); + Account account = new Account(Helper.hexToBytes(priKey), scheme); + Address script_hash = Address.addressFromPubKey(account.serializePublicKey()); + String address = script_hash.toBase58(); + byte[] addresshashTmp = Digest.hash256(address.getBytes()); + byte[] addresshashNew = Arrays.copyOfRange(addresshashTmp, 0, 4); + + if (!new String(addresshash).equals(new String(addresshashNew))) { + throw new SDKException(ErrorCode.DecodePrikeyPassphraseError + Helper.toHexString(addresshash) + "," + Helper.toHexString(addresshashNew)); + } + return priKey; + } + + private static byte[] XOR(byte[] x, byte[] y) throws Exception { + if (x.length != y.length) { + throw new SDKException(ErrorCode.ParamError); + } + byte[] ret = new byte[x.length]; + for (int i = 0; i < x.length; i++) { + ret[i] = (byte) (x[i] ^ y[i]); + } + return ret; + } + + public Address getAddressU160() { + return addressU160; + } + + public PublicKey getPublicKey() { + return publicKey; + } + + public PrivateKey getPrivateKey() { + return privateKey; + } + + public byte[] generateSignature(byte[] msg, SignatureScheme scheme, Object param) throws Exception { + if (msg == null || msg.length == 0) { + throw new Exception(ErrorCode.InvalidMessage); + } + if (this.privateKey == null) { + throw new Exception(ErrorCode.WithoutPrivate); + } + + SignatureHandler ctx = new SignatureHandler(keyType, signatureScheme); + AlgorithmParameterSpec paramSpec = null; + if (signatureScheme == SignatureScheme.SM3WITHSM2) { + if (param instanceof String) { + paramSpec = new SM2ParameterSpec(Strings.toByteArray((String) param)); + } else if (param == null) { + paramSpec = new SM2ParameterSpec("1234567812345678".getBytes()); + } else { + throw new Exception(ErrorCode.InvalidSM2Signature); + } + } + byte[] signature = new Signature( + signatureScheme, + paramSpec, + ctx.generateSignature(privateKey, msg, paramSpec) + ).toBytes(); + return signature; + } + + public boolean verifySignature(byte[] msg, byte[] signature) throws Exception { + if (msg == null || signature == null || msg.length == 0 || signature.length == 0) { + throw new Exception(ErrorCode.AccountInvalidInput); + } + if (this.publicKey == null) { + throw new Exception(ErrorCode.AccountWithoutPublicKey); + } + Signature sig = new Signature(signature); + SignatureHandler ctx = new SignatureHandler(keyType, sig.getScheme()); + return ctx.verifySignature(publicKey, msg, sig.getValue()); + } + + + public byte[] serializePublicKey() { + ByteArrayOutputStream bs = new ByteArrayOutputStream(); + BCECPublicKey pub = (BCECPublicKey) publicKey; + try { + switch (this.keyType) { + case ECDSA: + //bs.write(this.keyType.getLabel()); + //bs.write(Curve.valueOf(pub.getParameters().getCurve()).getLabel()); + bs.write(pub.getQ().getEncoded(true)); + break; + case SM2: + bs.write(this.keyType.getLabel()); + bs.write(Curve.valueOf(pub.getParameters().getCurve()).getLabel()); + bs.write(pub.getQ().getEncoded(true)); + break; + default: + // Should not reach here + throw new Exception(ErrorCode.UnknownKeyType); + } + } catch (Exception e) { + // Should not reach here + e.printStackTrace(); + return null; + } + return bs.toByteArray(); + } + + private void parsePublicKey(byte[] data) throws Exception { + if (data == null) { + throw new Exception(ErrorCode.NullInput); + } + if (data.length < 2) { + throw new Exception(ErrorCode.InvalidData); + } + if(data.length == 33){ + this.keyType = KeyType.ECDSA; + } else if(data.length == 35) { + this.keyType = KeyType.fromLabel(data[0]); + } + this.privateKey = null; + this.publicKey = null; + switch (this.keyType) { + case ECDSA: + this.keyType = KeyType.ECDSA; + this.curveParams = new Object[]{Curve.P256.toString()}; + ECNamedCurveParameterSpec spec0 = ECNamedCurveTable.getParameterSpec(Curve.P256.toString()); + ECParameterSpec param0 = new ECNamedCurveSpec(spec0.getName(), spec0.getCurve(), spec0.getG(), spec0.getN()); + ECPublicKeySpec pubSpec0 = new ECPublicKeySpec( + ECPointUtil.decodePoint( + param0.getCurve(), + Arrays.copyOfRange(data, 0, data.length)), + param0); + KeyFactory kf0 = KeyFactory.getInstance("EC", "BC"); + this.publicKey = kf0.generatePublic(pubSpec0); + break; + case SM2: +// this.keyType = KeyType.fromLabel(data[0]); + Curve c = Curve.fromLabel(data[1]); + this.curveParams = new Object[]{c.toString()}; + ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec(c.toString()); + ECParameterSpec param = new ECNamedCurveSpec(spec.getName(), spec.getCurve(), spec.getG(), spec.getN()); + ECPublicKeySpec pubSpec = new ECPublicKeySpec( + ECPointUtil.decodePoint( + param.getCurve(), + Arrays.copyOfRange(data, 2, data.length)), + param); + KeyFactory kf = KeyFactory.getInstance("EC", "BC"); + this.publicKey = kf.generatePublic(pubSpec); + break; + default: + throw new Exception(ErrorCode.UnknownKeyType); + } + } + + public byte[] serializePrivateKey() throws Exception { + switch (this.keyType) { + case ECDSA: + case SM2: + BCECPrivateKey pri = (BCECPrivateKey) this.privateKey; + String curveName = Curve.valueOf(pri.getParameters().getCurve()).toString(); + byte[] d = new byte[32]; + if (pri.getD().toByteArray().length == 33) { + System.arraycopy(pri.getD().toByteArray(), 1, d, 0, 32); + } else if (pri.getD().toByteArray().length == 31){ + d[0] = 0; + System.arraycopy(pri.getD().toByteArray(), 0, d, 1, 31); + } else { + return pri.getD().toByteArray(); + } + return d; + default: + // should not reach here + throw new Exception(ErrorCode.UnknownKeyType); + } + } + + + public int compareTo(Account o) { + byte[] pub0 = serializePublicKey(); + byte[] pub1 = o.serializePublicKey(); + for (int i = 0; i < pub0.length && i < pub1.length; i++) { + if (pub0[i] != pub1[i]) { + return pub0[i] - pub1[i]; + } + } + + return pub0.length - pub1.length; + } + + public String exportWif() throws Exception { + byte[] data = new byte[38]; + data[0] = (byte) 0x80; + byte[] prikey = serializePrivateKey(); + System.arraycopy(prikey, 0, data, 1, 32); + data[33] = (byte) 0x01; + byte[] checksum = Digest.hash256(data, 0, data.length - 4); + System.arraycopy(checksum, 0, data, data.length - 4, 4); + String wif = Base58.encode(data); + Arrays.fill(data, (byte) 0); + return wif; + } + + public String exportEcbEncryptedPrikey(String passphrase, int n) throws SDKException { + int N = n; + int r = 8; + int p = 8; + int dkLen = 64; + Address script_hash = Address.addressFromPubKey(serializePublicKey()); + String address = script_hash.toBase58(); + + byte[] addresshashTmp = Digest.hash256(address.getBytes()); + byte[] addresshash = Arrays.copyOfRange(addresshashTmp, 0, 4); + + byte[] derivedkey = SCrypt.generate(passphrase.getBytes(StandardCharsets.UTF_8), addresshash, N, r, p, dkLen); + byte[] derivedhalf1 = new byte[32]; + byte[] derivedhalf2 = new byte[32]; + System.arraycopy(derivedkey, 0, derivedhalf1, 0, 32); + System.arraycopy(derivedkey, 32, derivedhalf2, 0, 32); + try { + SecretKeySpec skeySpec = new SecretKeySpec(derivedhalf2, "AES"); + Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding"); + cipher.init(Cipher.ENCRYPT_MODE, skeySpec); + byte[] derived = XOR(serializePrivateKey(), derivedhalf1); + byte[] encryptedkey = cipher.doFinal(derived); + + byte[] buffer = new byte[encryptedkey.length + 7]; + buffer[0] = (byte) 0x01; + buffer[1] = (byte) 0x42; + buffer[2] = (byte) 0xe0; + System.arraycopy(addresshash, 0, buffer, 3, addresshash.length); + System.arraycopy(encryptedkey, 0, buffer, 7, encryptedkey.length); + return Base58.checkSumEncode(buffer); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public String exportCtrEncryptedPrikey(String passphrase, int n) throws Exception { + int N = n; + int r = 8; + int p = 8; + int dkLen = 64; + Address script_hash = Address.addressFromPubKey(serializePublicKey()); + String address = script_hash.toBase58(); + + byte[] addresshashTmp = Digest.hash256(address.getBytes()); + byte[] addresshash = Arrays.copyOfRange(addresshashTmp, 0, 4); + + byte[] derivedkey = SCrypt.generate(passphrase.getBytes(StandardCharsets.UTF_8), addresshash, N, r, p, dkLen); + byte[] derivedhalf2 = new byte[32]; + byte[] iv = new byte[16]; + System.arraycopy(derivedkey, 0, iv, 0, 16); + System.arraycopy(derivedkey, 32, derivedhalf2, 0, 32); + try { + SecretKeySpec skeySpec = new SecretKeySpec(derivedhalf2, "AES"); + Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding"); + cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(iv)); + byte[] encryptedkey = cipher.doFinal(serializePrivateKey()); + return new String(Base64.getEncoder().encode(encryptedkey)); + } catch (Exception e) { + throw new SDKException(ErrorCode.EncriptPrivateKeyError); + } + } + + public String exportGcmEncryptedPrikey(String passphrase,byte[] salt, int n) throws Exception { + int N = n; + int r = 8; + int p = 8; + int dkLen = 64; + if (salt.length != 16) { + throw new SDKException(ErrorCode.ParamError); + } + Security.addProvider(new BouncyCastleProvider()); + byte[] derivedkey = SCrypt.generate(passphrase.getBytes(StandardCharsets.UTF_8), salt, N, r, p, dkLen); + byte[] derivedhalf2 = new byte[32]; + byte[] iv = new byte[12]; + System.arraycopy(derivedkey, 0, iv, 0, 12); + System.arraycopy(derivedkey, 32, derivedhalf2, 0, 32); + try { + SecretKeySpec skeySpec = new SecretKeySpec(derivedhalf2, "AES"); + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new GCMParameterSpec(128,iv)); + cipher.updateAAD(getAddressU160().toBase58().getBytes()); + byte[] encryptedkey = cipher.doFinal(serializePrivateKey()); + return new String(Base64.getEncoder().encode(encryptedkey)); + } catch (Exception e) { + e.printStackTrace(); + throw new SDKException(ErrorCode.EncriptPrivateKeyError); + } + } + + public static String getCtrDecodedPrivateKey(String encryptedPriKey, String passphrase, String address, int n, SignatureScheme scheme) throws Exception { + byte[] addresshashTmp = Digest.hash256(address.getBytes()); + byte[] addresshash = Arrays.copyOfRange(addresshashTmp, 0, 4); + return getCtrDecodedPrivateKey(encryptedPriKey,passphrase,addresshash,n,scheme); + } + public static String getCtrDecodedPrivateKey(String encryptedPriKey, String passphrase, byte[] salt, int n, SignatureScheme scheme) throws Exception { + if (encryptedPriKey == null) { + throw new SDKException(ErrorCode.EncryptedPriKeyError); + } + if (salt.length != 4) { + throw new SDKException(ErrorCode.ParamError); + } + Security.addProvider(new BouncyCastleProvider()); + byte[] encryptedkey = Base64.getDecoder().decode(encryptedPriKey); + + int N = n; + int r = 8; + int p = 8; + int dkLen = 64; + + byte[] derivedkey = SCrypt.generate(passphrase.getBytes(StandardCharsets.UTF_8), salt, N, r, p, dkLen); + byte[] derivedhalf2 = new byte[32]; + byte[] iv = new byte[16]; + System.arraycopy(derivedkey, 0, iv, 0, 16); + System.arraycopy(derivedkey, 32, derivedhalf2, 0, 32); + + SecretKeySpec skeySpec = new SecretKeySpec(derivedhalf2, "AES"); + Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding"); + cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(iv)); + byte[] rawkey = cipher.doFinal(encryptedkey); + String address = new Account(rawkey, scheme).getAddressU160().toBase58(); + byte[] addresshashTmp = Digest.hash256(address.getBytes()); + byte[] addresshash = Arrays.copyOfRange(addresshashTmp, 0, 4); + if (!Arrays.equals(addresshash,salt)) { + throw new SDKException(ErrorCode.encryptedPriKeyAddressPasswordErr); + } + return Helper.toHexString(rawkey); + } + + public static String getGcmDecodedPrivateKey(String encryptedPriKey, String passphrase,String address, byte[] salt, int n, SignatureScheme scheme) throws Exception { + if (encryptedPriKey == null) { + throw new SDKException(ErrorCode.EncryptedPriKeyError); + } + if (salt.length != 16) { + throw new SDKException(ErrorCode.ParamError); + } + byte[] encryptedkey = new byte[]{}; + try{ + encryptedkey = Base64.getDecoder().decode(encryptedPriKey); + }catch (Exception e){ + throw new SDKException(ErrorCode.ParamErr("encryptedPriKey is wrong")); + } + + + int N = n; + int r = 8; + int p = 8; + int dkLen = 64; + + byte[] derivedkey = SCrypt.generate(passphrase.getBytes(StandardCharsets.UTF_8), salt, N, r, p, dkLen); + byte[] derivedhalf2 = new byte[32]; + byte[] iv = new byte[12]; + System.arraycopy(derivedkey, 0, iv, 0, 12); + System.arraycopy(derivedkey, 32, derivedhalf2, 0, 32); + + byte[] rawkey = new byte[0]; + try { + SecretKeySpec skeySpec = new SecretKeySpec(derivedhalf2, "AES"); + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + cipher.init(Cipher.DECRYPT_MODE, skeySpec, new GCMParameterSpec(128,iv)); + cipher.updateAAD(address.getBytes()); + rawkey = cipher.doFinal(encryptedkey); + } catch (Exception e) { + e.printStackTrace(); + throw new SDKException(ErrorCode.encryptedPriKeyAddressPasswordErr); + } + Account account = new Account(rawkey, scheme); + if (!address.equals(account.getAddressU160().toBase58())) { + throw new SDKException(ErrorCode.encryptedPriKeyAddressPasswordErr); + } + return Helper.toHexString(rawkey); + } + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof Account)) { + return false; + } + return addressU160.equals(((Account) obj).addressU160); + } + + @Override + public int hashCode() { + return addressU160.hashCode(); + } +} diff --git a/src/main/java/com/github/DNAProject/common/Address.java b/src/main/java/com/github/DNAProject/common/Address.java new file mode 100644 index 0000000..d23665d --- /dev/null +++ b/src/main/java/com/github/DNAProject/common/Address.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.common; + +import com.github.DNAProject.core.program.Program; +import com.github.DNAProject.core.scripts.ScriptBuilder; +import com.github.DNAProject.core.scripts.ScriptOp; +import com.github.DNAProject.crypto.Base58; +import com.github.DNAProject.crypto.Digest; +import com.github.DNAProject.sdk.exception.SDKException; + +import org.bouncycastle.math.ec.ECPoint; + +/** + * Custom type which inherits base class defines 20-bit data, + * it mostly used to defined contract address + */ +public class Address extends UIntBase implements Comparable
{ + public static final Address ZERO = new Address(); + public static final byte COIN_VERSION = 0x17; + + public Address() { + this(null); + } + + public Address(byte[] value) { + super(20, value); + } + + + public static Address parse(String value) { + if (value == null) { + throw new NullPointerException(); + } + if (value.startsWith("0x")) { + value = value.substring(2); + } + if (value.length() != 40) { + throw new IllegalArgumentException(); + } + byte[] v = Helper.hexToBytes(value); + return new Address(v); +// return new UInt160(Helper.reverse(v)); + } + + public static boolean tryParse(String s, Address result) { + try { + Address v = parse(s); + result.data_bytes = v.data_bytes; + return true; + } catch (Exception e) { + return false; + } + } + + public static Address AddressFromVmCode(String codeHexStr) { + Address code = Address.toScriptHash(Helper.hexToBytes(codeHexStr)); + return code; + } + + public static Address addressFromPubKey(String publicKey) { + return addressFromPubKey(Helper.hexToBytes(publicKey)); + } + + public static Address addressFromPubKey(byte[] publicKey) { + ScriptBuilder sb = new ScriptBuilder(); + sb.emitPushByteArray(publicKey); + sb.add(ScriptOp.OP_CHECKSIG); + return Address.toScriptHash(sb.toArray()); + } + + public static Address addressFromMultiPubKeys(int m, byte[]... publicKeys) throws Exception { + return Address.toScriptHash(Program.ProgramFromMultiPubKey(m,publicKeys)); + } + + public static Address decodeBase58(String address) throws SDKException { + byte[] data = new byte[]{}; + try{ + data = Base58.decode(address); + }catch (Exception e){ + throw new SDKException(ErrorCode.ParamError); + } + if (data.length != 25) { + throw new SDKException(ErrorCode.ParamError); + } + if (data[0] != COIN_VERSION) { + throw new SDKException(ErrorCode.ParamError); + } + byte[] checksum = Digest.sha256(Digest.sha256(data, 0, 21)); + for (int i = 0; i < 4; i++) { + if (data[data.length - 4 + i] != checksum[i]) { + throw new SDKException(ErrorCode.ParamError); + } + } + byte[] buffer = new byte[20]; + System.arraycopy(data, 1, buffer, 0, 20); + return new Address(buffer); + } + + public static Address toScriptHash(byte[] script) { + return new Address(Digest.hash160(script)); + } + + @Override + public int compareTo(Address other) { + byte[] x = this.data_bytes; + byte[] y = other.data_bytes; + for (int i = x.length - 1; i >= 0; i--) { + int r = Byte.toUnsignedInt(x[i]) - Byte.toUnsignedInt(y[i]); + if (r != 0) { + return r; + } + } + return 0; + } + + public String toBase58() { + byte[] data = new byte[25]; + data[0] = COIN_VERSION; + System.arraycopy(toArray(), 0, data, 1, 20); + byte[] checksum = Digest.sha256(Digest.sha256(data, 0, 21)); + System.arraycopy(checksum, 0, data, 21, 4); + return Base58.encode(data); + } + +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/common/Common.java b/src/main/java/com/github/DNAProject/common/Common.java new file mode 100644 index 0000000..90250d2 --- /dev/null +++ b/src/main/java/com/github/DNAProject/common/Common.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.common; + +import com.github.DNAProject.crypto.ECC; + +import java.text.SimpleDateFormat; +import java.util.Date; + + +public abstract class Common implements AutoCloseable { + public static String diddna = "did:dna:"; + public static final int MULTI_SIG_MAX_PUBKEY_SIZE = 16; + public static final int TX_MAX_SIG_SIZE = 16; + + public static byte[] generateKey64Bit() { + return ECC.generateKey(64); + } + + public static String currentTime() { + return new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()); + } + + private static String now() { + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()); + } + +} diff --git a/src/main/java/com/github/DNAProject/common/ErrorCode.java b/src/main/java/com/github/DNAProject/common/ErrorCode.java new file mode 100644 index 0000000..80ebb0b --- /dev/null +++ b/src/main/java/com/github/DNAProject/common/ErrorCode.java @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.common; +import com.alibaba.fastjson.JSON; + +import java.util.HashMap; +import java.util.Map; + +public class ErrorCode { + public static String getError(int code, String msg) { + Map map = new HashMap(); + map.put("Error", code); + map.put("Desc", msg); + return JSON.toJSONString(map); + } + + //account error + public static String InvalidParams = getError(51001, "Account Error,invalid params"); + public static String UnsupportedKeyType = getError(51002, "Account Error,unsupported key type"); + public static String InvalidMessage = getError(51003, "Account Error,invalid message"); + public static String WithoutPrivate = getError(51004, "Account Error,account without private key cannot generate signature"); + public static String InvalidSM2Signature = getError(51005, "Account Error,invalid SM2 signature parameter, ID (String) excepted"); + public static String AccountInvalidInput = getError(51006, "Account Error,account invalid input"); + public static String AccountWithoutPublicKey = getError(51007, "Account Error,account without public key cannot verify signature"); + public static String UnknownKeyType = getError(51008, "Account Error,unknown key type"); + public static String NullInput = getError(51009, "Account Error,null input"); + public static String InvalidData = getError(51010, "Account Error,invalid data"); + public static String Decoded3bytesError = getError(51011, "Account Error,decoded 3 bytes error"); + public static String DecodePrikeyPassphraseError = getError(51012, "Account Error,decode prikey passphrase error."); + public static String PrikeyLengthError = getError(51013, "Account Error,Prikey length error"); + public static String EncryptedPriKeyError = getError(51014, "Account Error,Prikey length error"); + public static String encryptedPriKeyAddressPasswordErr = getError(51015, "Account Error,encryptedPriKey address password not match."); + public static String EncriptPrivateKeyError = getError(51016, "Account Error, encript privatekey error,"); + + + // + public static String ParamLengthErr = getError(52001, "Uint256 Error,param length error"); + public static String ChecksumNotValidate = getError(52002, "Base58 Error,Checksum does not validate"); + public static String InputTooShort = getError(52003, "Base58 Error,Input too short"); + public static String UnknownCurve = getError(52004, "Curve Error,unknown curve"); + public static String UnknownCurveLabel = getError(52005, "Curve Error,unknown curve label"); + public static String UnknownAsymmetricKeyType = getError(52006, "keyType Error,unknown asymmetric key type"); + public static String InvalidSignatureData = getError(52007, "Signature Error,invalid signature data: missing the ID parameter for SM3withSM2"); + public static String InvalidSignatureDataLen = getError(52008, "Signature Error,invalid signature data length"); + public static String MalformedSignature = getError(52009, "Signature Error,malformed signature"); + public static String UnsupportedSignatureScheme = getError(52010, "Signature Error,unsupported signature scheme:"); + public static String DataSignatureErr = getError(52011, "Signature Error,Data signature error."); + public static String UnSupportOperation = getError(52012, "Address Error, UnsupportedOperationException"); + + + //Core Error + public static String TxDeserializeError = getError(53001, "Core Error,Transaction deserialize failed"); + public static String BlockDeserializeError = getError(53002, "Core Error,Block deserialize failed"); + + + //merkle error + public static String MerkleVerifierErr = getError(54001, "Wrong params: the tree size is smaller than the leaf index"); + public static String TargetHashesErr = getError(54002, "targetHashes error"); + + public static String ConstructedRootHashErr(String msg) { + return getError(54003, "Other Error," + msg); + } + + public static String AsserFailedHashFullTree = getError(54004, "assert failed in hash full tree"); + public static String LeftTreeFull = getError(54005, "left tree always full"); + + + //SmartCodeTx Error + public static String SendRawTxError = getError(58001, "SmartCodeTx Error,sendRawTransaction error"); + public static String TypeError = getError(58002, "SmartCodeTx Error,type error"); + + //DnaIdTx Error + public static String NullCodeHash = getError(58003, "DnaIdTx Error,null codeHash"); + public static String ParamError = getError(58004, "param error,"); + + public static String ParamErr(String msg) { + return getError(58005, msg); + } + + public static String DidNull = getError(58006, "DnaIdTx Error,SendDid or receiverDid is null in metaData"); + public static String NotExistCliamIssuer = getError(58007, "DnaIdTx Error,Not exist cliam issuer"); + public static String NotFoundPublicKeyId = getError(58008, "DnaIdTx Error,not found PublicKeyId"); + public static String PublicKeyIdErr = getError(58009, "DnaIdTx Error,PublicKeyId err"); + public static String BlockHeightNotMatch = getError(58010, "DnaIdTx Error,BlockHeight not match"); + public static String NodesNotMatch = getError(58011, "DnaIdTx Error,nodes not match"); + public static String ResultIsNull = getError(58012, "DnaIdTx Error,result is null"); + public static String CreateDnaIdClaimErr = getError(58013, "DnaIdTx Error, createDnaIdClaim error"); + public static String VerifyDnaIdClaimErr = getError(58014, "DnaIdTx Error, verifyDnaIdClaim error"); + public static String WriteVarBytesError = getError(58015, "DnaIdTx Error, writeVarBytes error"); + public static String SendRawTransactionPreExec = getError(58016, "DnaIdTx Error, sendRawTransaction PreExec error"); + public static String SenderAmtNotEqPasswordAmt = getError(58017, "DnaIdTx Error, senders amount is not equal password amount"); + public static String ExpireErr = getError(58017, "DnaIdTx Error, expire is wrong"); + public static String GetStatusErr(String msg){return getError(58017, "GetStatus Error," + msg);} ; + + + //OntAsset Error + public static String AssetNameError = getError(58101, "OntAsset Error,asset name error"); + public static String DidError = getError(58102, "OntAsset Error,Did error"); + public static String NullPkId = getError(58103, "OntAsset Error,null pkId"); + public static String NullClaimId = getError(58104, "OntAsset Error,null claimId"); + public static String AmountError = getError(58105, "OntAsset Error,amount or gas is less than or equal to zero"); + public static String ParamLengthNotSame = getError(58105, "OntAsset Error,param length is not the same"); + + //RecordTx Error + public static String NullKeyOrValue = getError(58201, "RecordTx Error,null key or value"); + public static String NullKey = getError(58202, "RecordTx Error,null key"); + + + //dnaSdk Error + public static String WebsocketNotInit = getError(58301, "DnaSdk Error,websocket not init"); + public static String ConnRestfulNotInit = getError(58302, "DnaSdk Error,connRestful not init"); + + + //abi error + public static String SetParamsValueValueNumError = getError(58401, "AbiFunction Error,setParamsValue value num error"); + public static String ConnectUrlErr = getError(58402, "Interfaces Error,connect error:"); + + public static String ConnectUrlErr(String msg) { + return getError(58403, "connect error:" + msg); + } + + //WalletManager Error + public static String GetAccountByAddressErr = getError(58501, "WalletManager Error,getAccountByAddress err"); + + //Param Error + public static String InvalidInterfaceParam = getError(58601, "Interface Param Error, empty or null param founded"); + + public static String OtherError(String msg) { + return getError(59000, "Other Error," + msg); + } +} diff --git a/src/main/java/DNA/Fixed8.java b/src/main/java/com/github/DNAProject/common/Fixed8.java similarity index 55% rename from src/main/java/DNA/Fixed8.java rename to src/main/java/com/github/DNAProject/common/Fixed8.java index e3da6f8..65b968c 100644 --- a/src/main/java/DNA/Fixed8.java +++ b/src/main/java/com/github/DNAProject/common/Fixed8.java @@ -1,134 +1,153 @@ -package DNA; +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.common; import java.io.IOException; import java.math.BigDecimal; import java.util.function.Function; -import DNA.IO.BinaryReader; -import DNA.IO.BinaryWriter; -import DNA.IO.Serializable; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; /** - * Number type in block. this type Can be accurate to 64-bit fixed-point, the rounding - * error to a minimum. By controlling the multiplier's accuracy, - * the rounding error can be completely eliminated - * - * @author 12146 - * @since JDK1.8 + * */ public class Fixed8 implements Comparable, Serializable { - private static final long D = 100000000L; - private long value; + public static final Fixed8 MAX_VALUE = new Fixed8(Long.MAX_VALUE); public static final Fixed8 MIN_VALUE = new Fixed8(Long.MIN_VALUE); - public static final Fixed8 ONE = new Fixed8(D); public static final Fixed8 SATOSHI = new Fixed8(1); public static final Fixed8 ZERO = new Fixed8(0); - + public static int DefaultPrecision = 8; + private static final long D = (long) Math.pow(10, DefaultPrecision); + public static final Fixed8 ONE = new Fixed8(D); + private long value; + public Fixed8() { - this(0); + this(0); } public Fixed8(long data) { this.value = data; } - public Fixed8 abs() { - if (value >= 0) { - return this; - } - return new Fixed8(-value); - } - - @Override - public int compareTo(Fixed8 other) { - return Long.compare(value, other.value); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof Fixed8)) { - return false; - } - return value == ((Fixed8) obj).value; - } - public static Fixed8 fromDecimal(BigDecimal val) { return new Fixed8(val.multiply(new BigDecimal(D)).longValueExact()); } - + public static Fixed8 fromLong(long val) { - if (val < 0 || val > Long.MAX_VALUE / D) { - throw new IllegalArgumentException(); - } - return new Fixed8(val * D); + if (val < 0 || val > Long.MAX_VALUE / D) { + throw new IllegalArgumentException(); + } + return new Fixed8(val * D); } - + public static Fixed8 parse(String s) { return fromDecimal(new BigDecimal(s)); } - public long getData() { - return value; - } - - @Override - public int hashCode() { - return Long.valueOf(value).hashCode(); - } - - public static Fixed8 max(Fixed8 first, Fixed8 ...others) { + public static Fixed8 max(Fixed8 first, Fixed8... others) { for (Fixed8 other : others) { if (first.compareTo(other) < 0) { - first = other; + first = other; } } return first; } - public static Fixed8 min(Fixed8 first, Fixed8 ...others) { + public static Fixed8 min(Fixed8 first, Fixed8... others) { for (Fixed8 other : others) { if (first.compareTo(other) > 0) { - first = other; + first = other; } } return first; } public static Fixed8 sum(Fixed8[] values) { - return sum(values, p -> p); + return sum(values, p -> p); } - + public static Fixed8 sum(T[] values, Function selector) { - Fixed8 sum = Fixed8.ZERO; + Fixed8 sum = Fixed8.ZERO; for (T item : values) { sum = sum.add(selector.apply(item)); } return sum; } - @Override - public String toString() { - BigDecimal v = new BigDecimal(value); - v = v.divide(new BigDecimal(D), 8, BigDecimal.ROUND_UNNECESSARY); - return v.toPlainString(); - } - public static boolean tryParse(String s, Fixed8 result) { try { BigDecimal val = new BigDecimal(s); result.value = val.longValueExact(); return true; - } catch(NumberFormatException | ArithmeticException ex) { + } catch (NumberFormatException | ArithmeticException ex) { return false; } } + public Fixed8 abs() { + if (value >= 0) { + return this; + } + return new Fixed8(-value); + } + + @Override + public int compareTo(Fixed8 other) { + return Long.compare(value, other.value); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Fixed8)) { + return false; + } + return value == ((Fixed8) obj).value; + } + + + public long getData() { + return value; + } + + @Override + public int hashCode() { + return Long.valueOf(value).hashCode(); + } + + + @Override + public String toString() { + BigDecimal v = new BigDecimal(value); + v = v.divide(new BigDecimal(D), DefaultPrecision, BigDecimal.ROUND_UNNECESSARY); + return v.toPlainString(); + } + + public long toLong() { return value / D; } @@ -142,24 +161,24 @@ public Fixed8 divide(long other) { } public Fixed8 add(Fixed8 other) { - return new Fixed8(Math.addExact(this.value, other.value)); + return new Fixed8(Math.addExact(this.value, other.value)); } public Fixed8 subtract(Fixed8 other) { - return new Fixed8(Math.subtractExact(this.value, other.value)); + return new Fixed8(Math.subtractExact(this.value, other.value)); } public Fixed8 negate() { return new Fixed8(-value); } - @Override - public void serialize(BinaryWriter writer) throws IOException { - writer.writeLong(value); - } + @Override + public void serialize(BinaryWriter writer) throws IOException { + writer.writeLong(value); + } - @Override - public void deserialize(BinaryReader reader) throws IOException { - value = reader.readLong(); - } + @Override + public void deserialize(BinaryReader reader) throws IOException { + value = reader.readLong(); + } } \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/common/Helper.java b/src/main/java/com/github/DNAProject/common/Helper.java new file mode 100644 index 0000000..be2e2b5 --- /dev/null +++ b/src/main/java/com/github/DNAProject/common/Helper.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.common; + +import java.math.BigInteger; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.Map; + +/** + * Byte Handle Helper + */ +public class Helper { + public static String getbyteStr(byte[] bs) { + StringBuilder sb = new StringBuilder(); + for (byte b : bs) { + sb.append(" ").append(Byte.toUnsignedInt(b)); + } + return sb.substring(1); + } + + public static byte[] reverse(byte[] v) { + byte[] result = new byte[v.length]; + for (int i = 0; i < v.length; i++) { + result[i] = v[v.length - i - 1]; + } + return result; + } + + public static byte[] BigIntToNeoBytes(BigInteger data){ + if (data.equals(BigInteger.ZERO)) { + return new byte[0]; + } + byte[] bs = data.toByteArray(); + if(bs.length == 0) { + return new byte[0]; + } + if(data.signum() < 0) { + byte b = data.negate().toByteArray()[0]; + byte[] res = reverse(bs); + if(b >> 7 == 1){ + byte[] t = new byte[res.length + 1]; + System.arraycopy(res,0,t,0,res.length); + t[res.length] = (byte)255; + return t; + } + return res; + }else{ + byte b = bs[0]; + byte[] res = reverse(bs); + if(b >> 7 == 1){ + byte[] t = new byte[res.length + 1]; + System.arraycopy(res,0,t,0,res.length); + t[res.length] = (byte)0; + return t; + } + return res; + } + } + + public static BigInteger BigIntFromNeoBytes(byte[] ba){ + if(ba.length == 0){ + return BigInteger.ZERO; + } + byte[] bs = reverse(ba); + if(bs[0] >> 7 == 1) { + for(int i = 0;i < bs.length;i++) { + bs[i] = (byte)~bs[i]; + } + BigInteger temp = new BigInteger(bs); + temp.add(BigInteger.ONE); + return temp.negate(); + } + return new BigInteger(bs); + } + + public static byte[] hexToBytes(String value) { + if (value == null || value.length() == 0) { + return new byte[0]; + } + if (value.length() % 2 == 1) { + throw new IllegalArgumentException(); + } + byte[] result = new byte[value.length() / 2]; + for (int i = 0; i < result.length; i++) { + result[i] = (byte) Integer.parseInt(value.substring(i * 2, i * 2 + 2), 16); + } + return result; + } + + public static String toHexString(byte[] value) { + StringBuilder sb = new StringBuilder(); + for (byte b : value) { + int v = Byte.toUnsignedInt(b); + sb.append(Integer.toHexString(v >>> 4)); + sb.append(Integer.toHexString(v & 0x0f)); + } + return sb.toString(); + } + + public static String reverse(String value) { + return toHexString(reverse(hexToBytes(value))); + } + + public static byte[] removePrevZero(byte[] bt) { + if (bt.length == 33 && bt[0] == 0) { + return Arrays.copyOfRange(bt, 1, 33); + } + return bt; + } + + public static byte[] addBytes(byte[] data1, byte[] data2) { + byte[] data3 = new byte[data1.length + data2.length]; + System.arraycopy(data1, 0, data3, 0, data1.length); + System.arraycopy(data2, 0, data3, data1.length, data2.length); + return data3; + } + + + public static String now() { + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()); + } + + public static String toString(Map map) { + StringBuilder sb = new StringBuilder(); + for (Map.Entry e : map.entrySet()) { + sb.append("\n").append(e.getKey() + ": " + e.getValue()); + } + return sb.toString(); + } + + public static void print(Map map) { + System.out.println(toString(map)); + } +} diff --git a/src/main/java/com/github/DNAProject/common/NotifyEventInfo.java b/src/main/java/com/github/DNAProject/common/NotifyEventInfo.java new file mode 100644 index 0000000..8f40ac0 --- /dev/null +++ b/src/main/java/com/github/DNAProject/common/NotifyEventInfo.java @@ -0,0 +1,36 @@ +package com.github.DNAProject.common; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONField; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class NotifyEventInfo { + public List States; + public String ContractAddress; + public List getStates() { + return States; + } + + public void setStates(List states) { + States = states; + } + + public String getContractAddress() { + return ContractAddress; + } + + public void setContractAddress(String contractAddress) { + ContractAddress = contractAddress; + } + + public String toJson(){ + Map map = new HashMap(); + map.put("States", States); + map.put("ContractAddress", ContractAddress); + return JSON.toJSONString(map); + } + +} diff --git a/src/main/java/com/github/DNAProject/common/SmartCodeEvent.java b/src/main/java/com/github/DNAProject/common/SmartCodeEvent.java new file mode 100644 index 0000000..ddd1e7c --- /dev/null +++ b/src/main/java/com/github/DNAProject/common/SmartCodeEvent.java @@ -0,0 +1,43 @@ +package com.github.DNAProject.common; + +import java.util.List; + +public class SmartCodeEvent { + public String TxHash; + public int State; + public long GasConsumed; + public List Notify; + + public String getTxHash() { + return TxHash; + } + + public void setTxHash(String txHash) { + TxHash = txHash; + } + + public int getState() { + return State; + } + + public void setState(int state) { + State = state; + } + + public long getGasConsumed() { + return GasConsumed; + } + + public void setGasConsumed(long gasConsumed) { + GasConsumed = gasConsumed; + } + + public List getNotify() { + return Notify; + } + + public void setNotify(List notify) { + Notify = notify; + } + +} diff --git a/src/main/java/com/github/DNAProject/common/UInt256.java b/src/main/java/com/github/DNAProject/common/UInt256.java new file mode 100644 index 0000000..3db0f19 --- /dev/null +++ b/src/main/java/com/github/DNAProject/common/UInt256.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.common; + +import com.alibaba.fastjson.JSON; + +/** + * Custom type which inherits base class defines 32-bit data, + * it mostly used to defined transaction identity + */ +public class UInt256 extends UIntBase implements Comparable { + public static final UInt256 ZERO = new UInt256(); + + public UInt256() { + this(null); + } + + public UInt256(byte[] value) { + super(32, value); + } + + + public static UInt256 parse(String s) { + if (s == null) { + throw new NullPointerException(); + } + if (s.startsWith("0x")) { + s = s.substring(2); + } + if (s.length() != 64) { + throw new IllegalArgumentException(ErrorCode.ParamLengthErr); + } + byte[] v = Helper.hexToBytes(s); +// return new UInt256(v); + return new UInt256(Helper.reverse(v)); + } + + public static boolean tryParse(String s, UInt256 result) { + try { + UInt256 v = parse(s); + result.data_bytes = v.data_bytes; + return true; + } catch (Exception e) { + return false; + } + } + + @Override + public int compareTo(UInt256 other) { + byte[] x = this.data_bytes; + byte[] y = other.data_bytes; + for (int i = x.length - 1; i >= 0; i--) { + int r = Byte.toUnsignedInt(x[i]) - Byte.toUnsignedInt(y[i]); + if (r != 0) { + return r; + } + } + return 0; + } +} \ No newline at end of file diff --git a/src/main/java/DNA/UIntBase.java b/src/main/java/com/github/DNAProject/common/UIntBase.java similarity index 51% rename from src/main/java/DNA/UIntBase.java rename to src/main/java/com/github/DNAProject/common/UIntBase.java index 6b5078b..07a441e 100644 --- a/src/main/java/DNA/UIntBase.java +++ b/src/main/java/com/github/DNAProject/common/UIntBase.java @@ -1,18 +1,35 @@ -package DNA; +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.common; import java.io.IOException; import java.nio.*; import java.util.Arrays; -import DNA.IO.*; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; /** - * Custom type base abstract class, it defines the storage and the serialization + * Custom type base abstract class, it defines the storage and the serialization * and deserialization of actual data - * - * @author 12146 - * @since JDK1.8 - * */ public abstract class UIntBase implements Serializable { protected byte[] data_bytes; @@ -23,7 +40,7 @@ protected UIntBase(int bytes, byte[] value) { return; } if (value.length != bytes) { - throw new IllegalArgumentException(); + throw new IllegalArgumentException(); } this.data_bytes = value; } @@ -36,7 +53,7 @@ public boolean equals(Object obj) { if (obj == this) { return true; } - if (!(obj instanceof UIntBase)) { + if (!(obj instanceof UIntBase)) { return false; } UIntBase other = (UIntBase) obj; @@ -48,26 +65,28 @@ public int hashCode() { return ByteBuffer.wrap(data_bytes).order(ByteOrder.LITTLE_ENDIAN).getInt(); } + @Override public byte[] toArray() { return data_bytes; } - /** - * 转为16进制字符串 - * @return 返回16进制字符串 - */ @Override public String toString() { + // return Helper.toHexString(data_bytes); return Helper.toHexString(Helper.reverse(data_bytes)); } - + @Override + public String toHexString() { + return Helper.reverse(Helper.toHexString(toArray())); + } + @Override public void serialize(BinaryWriter writer) throws IOException { - writer.write(data_bytes); + writer.write(data_bytes); } - + @Override public void deserialize(BinaryReader reader) throws IOException { - reader.read(data_bytes); + reader.read(data_bytes); } } diff --git a/src/main/java/com/github/DNAProject/common/WalletQR.java b/src/main/java/com/github/DNAProject/common/WalletQR.java new file mode 100644 index 0000000..f73ee8d --- /dev/null +++ b/src/main/java/com/github/DNAProject/common/WalletQR.java @@ -0,0 +1,93 @@ +package com.github.DNAProject.common; + + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.crypto.SignatureScheme; +import com.github.DNAProject.sdk.exception.SDKException; +import com.github.DNAProject.sdk.wallet.*; + +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +public class WalletQR { + public static Map exportIdentityQRCode(Wallet walletFile, Identity identity) throws Exception { + if(walletFile==null || identity == null){ + throw new SDKException(ErrorCode.ParamErr("walletFile or identity should not be null")); + } + Control control = identity.controls.get(0); + String address = identity.dnaid.substring(8); + Map map = new HashMap(); + map.put("type", "I"); + map.put("label",identity.label); + map.put("key", control.key); + map.put("parameters", control.parameters); + map.put("algorithm", "ECDSA"); + map.put("scrypt", walletFile.getScrypt()); + map.put("address",address); + map.put("salt", control.salt); + return map; + } + public static Map exportIdentityQRCode(Scrypt scrypt,Identity identity) throws Exception { + if(scrypt==null || identity == null){ + throw new SDKException(ErrorCode.ParamErr("scrypt or identity should not be null")); + } + Control control = identity.controls.get(0); + String address = identity.dnaid.substring(8); + Map map = new HashMap(); + map.put("type", "I"); + map.put("label",identity.label); + map.put("key", control.key); + map.put("parameters", control.parameters); + map.put("algorithm", "ECDSA"); + map.put("scrypt", scrypt); + map.put("address",address); + map.put("salt", control.salt); + return map; + } + public static Map exportAccountQRCode(Wallet walletFile,Account account) throws Exception { + if(walletFile==null || account == null){ + throw new SDKException(ErrorCode.ParamErr("walletFile or account should not be null")); + } + Map map = new HashMap(); + map.put("type", "A"); + map.put("label", account.label); + map.put("key", account.key); + map.put("parameters", account.parameters); + map.put("algorithm", "ECDSA"); + map.put("scrypt", walletFile.getScrypt()); + map.put("address",account.address); + map.put("salt", account.salt); + return map; + } + public static Map exportAccountQRCode(Scrypt scrypt, Account account) throws Exception { + if(scrypt==null || account == null){ + throw new SDKException(ErrorCode.ParamErr("scrypt or account should not be null")); + } + Map map = new HashMap(); + map.put("type", "A"); + map.put("label", account.label); + map.put("key", account.key); + map.put("parameters", account.parameters); + map.put("algorithm", "ECDSA"); + map.put("scrypt", scrypt); + map.put("address",account.address); + map.put("salt", account.salt); + return map; + } + public static String getPriKeyFromQrCode(String qrcode,String password) throws SDKException { + if(qrcode==null || qrcode.equals("") || password == null || password.equals("")){ + throw new SDKException(ErrorCode.ParamErr("qrcode or password should not be null")); + } + Map map = JSON.parseObject(qrcode,Map.class); + String key = (String)map.get("key"); + String address = (String)map.get("address"); + String salt = (String)map.get("salt"); + int n = (int)((Map)map.get("scrypt")).get("n"); + try { + return com.github.DNAProject.account.Account.getGcmDecodedPrivateKey(key,password,address, Base64.getDecoder().decode(salt),n, SignatureScheme.SHA256WITHECDSA); + } catch (Exception e) { + throw new SDKException(ErrorCode.OtherError("password and qrcode not match")); + } + } +} diff --git a/src/main/java/com/github/DNAProject/core/DataSignature.java b/src/main/java/com/github/DNAProject/core/DataSignature.java new file mode 100644 index 0000000..0d1ddc3 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/DataSignature.java @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core; + +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.crypto.SignatureScheme; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; + +import java.io.IOException; + + +public class DataSignature implements Signable { + private Account account; + private byte[] data; + private SignatureScheme scheme; + + public DataSignature() { + } + + public DataSignature(byte[] data) { + this.data = data; + } + + public DataSignature(SignatureScheme scheme, Account acct, byte[] data) { + this.scheme = scheme; + this.account = acct; + this.data = data; + } + public DataSignature(SignatureScheme scheme, Account acct, String data) { + this.scheme = scheme; + this.account = acct; + this.data = data.getBytes(); + } + + public byte[] getData() { + return data; + } + + public byte[] signature() { + try { + byte[] signData = sign(account, scheme); + return signData; + } catch (Exception e) { + throw new RuntimeException(ErrorCode.DataSignatureErr); + } + } + + @Override + public byte[] sign(Account account, SignatureScheme scheme) throws Exception { + return account.generateSignature(getHashData(), scheme, null); + } + + @Override + public boolean verifySignature(Account account, byte[] data, byte[] signature) throws Exception { + return account.verifySignature(data, signature); + } + + @Override + public Address[] getAddressU160ForVerifying() { + return null; + } + + @Override + public void deserialize(BinaryReader reader) throws IOException { + } + + @Override + public void deserializeUnsigned(BinaryReader reader) throws IOException { + } + + @Override + public void serializeUnsigned(BinaryWriter writer) throws IOException { + writer.write(data); + } + + @Override + public void serialize(BinaryWriter writer) throws IOException { + } +} diff --git a/src/main/java/com/github/DNAProject/core/Inventory.java b/src/main/java/com/github/DNAProject/core/Inventory.java new file mode 100644 index 0000000..a083716 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/Inventory.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core; + +import com.github.DNAProject.common.UInt256; +import com.github.DNAProject.crypto.Digest; + +public abstract class Inventory implements Signable { + //[NonSerialized] + private UInt256 _hash = null; + + public UInt256 hash() { + if (_hash == null) { + _hash = new UInt256(Digest.hash256(getHashData())); + } + return _hash; + } + + public abstract InventoryType inventoryType(); + + public abstract boolean verify(); +} diff --git a/src/main/java/com/github/DNAProject/core/InventoryType.java b/src/main/java/com/github/DNAProject/core/InventoryType.java new file mode 100644 index 0000000..0814af8 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/InventoryType.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core; + + +public enum InventoryType { + TX(0x01), + Block(0x02), + Consensus(0xe0), + ; + private byte value; + private InventoryType(int v) { + value = (byte)v; + } + public int value() { + return value; + } + + public static InventoryType from(byte b) { + for(InventoryType t: InventoryType.values()) { + if(t.value() == b) { + return t; + } + } + throw new IllegalArgumentException(); + } +} + diff --git a/src/main/java/com/github/DNAProject/core/Signable.java b/src/main/java/com/github/DNAProject/core/Signable.java new file mode 100644 index 0000000..2a9c12f --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/Signable.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.crypto.Digest; +import com.github.DNAProject.crypto.SignatureScheme; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; + +import com.github.DNAProject.common.Address; + + +public interface Signable extends Serializable { + + void deserializeUnsigned(BinaryReader reader) throws IOException; + + void serializeUnsigned(BinaryWriter writer) throws IOException; + + Address[] getAddressU160ForVerifying(); + + default byte[] getHashData() { + try (ByteArrayOutputStream ms = new ByteArrayOutputStream()) { + try (BinaryWriter writer = new BinaryWriter(ms)) { + serializeUnsigned(writer); + writer.flush(); + return ms.toByteArray(); + } + } catch (IOException ex) { + throw new UnsupportedOperationException(ex); + } + } + default byte[] sign(Account account, SignatureScheme scheme) throws Exception { + return account.generateSignature(Digest.hash256(getHashData()), scheme,null); + } + default boolean verifySignature(Account account, byte[] data, byte[] signature) throws Exception { + return account.verifySignature(Digest.hash256(Digest.sha256(data)), signature); + } + +} diff --git a/src/main/java/com/github/DNAProject/core/VmType.java b/src/main/java/com/github/DNAProject/core/VmType.java new file mode 100644 index 0000000..9ed181c --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/VmType.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core; + +/** + * list vm types + */ +public enum VmType { + + NEOVM(0x01), + WASMVM(0x03); + + private byte value; + VmType(int v) { + value = (byte)v; + } + public byte value() { + return value; + } + + public static VmType valueOf(byte v) { + for (VmType e : VmType.values()) { + if (e.value == v) { + return e; + } + } + throw new IllegalArgumentException(); + } +} diff --git a/src/main/java/com/github/DNAProject/core/asset/Contract.java b/src/main/java/com/github/DNAProject/core/asset/Contract.java new file mode 100644 index 0000000..11aa781 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/asset/Contract.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ +package com.github.DNAProject.core.asset; + +import com.github.DNAProject.common.Address; +import com.github.DNAProject.io.*; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +/** + * + */ +public class Contract implements Serializable { + public byte version; + public Address constracHash; + public String method; + public byte[] args; + public Contract(){ + + } + public Contract(byte version,Address constracHash, String method,byte[] args){ + this.version = version; + this.constracHash = constracHash; + this.method = method; + this.args = args; + } + @Override + public void deserialize(BinaryReader reader) throws IOException { + try { + version = reader.readByte(); + constracHash = reader.readSerializable(Address.class); + method = new String(reader.readVarBytes()); + args = reader.readVarBytes(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + + } + + @Override + public void serialize(BinaryWriter writer) throws IOException { + writer.writeByte(version); + writer.writeSerializable(constracHash); + writer.writeVarBytes(method.getBytes()); + writer.writeVarBytes(args); + } + + + public static Contract deserializeFrom(byte[] value) throws IOException { + try { + int offset = 0; + ByteArrayInputStream ms = new ByteArrayInputStream(value, offset, value.length - offset); + BinaryReader reader = new BinaryReader(ms); + Contract contract = new Contract(); + contract.deserialize(reader); + return contract; + } catch (IOException ex) { + throw new IOException(ex); + } + } +} diff --git a/src/main/java/com/github/DNAProject/core/asset/Sig.java b/src/main/java/com/github/DNAProject/core/asset/Sig.java new file mode 100644 index 0000000..e7483a4 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/asset/Sig.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core.asset; + +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.program.Program; +import com.github.DNAProject.core.program.ProgramInfo; +import com.github.DNAProject.io.*; + +import java.io.IOException; +import java.util.*; + +import static com.github.DNAProject.core.program.Program.*; + +/** + * + */ +public class Sig implements Serializable { + public byte[][] pubKeys = null; + public int M; + public byte[][] sigData; + + @Override + public void deserialize(BinaryReader reader) throws IOException { + byte[] invocationScript = reader.readVarBytes(); + byte[] verificationScript = reader.readVarBytes(); + sigData = Program.getParamInfo(invocationScript); + ProgramInfo info = Program.getProgramInfo(verificationScript); + pubKeys = info.publicKey; + M = info.m; + } + + @Override + public void serialize(BinaryWriter writer) throws IOException { + writer.writeVarBytes(ProgramFromParams(sigData)); + try { + if(pubKeys.length == 1){ + writer.writeVarBytes(ProgramFromPubKey(pubKeys[0])); + }else if(pubKeys.length > 1){ + writer.writeVarBytes(ProgramFromMultiPubKey(M,pubKeys)); + } + } catch (Exception e) { + e.printStackTrace(); + } + + } + public Object json() { + Map json = new HashMap<>(); + json.put("M", M); + List list = new ArrayList(); + for(int i=0;iHelper.toHexString(p)).toArray(String[]::new)); + //json.put("SigData", Arrays.stream(sigData).map(p->Helper.toHexString(p)).toArray(String[]::new)); + return json; + } + +} diff --git a/src/main/java/com/github/DNAProject/core/asset/State.java b/src/main/java/com/github/DNAProject/core/asset/State.java new file mode 100644 index 0000000..7edf6af --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/asset/State.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core.asset; + +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.io.*; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.util.HashMap; +import java.util.Map; + +/** + * + */ +public class State implements Serializable { + public Address from; + public Address to; + public long value; + public State(){} + public State(Address from, Address to, long amount){ + this.from = from; + this.to = to; + this.value = amount; + } + @Override + public void deserialize(BinaryReader reader) throws IOException { + from = new Address(reader.readVarBytes()); + to = new Address(reader.readVarBytes()); + value = Helper.BigIntFromNeoBytes(reader.readVarBytes()).longValue(); + } + + @Override + public void serialize(BinaryWriter writer) throws IOException { + writer.writeVarBytes(from.toArray()); + writer.writeVarBytes(to.toArray()); + writer.writeVarBytes(Helper.BigIntToNeoBytes(BigInteger.valueOf(value))); + } + + public static State deserializeFrom(byte[] value) throws IOException { + try { + int offset = 0; + ByteArrayInputStream ms = new ByteArrayInputStream(value, offset, value.length - offset); + BinaryReader reader = new BinaryReader(ms); + State state = new State(); + state.deserialize(reader); + return state; + } catch (IOException ex) { + throw new IOException(ex); + } + } + public Object json() { + Map json = new HashMap<>(); + json.put("from", from.toHexString()); + json.put("to", to.toHexString()); + json.put("value", value); + return json; + } + +} diff --git a/src/main/java/com/github/DNAProject/core/asset/TransferFrom.java b/src/main/java/com/github/DNAProject/core/asset/TransferFrom.java new file mode 100644 index 0000000..215e258 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/asset/TransferFrom.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core.asset; + +import com.github.DNAProject.common.Address; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +/** + * + */ +public class TransferFrom implements Serializable { + public Address sender; + public Address from; + public Address to; + public long value; + + public TransferFrom(Address sender,Address from, Address to, long amount){ + this.sender = sender; + this.from = from; + this.to = to; + this.value = amount; + } + @Override + public void deserialize(BinaryReader reader) throws IOException { + try { + sender = reader.readSerializable(Address.class); + from = reader.readSerializable(Address.class); + to = reader.readSerializable(Address.class); + value = reader.readVarInt(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + @Override + public void serialize(BinaryWriter writer) throws IOException { + writer.writeSerializable(sender); + writer.writeSerializable(from); + writer.writeSerializable(to); + writer.writeVarInt(value); + + } + + + public Object json() { + Map json = new HashMap<>(); + json.put("sender", sender.toHexString()); + json.put("from", from.toHexString()); + json.put("to", to.toHexString()); + json.put("value", value); + return json; + } + +} diff --git a/src/main/java/com/github/DNAProject/core/asset/Transfers.java b/src/main/java/com/github/DNAProject/core/asset/Transfers.java new file mode 100644 index 0000000..bf57468 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/asset/Transfers.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core.asset; + +import com.github.DNAProject.io.*; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * + */ +public class Transfers implements Serializable { + public State[] states; + public Transfers(){ + + } + public Transfers(State[] states){ + this.states = states; + } + @Override + public void deserialize(BinaryReader reader) throws IOException { + int len = (int)reader.readVarInt(); + states = new State[len]; + for(int i = 0;i (); + List list = new ArrayList<>(); + for(int i=0;i. + * + */ + +package com.github.DNAProject.core.block; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.common.*; +import com.github.DNAProject.core.Inventory; +import com.github.DNAProject.core.InventoryType; +import com.github.DNAProject.core.payload.Bookkeeping; +import com.github.DNAProject.core.payload.DeployCode; +import com.github.DNAProject.core.payload.InvokeCode; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; +import org.bouncycastle.math.ec.ECPoint; + +/** + * block + */ +public class Block extends Inventory { + + public int version; + public UInt256 prevBlockHash; + public UInt256 transactionsRoot; + public UInt256 blockRoot; + public int timestamp; + public int height; + public long consensusData; + public byte[] consensusPayload; + public Address nextBookkeeper; + public String[] sigData; + public byte[][] bookkeepers; + public Transaction[] transactions; + public UInt256 hash; + private Block _header = null; + + public Block header() { + if (isHeader()) { + return this; + } + if (_header == null) { + _header = new Block(); + _header.prevBlockHash = prevBlockHash; + _header.transactionsRoot = this.transactionsRoot; + _header.blockRoot = this.blockRoot; + _header.timestamp = this.timestamp; + _header.height = this.height; + _header.consensusData = this.consensusData; + _header.nextBookkeeper = this.nextBookkeeper; + _header.sigData = this.sigData; + _header.bookkeepers = this.bookkeepers; + _header.transactions = new Transaction[0]; + } + return _header; + } + + @Override + public InventoryType inventoryType() { + return InventoryType.Block; + } + + public boolean isHeader() { + return transactions.length == 0; + } + + @Override + public void deserialize(BinaryReader reader) throws IOException { + deserializeUnsigned(reader); + int len = (int) reader.readVarInt(); + sigData = new String[len]; + for (int i = 0; i < len; i++) { + this.sigData[i] = Helper.toHexString(reader.readVarBytes()); + } + + len = reader.readInt(); + transactions = new Transaction[len]; + for (int i = 0; i < transactions.length; i++) { + transactions[i] = Transaction.deserializeFrom(reader); + } + } + + @Override + public void deserializeUnsigned(BinaryReader reader) throws IOException { + try { + version = reader.readInt(); + prevBlockHash = reader.readSerializable(UInt256.class); + transactionsRoot = reader.readSerializable(UInt256.class); + blockRoot = reader.readSerializable(UInt256.class); + timestamp = reader.readInt(); + height = reader.readInt(); + consensusData = Long.valueOf(reader.readLong()); + consensusPayload = reader.readVarBytes(); + nextBookkeeper = reader.readSerializable(Address.class); + int len = (int) reader.readVarInt(); + bookkeepers = new byte[len][]; + for (int i = 0; i < len; i++) { + this.bookkeepers[i] = reader.readVarBytes(); + } + transactions = new Transaction[0]; + } catch (InstantiationException | IllegalAccessException ex) { + throw new IOException(ex); + } + } + + @Override + public void serialize(BinaryWriter writer) throws IOException { + serializeUnsigned(writer); + writer.writeVarInt(bookkeepers.length); + for(int i=0;iHelper.toHexString(p)).toArray(Object[]::new)); + + json.put("Header", head); + json.put("Transactions", Arrays.stream(transactions).map(p -> { + if (p instanceof InvokeCode) { + return ((InvokeCode) p).json(); + } else if (p instanceof DeployCode) { + return ((DeployCode) p).json(); + } else if (p instanceof Bookkeeping) { + return ((Bookkeeping) p).json(); + } else { + return p.json(); + } + }).toArray(Object[]::new)); + return JSON.toJSONString(json); + } + + public byte[] trim() { + try (ByteArrayOutputStream ms = new ByteArrayOutputStream()) { + try (BinaryWriter writer = new BinaryWriter(ms)) { + serializeUnsigned(writer); + writer.writeByte((byte) 1); + writer.writeSerializableArray(Arrays.stream(transactions).map(p -> p.hash()).toArray(Serializable[]::new)); + writer.flush(); + return ms.toByteArray(); + } + } catch (IOException ex) { + throw new UnsupportedOperationException(ex); + } + } + + public static Block fromTrimmedData(byte[] data, int index, Function txSelector) throws IOException { + Block block = new Block(); + try (ByteArrayInputStream ms = new ByteArrayInputStream(data, index, data.length - index)) { + try (BinaryReader reader = new BinaryReader(ms)) { + block.deserializeUnsigned(reader); + reader.readByte(); + if (txSelector == null) { + block.transactions = new Transaction[0]; + } else { + block.transactions = new Transaction[(int) reader.readVarInt(0x10000000)]; + for (int i = 0; i < block.transactions.length; i++) { + block.transactions[i] = txSelector.apply(reader.readSerializable(UInt256.class)); + } + } + } catch (InstantiationException | IllegalAccessException ex) { + throw new IOException(ex); + } + } + return block; + } + @Override + public boolean verify() { + return true; + } + +} diff --git a/src/main/java/com/github/DNAProject/core/dnaid/Attribute.java b/src/main/java/com/github/DNAProject/core/dnaid/Attribute.java new file mode 100644 index 0000000..43a50ed --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/dnaid/Attribute.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core.dnaid; + +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; + +import java.io.IOException; + +public class Attribute implements Serializable { + public byte[] key; + public byte[] valueType; + public byte[] value; + public Attribute(){} + public Attribute(byte[] key,byte[] valueType,byte[] value){ + this.key = key; + this.valueType = valueType; + this.value = value; + } + @Override + public void deserialize(BinaryReader reader) throws IOException { + this.key = reader.readVarBytes(); + this.valueType = reader.readVarBytes(); + this.value = reader.readVarBytes(); + } + + @Override + public void serialize(BinaryWriter writer) throws IOException { + writer.writeVarBytes(key); + writer.writeVarBytes(valueType); + writer.writeVarBytes(value); + } +} diff --git a/src/main/java/com/github/DNAProject/core/globalparams/Param.java b/src/main/java/com/github/DNAProject/core/globalparams/Param.java new file mode 100644 index 0000000..7e20852 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/globalparams/Param.java @@ -0,0 +1,11 @@ +package com.github.DNAProject.core.globalparams; + + +public class Param { + public String key; + public String value; + public Param(String key,String value){ + this.key = key; + this.value = value; + } +} diff --git a/src/main/java/com/github/DNAProject/core/globalparams/Params.java b/src/main/java/com/github/DNAProject/core/globalparams/Params.java new file mode 100644 index 0000000..5abc9da --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/globalparams/Params.java @@ -0,0 +1,33 @@ +package com.github.DNAProject.core.globalparams; + +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; + +import java.io.IOException; +import java.math.BigInteger; + +public class Params implements Serializable { + public Param[] params; + public Params(Param[] params) { + this.params = params; + } + + @Override + public void deserialize(BinaryReader reader) throws IOException { + + } + + @Override + public void serialize(BinaryWriter writer) throws IOException { + long l = params.length; + byte[] aa = Helper.BigIntToNeoBytes(BigInteger.valueOf(l)); + String bb = Helper.toHexString(aa); + writer.writeVarBytes(aa); + for(int i=0;i< params.length;i++) { + writer.writeVarString(params[i].key); + writer.writeVarString(params[i].value); + } + } +} diff --git a/src/main/java/com/github/DNAProject/core/governance/AuthorizeInfo.java b/src/main/java/com/github/DNAProject/core/governance/AuthorizeInfo.java new file mode 100644 index 0000000..97e4e3d --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/governance/AuthorizeInfo.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core.governance; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class AuthorizeInfo implements Serializable { + public String peerPubkey; + public Address address; + public long consensusPos; + public long freezePos; + public long newPos; + public long withdrawPos; + public long withdrawFreezePos; + public long withdrawUnfreezePos; + + public AuthorizeInfo(){} + + @Override + public void deserialize(BinaryReader reader) throws IOException { + this.peerPubkey = reader.readVarString(); + try { + this.address = reader.readSerializable(Address.class); + this.consensusPos = reader.readLong(); + this.freezePos = reader.readLong(); + this.newPos = reader.readLong(); + this.withdrawPos = reader.readLong(); + this.withdrawFreezePos = reader.readLong(); + this.withdrawUnfreezePos = reader.readLong(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + @Override + public void serialize(BinaryWriter writer) throws IOException { + + } + + public String toJson(){ + Map map = new HashMap(); + map.put("peerPubkey",peerPubkey); + map.put("address",address.toBase58()); + map.put("consensusPos",consensusPos); + map.put("freezePos",freezePos); + map.put("newPos",newPos); + map.put("withdrawPos",withdrawPos); + map.put("withdrawFreezePos",withdrawFreezePos); + map.put("withdrawUnfreezePos",withdrawUnfreezePos); + return JSON.toJSONString(map); + } +} diff --git a/src/main/java/com/github/DNAProject/core/governance/Configuration.java b/src/main/java/com/github/DNAProject/core/governance/Configuration.java new file mode 100644 index 0000000..c043017 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/governance/Configuration.java @@ -0,0 +1,50 @@ +package com.github.DNAProject.core.governance; + +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; +import com.github.DNAProject.io.utils; + +import java.io.IOException; + +public class Configuration implements Serializable { + public int N; + public int C; + public int K; + public int L; + public int BlockMsgDelay; + public int HashMsgDelay; + public int PeerHandshakeTimeout; + public int MaxBlockChangeView; + public Configuration(){ + + } + public Configuration(int N,int C,int K,int L,int BlockMsgDelay, int HashMsgDelay,int PeerHandshakeTimeout, int MaxBlockChangeView){ + this.N = N; + this.C = C; + this.K = K; + this.L = L; + this.BlockMsgDelay = BlockMsgDelay; + this.HashMsgDelay = HashMsgDelay; + this.PeerHandshakeTimeout = PeerHandshakeTimeout; + this.MaxBlockChangeView = MaxBlockChangeView; + } + + @Override + public void deserialize(BinaryReader reader) throws IOException { + + this.N = (int)utils.readVarInt(reader); + this.C = (int)utils.readVarInt(reader); + this.K = (int)utils.readVarInt(reader); + this.L = (int)utils.readVarInt(reader); + this.BlockMsgDelay = (int)utils.readVarInt(reader); + this.HashMsgDelay = (int)utils.readVarInt(reader); + this.PeerHandshakeTimeout = (int)utils.readVarInt(reader); + this.MaxBlockChangeView = (int)utils.readVarInt(reader); + } + + @Override + public void serialize(BinaryWriter binaryWriter) throws IOException { + + } +} diff --git a/src/main/java/com/github/DNAProject/core/governance/GlobalParam.java b/src/main/java/com/github/DNAProject/core/governance/GlobalParam.java new file mode 100644 index 0000000..4194c41 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/governance/GlobalParam.java @@ -0,0 +1,35 @@ +package com.github.DNAProject.core.governance; + +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; +import com.github.DNAProject.io.utils; + +import java.io.IOException; + +public class GlobalParam implements Serializable { + public int candidateFeeSplitNum; + public int A; + public int B; + public int yita; + public GlobalParam(){} + public GlobalParam(int CandidateFeeSplitNum, int A, int B, int Yita){ + this.candidateFeeSplitNum = CandidateFeeSplitNum; + this.A = A; + this.B = B; + this.yita = Yita; + } + + @Override + public void deserialize(BinaryReader reader) throws IOException { + this.candidateFeeSplitNum = (int)utils.readVarInt(reader); + this.A = (int)utils.readVarInt(reader); + this.B = (int)utils.readVarInt(reader); + this.yita = (int)utils.readVarInt(reader); + } + + @Override + public void serialize(BinaryWriter binaryWriter) throws IOException { + + } +} diff --git a/src/main/java/com/github/DNAProject/core/governance/GlobalParam1.java b/src/main/java/com/github/DNAProject/core/governance/GlobalParam1.java new file mode 100644 index 0000000..4b5b63a --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/governance/GlobalParam1.java @@ -0,0 +1,43 @@ +package com.github.DNAProject.core.governance; + +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; +import com.github.DNAProject.io.utils; + +import java.io.IOException; + +public class GlobalParam1 implements Serializable { + public long candidateFee; + public int minInitStake; + public int candidateNum; + public int posLimit; + public int A; + public int B; + public int yita; + public int penalty; + public GlobalParam1(){} + public GlobalParam1(int CandidateFeeSplitNum, int A, int B, int Yita){ + this.candidateFee = CandidateFeeSplitNum; + this.A = A; + this.B = B; + this.yita = Yita; + } + + @Override + public void deserialize(BinaryReader reader) throws IOException { + this.candidateFee = utils.readVarInt(reader); + this.minInitStake = (int)utils.readVarInt(reader); + this.candidateNum = (int)utils.readVarInt(reader); + this.posLimit = (int)utils.readVarInt(reader); + this.A = (int)utils.readVarInt(reader); + this.B = (int)utils.readVarInt(reader); + this.yita = (int)utils.readVarInt(reader); + this.penalty = (int)utils.readVarInt(reader); + } + + @Override + public void serialize(BinaryWriter binaryWriter) throws IOException { + + } +} diff --git a/src/main/java/com/github/DNAProject/core/governance/GlobalParam2.java b/src/main/java/com/github/DNAProject/core/governance/GlobalParam2.java new file mode 100644 index 0000000..4bcffb6 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/governance/GlobalParam2.java @@ -0,0 +1,51 @@ +package com.github.DNAProject.core.governance; + +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; +import com.github.DNAProject.io.utils; + +import java.io.IOException; + +public class GlobalParam2 implements Serializable { + public int minAuthorizePos; + public int candidateFeeSplitNum; + public byte[] field1; + public byte[] field2; + public byte[] field3; + public byte[] field4; + public byte[] field5; + public byte[] field6; + public GlobalParam2(){ + + } + public GlobalParam2(int minAuthorizePos, int candidateFeeSplitNum, byte[] field1, byte[] field2, byte[] field3, byte[] field4, + byte[] field5, byte[] field6){ + this.minAuthorizePos = minAuthorizePos; + this.candidateFeeSplitNum = candidateFeeSplitNum; + this.field1 = field1; + this.field2 = field2; + this.field3 = field3; + this.field4 = field4; + this.field5 = field5; + this.field6 = field6; + + } + @Override + public void deserialize(BinaryReader reader) throws IOException { + this.minAuthorizePos = (int)utils.readVarInt(reader); + this.candidateFeeSplitNum = (int)utils.readVarInt(reader); + this.field1 = reader.readVarBytes(); + this.field2 = reader.readVarBytes(); + this.field3 = reader.readVarBytes(); + this.field4 = reader.readVarBytes(); + this.field5 = reader.readVarBytes(); + this.field6 = reader.readVarBytes(); + + } + + @Override + public void serialize(BinaryWriter writer) throws IOException { + + } +} diff --git a/src/main/java/com/github/DNAProject/core/governance/GovernanceView.java b/src/main/java/com/github/DNAProject/core/governance/GovernanceView.java new file mode 100644 index 0000000..129a1b9 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/governance/GovernanceView.java @@ -0,0 +1,40 @@ +package com.github.DNAProject.core.governance; + +import com.github.DNAProject.common.UInt256; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; + +import java.io.IOException; + +public class GovernanceView implements Serializable { + public int view; + public int height; + public UInt256 txhash; + public GovernanceView(){ + } + GovernanceView(int view,int height,UInt256 txhash){ + this.view = view; + this.height = height; + this.txhash = txhash; + } + @Override + public void deserialize(BinaryReader reader) throws IOException { + this.view = reader.readInt(); + this.height = reader.readInt(); + try { + this.txhash = reader.readSerializable(UInt256.class); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + @Override + public void serialize(BinaryWriter writer) throws IOException { + writer.writeInt(view); + writer.writeInt(height); + writer.writeSerializable(txhash); + } +} diff --git a/src/main/java/com/github/DNAProject/core/governance/InputPeerPoolMapParam.java b/src/main/java/com/github/DNAProject/core/governance/InputPeerPoolMapParam.java new file mode 100644 index 0000000..d6b322c --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/governance/InputPeerPoolMapParam.java @@ -0,0 +1,14 @@ +package com.github.DNAProject.core.governance; + +import com.github.DNAProject.core.sidechaingovernance.NodeToSideChainParams; + +import java.util.Map; + +public class InputPeerPoolMapParam { + public Map peerPoolMap; + public Map nodeInfoMap; + public InputPeerPoolMapParam(Map peerPoolMap, Map nodeInfoMap){ + this.peerPoolMap = peerPoolMap; + this.nodeInfoMap = nodeInfoMap; + } +} diff --git a/src/main/java/com/github/DNAProject/core/governance/NodeToSideChainParams.java b/src/main/java/com/github/DNAProject/core/governance/NodeToSideChainParams.java new file mode 100644 index 0000000..98fb5c4 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/governance/NodeToSideChainParams.java @@ -0,0 +1,28 @@ +package com.github.DNAProject.core.governance; + +import com.github.DNAProject.common.Address; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; +import com.github.DNAProject.io.utils; + +import java.io.IOException; + +public class NodeToSideChainParams implements Serializable { + public String peerPubkey; + public Address address; + public String sideChainId; + public NodeToSideChainParams(){} + + @Override + public void deserialize(BinaryReader reader) throws IOException { + this.peerPubkey = reader.readVarString(); + this.address = utils.readAddress(reader); + this.sideChainId = reader.readVarString(); + } + + @Override + public void serialize(BinaryWriter binaryWriter) throws IOException { + + } +} diff --git a/src/main/java/com/github/DNAProject/core/governance/PeerPoolItem.java b/src/main/java/com/github/DNAProject/core/governance/PeerPoolItem.java new file mode 100644 index 0000000..00e1df8 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/governance/PeerPoolItem.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core.governance; + +import com.github.DNAProject.common.Address; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class PeerPoolItem implements Serializable { + public int index; + public String peerPubkey; + public Address address; + public int status; + public long initPos; + public long totalPos; + public PeerPoolItem(){} + public PeerPoolItem(int index,String peerPubkey,Address address,int status,long initPos,long totalPos){ + this.index = index; + this.peerPubkey = peerPubkey; + this.address = address; + this.status = status; + this.initPos = initPos; + this.totalPos = totalPos; + } + + @Override + public void deserialize(BinaryReader reader) throws IOException { + this.index = reader.readInt(); + this.peerPubkey = reader.readVarString(); + try { + this.address = reader.readSerializable(Address.class); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + this.status = reader.readByte(); + this.initPos = reader.readLong(); + this.totalPos = reader.readLong(); + } + + @Override + public void serialize(BinaryWriter writer) throws IOException { + writer.writeInt(index); + writer.writeVarString(peerPubkey); + writer.writeSerializable(address); + writer.writeByte((byte)status); + writer.writeLong(initPos); + writer.writeLong(totalPos); + } + public Object Json(){ + Map map = new HashMap(); + map.put("index",index); + map.put("peerPubkey",peerPubkey); + map.put("address",address.toBase58()); + map.put("status",status); + map.put("initPos",initPos); + map.put("totalPos",totalPos); + return map; + } +} diff --git a/src/main/java/com/github/DNAProject/core/governance/SplitCurve.java b/src/main/java/com/github/DNAProject/core/governance/SplitCurve.java new file mode 100644 index 0000000..116454b --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/governance/SplitCurve.java @@ -0,0 +1,35 @@ +package com.github.DNAProject.core.governance; + +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; + +import java.io.IOException; +import java.math.BigInteger; + +public class SplitCurve implements Serializable { + public int[] Yi; + public SplitCurve(){} + public SplitCurve(int[] Yi){ + this.Yi = Yi; + } + + @Override + public void deserialize(BinaryReader reader) throws IOException { + byte[] nBytes = reader.readVarBytes(); + BigInteger b = Helper.BigIntFromNeoBytes(nBytes); + int n = b.intValue(); + this.Yi = new int[n]; + for(int i=0; i. + * + */ + +package com.github.DNAProject.core.payload; + +import java.io.IOException; +import java.math.BigInteger; + +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.transaction.TransactionType; +import com.github.DNAProject.core.transaction.Transaction; +import org.bouncycastle.math.ec.ECPoint; + +import com.github.DNAProject.crypto.ECC; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; + +/** + * + */ +public class Bookkeeper extends Transaction { + public ECPoint issuer; + public BookkeeperAction action; + public byte[] cert; + + public Bookkeeper() { + super(TransactionType.Bookkeeper); + } + + @Override + protected void deserializeExclusiveData(BinaryReader reader) throws IOException { + issuer = ECC.secp256r1.getCurve().createPoint( + new BigInteger(1, reader.readVarBytes()), new BigInteger(1, reader.readVarBytes())); + action = BookkeeperAction.valueOf(reader.readByte()); + cert = reader.readVarBytes(); + } + + @Override + public Address[] getAddressU160ForVerifying() { + return null; + } + + @Override + protected void serializeExclusiveData(BinaryWriter writer) throws IOException { + writer.writeVarBytes(Helper.removePrevZero(issuer.getXCoord().toBigInteger().toByteArray())); + writer.writeVarBytes(Helper.removePrevZero(issuer.getYCoord().toBigInteger().toByteArray())); + writer.writeByte(action.value()); + writer.writeVarBytes(cert); + } +} diff --git a/src/main/java/com/github/DNAProject/core/payload/BookkeeperAction.java b/src/main/java/com/github/DNAProject/core/payload/BookkeeperAction.java new file mode 100644 index 0000000..c53b8a2 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/payload/BookkeeperAction.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core.payload; + +public enum BookkeeperAction { + BookKeeperAction_ADD(0x00), + BookKeeperAction_SUB(0x01),; + private byte value; + + BookkeeperAction(int v) { + value = (byte) v; + } + + + public static BookkeeperAction valueOf(byte v) { + for (BookkeeperAction e : BookkeeperAction.values()) { + if (e.value == v) { + return e; + } + } + throw new IllegalArgumentException(); + } + + public byte value() { + return value; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/core/payload/Bookkeeping.java b/src/main/java/com/github/DNAProject/core/payload/Bookkeeping.java new file mode 100644 index 0000000..41452b1 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/payload/Bookkeeping.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core.payload; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import com.github.DNAProject.common.Address; +import com.github.DNAProject.core.transaction.TransactionType; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; + +public class Bookkeeping extends Transaction { + private long nonce; + + public Bookkeeping() { + super(TransactionType.Bookkeeping); + } + + @Override + protected void deserializeExclusiveData(BinaryReader reader) throws IOException { + nonce = reader.readLong(); + } + + @Override + public Address[] getAddressU160ForVerifying() { + return null; + } + + @Override + protected void serializeExclusiveData(BinaryWriter writer) throws IOException { + writer.writeLong(nonce); + } + + @Override + public Object json() { + Map obj = (Map) super.json(); + Map payload = new HashMap(); + payload.put("Nonce", nonce); + obj.put("Payload", payload); + return obj; + } +} diff --git a/src/main/java/com/github/DNAProject/core/payload/DeployCode.java b/src/main/java/com/github/DNAProject/core/payload/DeployCode.java new file mode 100644 index 0000000..ce6f9d2 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/payload/DeployCode.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core.payload; + +import java.io.IOException; + +import com.github.DNAProject.common.Address; +import com.github.DNAProject.core.transaction.TransactionType; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; + +public class DeployCode extends Transaction { + public byte[] code; + public boolean needStorage; + public String name; + public String version; + public String author; + public String email; + public String description; + + + public DeployCode() { + super(TransactionType.DeployCode); + } + + @Override + public void deserializeExclusiveData(BinaryReader reader) throws IOException { + try { + code = reader.readVarBytes(); + needStorage = reader.readBoolean(); + name = reader.readVarString(); + version = reader.readVarString(); + author = reader.readVarString(); + email = reader.readVarString(); + description = reader.readVarString(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + protected void serializeExclusiveData(BinaryWriter writer) throws IOException { + writer.writeVarBytes(code); + writer.writeBoolean(needStorage); + writer.writeVarString(name); + writer.writeVarString(version); + writer.writeVarString(author); + writer.writeVarString(email); + writer.writeVarString(description); + } + + @Override + public Address[] getAddressU160ForVerifying() { + return null; + } +} diff --git a/src/main/java/com/github/DNAProject/core/payload/DeployWasmCode.java b/src/main/java/com/github/DNAProject/core/payload/DeployWasmCode.java new file mode 100644 index 0000000..4fc582e --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/payload/DeployWasmCode.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core.payload; + +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.VmType; +import com.github.DNAProject.core.transaction.Attribute; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.core.transaction.TransactionType; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; + +import java.io.IOException; +import java.util.Random; + +public class DeployWasmCode extends Transaction { + + public byte[] code; + public VmType vmType; + public String name; + public String version; + public String author; + public String email; + public String description; + + public DeployWasmCode() { + super(TransactionType.DeployCode); + this.vmType = VmType.WASMVM; + } + + public DeployWasmCode(String codeStr, String name, String codeVersion, String author, String email, + String description, Address payer, long gasLimit, long gasPrice) { + super(TransactionType.DeployCode); + this.vmType = VmType.WASMVM; + this.attributes = new Attribute[0]; + this.code = Helper.hexToBytes(codeStr); + this.name = name; + this.version = codeVersion; + this.author = author; + this.email = email; + this.nonce = new Random().nextInt(); + this.description = description; + if (payer != null) { + this.payer = payer; + } + this.gasLimit = gasLimit; + this.gasPrice = gasPrice; + } + + @Override + public void deserializeExclusiveData(BinaryReader reader) throws IOException { + try { + code = reader.readVarBytes(); + vmType = VmType.valueOf(reader.readByte()); + name = reader.readVarString(); + version = reader.readVarString(); + author = reader.readVarString(); + email = reader.readVarString(); + description = reader.readVarString(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + protected void serializeExclusiveData(BinaryWriter writer) throws IOException { + writer.writeVarBytes(code); + writer.writeByte(vmType.value()); + writer.writeVarString(name); + writer.writeVarString(version); + writer.writeVarString(author); + writer.writeVarString(email); + writer.writeVarString(description); + } + +} diff --git a/src/main/java/com/github/DNAProject/core/payload/Enrollment.java b/src/main/java/com/github/DNAProject/core/payload/Enrollment.java new file mode 100644 index 0000000..fa923a4 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/payload/Enrollment.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core.payload; + +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.transaction.TransactionType; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.crypto.ECC; +import com.github.DNAProject.io.BinaryReader; +import org.bouncycastle.math.ec.ECPoint; + +import java.io.IOException; +import java.math.BigInteger; + +/** + * + */ +public class Enrollment extends Transaction { + public ECPoint pubKey; + + public Enrollment() { + super(TransactionType.Enrollment); + } + + @Override + protected void deserializeExclusiveData(BinaryReader reader) throws IOException { + try { + pubKey = ECC.secp256r1.getCurve().createPoint( + new BigInteger(1, reader.readVarBytes()), new BigInteger(1, reader.readVarBytes())); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public Address[] getAddressU160ForVerifying() { + return null; + } + + @Override + protected void serializeExclusiveData(BinaryWriter writer) throws IOException { + writer.writeVarBytes(Helper.removePrevZero(pubKey.getXCoord().toBigInteger().toByteArray())); + writer.writeVarBytes(Helper.removePrevZero(pubKey.getYCoord().toBigInteger().toByteArray())); + } +} diff --git a/src/main/java/com/github/DNAProject/core/payload/InvokeCode.java b/src/main/java/com/github/DNAProject/core/payload/InvokeCode.java new file mode 100644 index 0000000..4cce263 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/payload/InvokeCode.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core.payload; + +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.core.transaction.TransactionType; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.common.Address; +import org.bouncycastle.math.ec.ECPoint; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class InvokeCode extends Transaction { + public byte[] code; + + public InvokeCode() { + super(TransactionType.InvokeCode); + } + + @Override + protected void deserializeExclusiveData(BinaryReader reader) throws IOException { + try { + code = reader.readVarBytes(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + protected void serializeExclusiveData(BinaryWriter writer) throws IOException { + writer.writeVarBytes(code); + } + + @Override + public Address[] getAddressU160ForVerifying() { + return null; + } + + @Override + public Object json() { + Map obj = (Map) super.json(); + Map payload = new HashMap(); + payload.put("Code", Helper.toHexString(code)); + obj.put("Payload", payload); + return obj; + } +} diff --git a/src/main/java/com/github/DNAProject/core/payload/InvokeWasmCode.java b/src/main/java/com/github/DNAProject/core/payload/InvokeWasmCode.java new file mode 100644 index 0000000..d49323a --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/payload/InvokeWasmCode.java @@ -0,0 +1,32 @@ +package com.github.DNAProject.core.payload; + +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.core.transaction.TransactionType; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; + +import java.io.IOException; + +public class InvokeWasmCode extends Transaction { + + public byte[] invokeCode; + + public InvokeWasmCode(byte[] invokeCode) { + super(TransactionType.InvokeWasm); + this.invokeCode = invokeCode; + } + + @Override + protected void deserializeExclusiveData(BinaryReader reader) throws IOException { + try { + invokeCode = reader.readVarBytes(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + protected void serializeExclusiveData(BinaryWriter writer) throws IOException { + writer.writeVarBytes(invokeCode); + } +} diff --git a/src/main/java/com/github/DNAProject/core/payload/Vote.java b/src/main/java/com/github/DNAProject/core/payload/Vote.java new file mode 100644 index 0000000..2f6b666 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/payload/Vote.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core.payload; + +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.core.transaction.TransactionType; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.crypto.ECC; +import com.github.DNAProject.io.BinaryReader; +import org.bouncycastle.math.ec.ECPoint; + +import java.io.IOException; +import java.math.BigInteger; + +/** + * + */ +public class Vote extends Transaction { + public ECPoint[] pubKeys; + public Address account; + + public Vote() { + super(TransactionType.Vote); + } + + @Override + protected void deserializeExclusiveData(BinaryReader reader) throws IOException { + try { + int len = reader.readInt(); + pubKeys = new ECPoint[len]; + for (int i = 0; i < len; i++) { + pubKeys[i] = ECC.secp256r1.getCurve().createPoint( + new BigInteger(1, reader.readVarBytes()), new BigInteger(1, reader.readVarBytes())); + } + account = reader.readSerializable(Address.class); + } catch (Exception e) { + } + } + + @Override + public Address[] getAddressU160ForVerifying() { + return null; + } + + @Override + protected void serializeExclusiveData(BinaryWriter writer) throws IOException { + writer.writeInt(pubKeys.length); + for (ECPoint pubkey : pubKeys) { + writer.writeVarBytes(Helper.removePrevZero(pubkey.getXCoord().toBigInteger().toByteArray())); + writer.writeVarBytes(Helper.removePrevZero(pubkey.getYCoord().toBigInteger().toByteArray())); + } + writer.writeSerializable(account); + } +} diff --git a/src/main/java/com/github/DNAProject/core/program/Program.java b/src/main/java/com/github/DNAProject/core/program/Program.java new file mode 100644 index 0000000..a666322 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/program/Program.java @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core.program; + +import com.github.DNAProject.common.Common; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.scripts.ScriptBuilder; +import com.github.DNAProject.core.scripts.ScriptOp; +import com.github.DNAProject.crypto.ECC; +import com.github.DNAProject.crypto.KeyType; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.sdk.exception.SDKException; +import org.bouncycastle.math.ec.ECPoint; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * + */ +public class Program { + public static byte[] ProgramFromParams(byte[][] sigData) throws IOException { + ScriptBuilder sb = new ScriptBuilder(); + sigData = Arrays.stream(sigData).sorted((o1, o2) -> { + return Helper.toHexString(o1).compareTo(Helper.toHexString(o2)); + }).toArray(byte[][]::new); + for (byte[] sig : sigData) { + sb.emitPushByteArray(sig); + } + return sb.toArray(); + } + public static byte[] ProgramFromPubKey(byte[] publicKey) throws Exception { + ScriptBuilder sb = new ScriptBuilder(); + sb.emitPushByteArray(publicKey); + sb.add(ScriptOp.OP_CHECKSIG); + return sb.toArray(); + } + public static byte[] ProgramFromMultiPubKey(int m, byte[]... publicKeys) throws Exception { + int n = publicKeys.length; + + if (m <= 0 || m > n || n > Common.MULTI_SIG_MAX_PUBKEY_SIZE) { + throw new SDKException(ErrorCode.ParamError); + } + try (ScriptBuilder sb = new ScriptBuilder()) { + sb.emitPushInteger(BigInteger.valueOf(m)); + publicKeys = sortPublicKeys(publicKeys); + for (byte[] publicKey : publicKeys) { + sb.emitPushByteArray(publicKey); + } + sb.emitPushInteger(BigInteger.valueOf(publicKeys.length)); + sb.add(ScriptOp.OP_CHECKMULTISIG); + return sb.toArray(); + } + } + public static byte[][] sortPublicKeys(byte[]... publicKeys){ + publicKeys = Arrays.stream(publicKeys).sorted((o1, o2) -> { + if (KeyType.fromPubkey(o1).getLabel() != KeyType.fromPubkey(o2).getLabel()) { + return KeyType.fromPubkey(o1).getLabel() >= KeyType.fromPubkey(o2).getLabel() ? 1 : -1; + } + switch (KeyType.fromPubkey(o1)) { + case SM2: + byte[] p = new byte[33]; + System.arraycopy(o1, 2, p, 0, p.length); + o1 = p; + byte[] p2 = new byte[33]; + System.arraycopy(o2, 2, p2, 0, p2.length); + o2 = p2; + ECPoint smPk1 = ECC.sm2p256v1.getCurve().decodePoint(o1); + ECPoint smPk2 = ECC.sm2p256v1.getCurve().decodePoint(o2); + return ECC.compare(smPk1, smPk2); + case ECDSA: + ECPoint pk1 = ECC.secp256r1.getCurve().decodePoint(o1); + ECPoint pk2 = ECC.secp256r1.getCurve().decodePoint(o2); + return ECC.compare(pk1, pk2); + case EDDSA: + //TODO + return Helper.toHexString(o1).compareTo(Helper.toHexString(o1)); + default: + return Helper.toHexString(o1).compareTo(Helper.toHexString(o1)); + } + }).toArray(byte[][]::new); + return publicKeys; + } + public static byte[][] getParamInfo(byte[] program) { + ByteArrayInputStream bais = new ByteArrayInputStream(program); + BinaryReader br = new BinaryReader(bais); + List list = new ArrayList(); + while(true){ + try { + list.add(readBytes(br)); + } catch (IOException e) { + break; + } + } + byte[][] res = new byte[list.size()][]; + for(int i=0;i < list.size(); i++){ + res[i] = list.get(i); + } + return res; + } + + public static byte[] readBytes(BinaryReader br) throws IOException { + + byte code = br.readByte(); + long keyLen; + if(code == ScriptOp.OP_PUSHDATA4.getByte()){ + int temp; + temp = br.readInt(); + keyLen = Long.valueOf(temp); + } else if(code == ScriptOp.OP_PUSHDATA2.getByte()){ + int temp; + temp = br.readShort(); + keyLen = Long.valueOf(temp); + }else if(code == ScriptOp.OP_PUSHDATA1.getByte()) { + int temp; + temp = br.readByte(); + keyLen = Long.valueOf(temp&0xFF); + }else if(code <= ScriptOp.OP_PUSHBYTES75.getByte() && code >= ScriptOp.OP_PUSHBYTES1.getByte()){ + keyLen = Long.valueOf(code) - Long.valueOf(ScriptOp.OP_PUSHBYTES1.getByte()) + 1; + }else{ + keyLen = 0; + } + byte[] res = br.readBytes((int) keyLen); + return res; + } + + public static ProgramInfo getProgramInfo(byte[] program) throws IOException { + ProgramInfo info = new ProgramInfo(); + if(program.length <= 2) { + + } + byte end = program[program.length - 1]; + byte[] temp = new byte[program.length - 1]; + System.arraycopy(program,0,temp,0,program.length - 1); + ByteArrayInputStream bais = new ByteArrayInputStream(temp); + BinaryReader reader = new BinaryReader(bais); + if(end == ScriptOp.OP_CHECKSIG.getByte()){ + try { + byte[] publicKey = readBytes(reader); + info.setPublicKey(new byte[][]{publicKey}); + info.setM((short)1); + } catch (IOException e) { + e.printStackTrace(); + } + }else if(end == ScriptOp.OP_CHECKMULTISIG.getByte()) { + short m = 0; + int len = program[program.length - 2] - ScriptOp.OP_PUSH1.getByte() +1; + try { + m = (byte)(reader.readByte() - ScriptOp.OP_PUSH1.getByte()+1); + } catch (Exception e) { + e.printStackTrace(); + } + byte[][] pub = new byte[len][]; + for(int i =0; i<(int)len; i++){ + pub[i] = reader.readVarBytes(); + } + info.setPublicKey(pub); + info.setM(m); + } + return info; + } + + public static short readNum(BinaryReader reader) throws IOException, SDKException { + ScriptOp code = readOpCode(reader); + if(code == ScriptOp.OP_PUSH0){ + readOpCode(reader); + return 0; + }else { + int num = (int)code.getByte() - (int)ScriptOp.OP_PUSH1.getByte() + 1; + if(num >= 1 && num <= 16) { + readOpCode(reader); + return (short)num; + } + } + byte[] buff = readBytes(reader); + BigInteger bint = Helper.BigIntFromNeoBytes(buff); + long num = bint.longValue(); + if(num > Short.MAX_VALUE || num < 16){ + throw new SDKException(ErrorCode.ParamErr("num is wrong")); + } + return (short)num; + } + public static ScriptOp readOpCode(BinaryReader reader) throws IOException { + return ScriptOp.valueOf(reader.readByte()); + } + + public static byte[] programFromParams(byte[][] sigs) { + ScriptBuilder builder = new ScriptBuilder(); + for(byte[] sigdata : sigs){ + builder.emitPushByteArray(sigdata); + } + return builder.toArray(); + } + public static byte[] programFromPubKey(byte[] publicKey) { + ScriptBuilder builder = new ScriptBuilder(); + builder.emitPushByteArray(publicKey); + builder.emit(ScriptOp.OP_CHECKSIG); + return builder.toArray(); + } + + public static byte[] programFromMultiPubKey(byte[][] publicKey,short m) throws SDKException { + int n = publicKey.length; + if (m >= 1 && m <= n && n <= 1024) { + throw new SDKException(ErrorCode.ParamErr("m is wrong")); + } + ScriptBuilder builder = new ScriptBuilder(); + builder.pushNum(m); + builder.add(ScriptOp.OP_CHECKSIG); + return builder.toArray(); + } +} + diff --git a/src/main/java/com/github/DNAProject/core/program/ProgramInfo.java b/src/main/java/com/github/DNAProject/core/program/ProgramInfo.java new file mode 100644 index 0000000..c3f0a72 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/program/ProgramInfo.java @@ -0,0 +1,26 @@ +package com.github.DNAProject.core.program; + +public class ProgramInfo { + public byte[][] publicKey; + public short m; + public ProgramInfo(){} + public ProgramInfo(byte[][] publicKey,short m){ + this.publicKey = publicKey; + this.m = m; + } + + public byte[][] getPublicKey() { + return publicKey; + } + + public void setPublicKey(byte[][] publicKey) { + this.publicKey = publicKey; + } + + public void setM(short m) { + this.m = m; + } + public short getM() { + return m; + } +} diff --git a/src/main/java/com/github/DNAProject/core/scripts/ScriptBuilder.java b/src/main/java/com/github/DNAProject/core/scripts/ScriptBuilder.java new file mode 100644 index 0000000..c841787 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/scripts/ScriptBuilder.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core.scripts; + +import java.io.*; +import java.math.BigInteger; +import java.nio.*; + +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.common.UIntBase; + +/** + */ +public class ScriptBuilder implements AutoCloseable { + private ByteArrayOutputStream ms = new ByteArrayOutputStream(); + + public ScriptBuilder add(ScriptOp op) { + return add(op.getByte()); + } + + public ScriptBuilder add(byte op) { + ms.write(op); + return this; + } + + public ScriptBuilder add(byte[] script) { + ms.write(script, 0, script.length); + return this; + } + + @Override + public void close() { + try { + ms.close(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + + public ScriptBuilder emitPushBool(boolean b) { + if (b == true) { + return add(ScriptOp.OP_PUSH1); + } + return add(ScriptOp.OP_PUSH0); + } + + public ScriptBuilder emitPushInteger(BigInteger number) { + if (number.equals(BigInteger.ONE.negate())) { + return add(ScriptOp.OP_PUSHM1); + } + if (number.equals(BigInteger.ZERO)) { + return add(ScriptOp.OP_PUSH0); + } + if (number.compareTo(BigInteger.ZERO) > 0 && number.compareTo(BigInteger.valueOf(16)) <= 0) { + return add((byte) (ScriptOp.OP_PUSH1.getByte() - 1 + number.byteValue())); + } +// if (number.longValue() < 0 || number.longValue() >= Long.MAX_VALUE) { +// throw new IllegalArgumentException(); +// } +// ByteBuffer byteBuffer = ByteBuffer.allocate(Long.BYTES).order(ByteOrder.LITTLE_ENDIAN); +// byteBuffer.putLong(number.longValue()); + byte[] bytes = Helper.BigIntToNeoBytes(number); + return emitPushByteArray(bytes); + } + + public ScriptBuilder pushNum(short num) { + if(num == 0) { + return add(ScriptOp.OP_PUSH0); + }else if(num < 16){ + return add(ScriptOp.valueOf(num - 1 + ScriptOp.OP_PUSH1.getByte())); + } + BigInteger bint = BigInteger.valueOf(num); + return emitPushByteArray(Helper.BigIntToNeoBytes(bint)); + } + + + public ScriptBuilder emitPushByteArray(byte[] data) { + if (data == null) { + throw new NullPointerException(); + } + if (data.length <= (int) ScriptOp.OP_PUSHBYTES75.getByte()) { + ms.write((byte) data.length); + ms.write(data, 0, data.length); + } else if (data.length < 0x100) { + add(ScriptOp.OP_PUSHDATA1); + ms.write((byte) data.length); + ms.write(data, 0, data.length); + } else if (data.length < 0x10000) { + add(ScriptOp.OP_PUSHDATA2); + ms.write(ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN).putShort((short) data.length).array(), 0, 2); + ms.write(data, 0, data.length); + } else if (data.length < 0x100000000L) { + add(ScriptOp.OP_PUSHDATA4); + ms.write(ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN).putInt(data.length).array(), 0, 4); + ms.write(data, 0, data.length); + } else { + throw new IllegalArgumentException(); + } + return this; + } + public ScriptBuilder emit(ScriptOp op) { + return add(op.getByte()); + } + public ScriptBuilder push(UIntBase hash) { + return emitPushByteArray(hash.toArray()); + } + + public ScriptBuilder pushPack() { + return add(ScriptOp.OP_PACK); + } + + public byte[] toArray() { + return ms.toByteArray(); + } +} diff --git a/src/main/java/DNA/Core/Scripts/ScriptOp.java b/src/main/java/com/github/DNAProject/core/scripts/ScriptOp.java similarity index 65% rename from src/main/java/DNA/Core/Scripts/ScriptOp.java rename to src/main/java/com/github/DNAProject/core/scripts/ScriptOp.java index 6ae0fb1..a312428 100644 --- a/src/main/java/DNA/Core/Scripts/ScriptOp.java +++ b/src/main/java/com/github/DNAProject/core/scripts/ScriptOp.java @@ -1,33 +1,52 @@ -package DNA.Core.Scripts; +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core.scripts; public enum ScriptOp { // Constants - OP_0(0x00), // An empty array of bytes is pushed onto the stack. (This is not a no-op: an item is added to the stack.) - OP_FALSE(OP_0), + OP_PUSH0(0x00), // An empty array of bytes is pushed onto the stack. (This is not a no-op: an item is added to the stack.) + OP_PUSHF(OP_PUSH0), OP_PUSHBYTES1(0x01), // 0x01-0x4B The next opcode bytes is data to be pushed onto the stack OP_PUSHBYTES75(0x4B), OP_PUSHDATA1(0x4C), // The next byte contains the number of bytes to be pushed onto the stack. OP_PUSHDATA2(0x4D), // The next two bytes contain the number of bytes to be pushed onto the stack. OP_PUSHDATA4(0x4E), // The next four bytes contain the number of bytes to be pushed onto the stack. - OP_1NEGATE(0x4F), // The number -1 is pushed onto the stack. + OP_PUSHM1(0x4F), // The number -1 is pushed onto the stack. //OP_RESERVED(0x50), // Transaction is invalid unless occuring in an unexecuted OP_IF branch - OP_1(0x51), // The number 1 is pushed onto the stack. - OP_TRUE(OP_1), - OP_2(0x52), // The number 2 is pushed onto the stack. - OP_3(0x53), // The number 3 is pushed onto the stack. - OP_4(0x54), // The number 4 is pushed onto the stack. - OP_5(0x55), // The number 5 is pushed onto the stack. - OP_6(0x56), // The number 6 is pushed onto the stack. - OP_7(0x57), // The number 7 is pushed onto the stack. - OP_8(0x58), // The number 8 is pushed onto the stack. - OP_9(0x59), // The number 9 is pushed onto the stack. - OP_10(0x5A), // The number 10 is pushed onto the stack. - OP_11(0x5B), // The number 11 is pushed onto the stack. - OP_12(0x5C), // The number 12 is pushed onto the stack. - OP_13(0x5D), // The number 13 is pushed onto the stack. - OP_14(0x5E), // The number 14 is pushed onto the stack. - OP_15(0x5F), // The number 15 is pushed onto the stack. - OP_16(0x60), // The number 16 is pushed onto the stack. + OP_PUSH1(0x51), // The number 1 is pushed onto the stack. + OP_PUSHT(OP_PUSH1), + OP_PUSH2(0x52), // The number 2 is pushed onto the stack. + OP_PUSH3(0x53), // The number 3 is pushed onto the stack. + OP_PUSH4(0x54), // The number 4 is pushed onto the stack. + OP_PUSH5(0x55), // The number 5 is pushed onto the stack. + OP_PUSH6(0x56), // The number 6 is pushed onto the stack. + OP_PUSH7(0x57), // The number 7 is pushed onto the stack. + OP_PUSH8(0x58), // The number 8 is pushed onto the stack. + OP_PUSH9(0x59), // The number 9 is pushed onto the stack. + OP_PUSH10(0x5A), // The number 10 is pushed onto the stack. + OP_PUSH11(0x5B), // The number 11 is pushed onto the stack. + OP_PUSH12(0x5C), // The number 12 is pushed onto the stack. + OP_PUSH13(0x5D), // The number 13 is pushed onto the stack. + OP_PUSH14(0x5E), // The number 14 is pushed onto the stack. + OP_PUSH15(0x5F), // The number 15 is pushed onto the stack. + OP_PUSH16(0x60), // The number 16 is pushed onto the stack. // Flow control @@ -40,19 +59,19 @@ public enum ScriptOp { OP_APPCALL(0x67), OP_SYSCALL(0x68), OP_VERIFY(0x69), // Marks transaction as invalid if top stack value is not true. True is removed, but false is not. - OP_HALT(0x6A), // Marks transaction as invalid. + OP_DUPFROMALTSTACK(0x6A), // Marks transaction as invalid. // Stack OP_TOALTSTACK(0x6B), // Puts the input onto the top of the alt stack. Removes it from the main stack. OP_FROMALTSTACK(0x6C), // Puts the input onto the top of the main stack. Removes it from the alt stack. - OP_2DROP(0x6D), // Removes the top two stack items. + OP_XDROP(0x6D), // Removes the top two stack items. OP_2DUP(0x6E), // Duplicates the top two stack items. OP_3DUP(0x6F), // Duplicates the top three stack items. OP_2OVER(0x70), // Copies the pair of items two spaces back in the stack to the front. OP_2ROT(0x71), // The fifth and sixth items back are moved to the top of the stack. - OP_2SWAP(0x72), // Swaps the top two pairs of items. - OP_IFDUP(0x73), // If the top stack value is not 0, duplicate it. + OP_XSWAP(0x72), // Swaps the top two pairs of items. + OP_XTUCK(0x73), // If the top stack value is not 0, duplicate it. OP_DEPTH(0x74), // Puts the number of stack items onto the stack. OP_DROP(0x75), // Removes the top stack item. OP_DUP(0x76), // Duplicates the top stack item. @@ -85,30 +104,30 @@ public enum ScriptOp { // Arithmetic // Note: Arithmetic inputs are limited to signed 32-bit integers, but may overflow their output. - OP_1ADD(0x8B), // 1 is added to the input. - OP_1SUB(0x8C), // 1 is subtracted from the input. - OP_2MUL(0x8D), // The input is multiplied by 2. - OP_2DIV(0x8E), // The input is divided by 2. + OP_INC(0x8B), // 1 is added to the input. + OP_DEC(0x8C), // 1 is subtracted from the input. + OP_SIGN(0x8D), // The input is multiplied by 2. + //OP_2DIV(0x8E), // The input is divided by 2. OP_NEGATE(0x8F), // The sign of the input is flipped. OP_ABS(0x90), // The input is made positive. OP_NOT(0x91), // If the input is 0 or 1, it is flipped. Otherwise the output will be 0. - OP_0NOTEQUAL(0x92), // Returns 0 if the input is 0. 1 otherwise. + OP_NZ(0x92), // Returns 0 if the input is 0. 1 otherwise. OP_ADD(0x93), // a is added to b. OP_SUB(0x94), // b is subtracted from a. OP_MUL(0x95), // a is multiplied by b. OP_DIV(0x96), // a is divided by b. OP_MOD(0x97), // Returns the remainder after dividing a by b. - OP_LSHIFT(0x98), // Shifts a left b bits, preserving sign. - OP_RSHIFT(0x99), // Shifts a right b bits, preserving sign. + OP_SHL(0x98), // Shifts a left b bits, preserving sign. + OP_SHR(0x99), // Shifts a right b bits, preserving sign. OP_BOOLAND(0x9A), // If both a and b are not 0, the output is 1. Otherwise 0. OP_BOOLOR(0x9B), // If a or b is not 0, the output is 1. Otherwise 0. OP_NUMEQUAL(0x9C), // Returns 1 if the numbers are equal, 0 otherwise. //OP_NUMEQUALVERIFY(0x9D), // Same as OP_NUMEQUAL, but runs OP_VERIFY afterward. OP_NUMNOTEQUAL(0x9E), // Returns 1 if the numbers are not equal, 0 otherwise. - OP_LESSTHAN(0x9F), // Returns 1 if a is less than b, 0 otherwise. - OP_GREATERTHAN(0xA0), // Returns 1 if a is greater than b, 0 otherwise. - OP_LESSTHANOREQUAL(0xA1), // Returns 1 if a is less than or equal to b, 0 otherwise. - OP_GREATERTHANOREQUAL(0xA2), // Returns 1 if a is greater than or equal to b, 0 otherwise. + OP_LT(0x9F), // Returns 1 if a is less than b, 0 otherwise. + OP_GT(0xA0), // Returns 1 if a is greater than b, 0 otherwise. + OP_LTE(0xA1), // Returns 1 if a is less than or equal to b, 0 otherwise. + OP_GTE(0xA2), // Returns 1 if a is greater than or equal to b, 0 otherwise. OP_MIN(0xA3), // Returns the smaller of a and b. OP_MAX(0xA4), // Returns the larger of a and b. OP_WITHIN(0xA5), // Returns 1 if x is within the specified range (left-inclusive), 0 otherwise. @@ -131,22 +150,25 @@ public enum ScriptOp { OP_ARRAYSIZE(0xC0), OP_PACK(0xC1), OP_UNPACK(0xC2), - OP_DISTINCT(0xC3), - OP_SORT(0xC4), - OP_REVERSE(0xC5), - OP_CONCAT(0xC6), - OP_UNION(0xC7), - OP_INTERSECT(0xC8), - OP_EXCEPT(0xC9), - OP_TAKE(0xCA), - OP_SKIP(0xCB), - OP_PICKITEM(0xCC), - OP_ALL(0xCD), + OP_PICKITEM(0xC3), + OP_SETITEM(0xC4), + OP_NEWARRAY(0xC5), + OP_NEWSTRUCT(0xC6), + OP_NEWMAP(0xC7), + OP_APPEND(0xC8), + OP_REVERSE(0xC9), + OP_REMOVE(0xCA), + OP_HASKEY(0xCB), + OP_KEYS(0xCC), + OP_VALUES(0xCD), OP_ANY(0xCE), OP_SUM(0xCF), OP_AVERAGE(0xD0), OP_MAXITEM(0xD1), OP_MINITEM(0xD2), + + OP_THROW(0xF0), + OP_THROWIFNOT(0xF1), ; private byte value; diff --git a/src/main/java/com/github/DNAProject/core/scripts/WasmScriptBuilder.java b/src/main/java/com/github/DNAProject/core/scripts/WasmScriptBuilder.java new file mode 100644 index 0000000..3aa4591 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/scripts/WasmScriptBuilder.java @@ -0,0 +1,186 @@ +package com.github.DNAProject.core.scripts; + +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.sdk.exception.SDKRuntimeException; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Arrays; +import java.util.List; + +public class WasmScriptBuilder implements AutoCloseable{ + + private ByteArrayOutputStream ms; + + private static BigInteger maxInt128 = new BigInteger("2").pow(127).subtract(BigInteger.ONE); + + private static BigInteger minInt128 = new BigInteger("2").pow(127).negate(); + + WasmScriptBuilder() { + this.ms = new ByteArrayOutputStream(); + } + + @Override + public void close() { + try { + ms.close(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + } + + void reset() { + ms.reset(); + } + + public static byte[] createWasmInvokeCode(String contractHash, String method, List params) { + try { + WasmScriptBuilder headBuilder = new WasmScriptBuilder(); + headBuilder.pushWithoutLen(Helper.reverse(Helper.hexToBytes(contractHash))); + return Helper.addBytes(headBuilder.toByteArray(), createWasmCodeParamsScript(method, params)); + } catch (Exception e) { + e.printStackTrace(); + throw new SDKRuntimeException("Create wasm invoke code failed"); + } + } + + private static byte[] createWasmCodeParamsScript(String method, List list) { + WasmScriptBuilder builder = new WasmScriptBuilder(); + builder.push(method); + list.forEach(builder::pushVmParam); + return builder.packAsArray(); + } + + private void pushVmParam(Object val) { + if (val instanceof byte[]) { + push((byte[]) val); + } else if (val instanceof Address) { + push(((Address) val)); + } else if (val instanceof String) { + push((String) val); + } else if (val instanceof Boolean) { + push((Boolean) val); + } else if (val instanceof Integer) { + push((Integer) val); + } else if (val instanceof Long) { + push((Long) val); + } else if (val instanceof List) { + List listVal = (List) val; + pushVarUInt((long) listVal.size()); + for (Object param : listVal) { + pushVmParam(param); + } + } else { + throw new SDKRuntimeException("Invalid data"); + } + } + + public byte[] toByteArray() { + return ms.toByteArray(); + } + + public String toHexString() { + return Helper.toHexString(toByteArray()); + } + + private byte[] packAsArray() { + WasmScriptBuilder finalBuilder = new WasmScriptBuilder(); + finalBuilder.push( this.toByteArray()); + return finalBuilder.toByteArray(); + } + + void push(Boolean val) { + if (val) { + ms.write(0x01); + } else { + ms.write(0x00); + } + } + + void pushWithoutLen(byte[] data) { + if (data == null) { + throw new NullPointerException(); + } + ms.write(data, 0, data.length); + } + + void push(byte[] data) { + if (data == null) { + throw new NullPointerException(); + } + pushVarUInt((long) data.length); + ms.write(data, 0, data.length); + } + + void push(Address val) { + byte[] byteVal = val.toArray(); + ms.write(byteVal, 0, byteVal.length); + } + + void push(String data) { + if (data == null) { + throw new NullPointerException(); + } + push(data.getBytes()); + } + + void push(Integer data) { + if (data == null) { + throw new SDKRuntimeException("NULL Pointer exception"); + } + push(BigInteger.valueOf(data)); + } + + void push(Long data) { + if (data == null) { + throw new SDKRuntimeException("NULL Pointer exception"); + } + push(BigInteger.valueOf(data)); + } + + void push(BigInteger data) { + if (data == null) { + throw new SDKRuntimeException("NULL Pointer exception"); + } + if (data.compareTo(minInt128) < 0 || data.compareTo(maxInt128) > 0) { + throw new SDKRuntimeException("Out of range"); + } + byte[] bytesData = Helper.reverse(data.toByteArray()); + int int128Length = 16; + if (bytesData.length > int128Length) { + throw new SDKRuntimeException("Data in bytes should be less equal then 16"); + } + byte[] finalResult = new byte[int128Length]; + if (data.compareTo(BigInteger.ZERO) < 0) { + Arrays.fill(finalResult, (byte) 0xFF); + } + System.arraycopy(bytesData, 0, finalResult, 0, bytesData.length); + ms.write(finalResult, 0, finalResult.length); + } + + void pushVarUInt(Long data) { + if (data == null) { + throw new NullPointerException(); + } + if (data < 0) { + throw new RuntimeException(); + } else if (data < 0XFD) { + byte[] bytes = ByteBuffer.allocate(Long.BYTES).order(ByteOrder.LITTLE_ENDIAN).putLong(data).array(); + ms.write(bytes, 0, 1); + } else if (data <= 0xFFFF) { + byte[] bytes = Helper.addBytes(new byte[]{(byte) 0xFD}, ByteBuffer.allocate(Long.BYTES).order(ByteOrder.LITTLE_ENDIAN).putLong(data).array()); + ms.write(bytes, 0, 3); + } else if (data <= 0xFFFFFFFFL) { + byte[] bytes = Helper.addBytes(new byte[]{(byte) 0xFE}, ByteBuffer.allocate(Long.BYTES).order(ByteOrder.LITTLE_ENDIAN).putLong(data).array()); + ms.write(bytes, 0, 5); + } else { + byte[] bytes = Helper.addBytes(new byte[]{(byte) 0xFF}, ByteBuffer.allocate(Long.BYTES).order(ByteOrder.LITTLE_ENDIAN).putLong(data).array()); + ms.write(bytes, 0, 9); + } + } + +} diff --git a/src/main/java/com/github/DNAProject/core/sidechaingovernance/InflationParam.java b/src/main/java/com/github/DNAProject/core/sidechaingovernance/InflationParam.java new file mode 100644 index 0000000..25eef28 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/sidechaingovernance/InflationParam.java @@ -0,0 +1,17 @@ +package com.github.DNAProject.core.sidechaingovernance; + + +import com.github.DNAProject.common.Address; + +public class InflationParam { + public String sideChainId; + public Address address; + public long depositAdd; + public long ongPoolAdd; + public InflationParam(String sideChainId, Address address, long depositAdd, long ongPoolAdd){ + this.sideChainId = sideChainId; + this.address = address; + this.depositAdd = depositAdd; + this.ongPoolAdd = ongPoolAdd; + } +} diff --git a/src/main/java/com/github/DNAProject/core/sidechaingovernance/NodeToSideChainParams.java b/src/main/java/com/github/DNAProject/core/sidechaingovernance/NodeToSideChainParams.java new file mode 100644 index 0000000..86c0aef --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/sidechaingovernance/NodeToSideChainParams.java @@ -0,0 +1,33 @@ +package com.github.DNAProject.core.sidechaingovernance; + +import com.github.DNAProject.common.Address; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; +import com.github.DNAProject.io.utils; + +import java.io.IOException; + +public class NodeToSideChainParams implements Serializable { + public String peerPubkey; + public Address address; + public String sideChainId; + public NodeToSideChainParams(){} + public NodeToSideChainParams(String peerPubkey, Address address, String sideChainId){ + this.peerPubkey = peerPubkey; + this.address = address; + this.sideChainId = sideChainId; + } + + @Override + public void deserialize(BinaryReader reader) throws IOException { + this.peerPubkey = reader.readVarString(); + this.address = utils.readAddress(reader); + this.sideChainId = reader.readVarString(); + } + + @Override + public void serialize(BinaryWriter writer) throws IOException { + + } +} diff --git a/src/main/java/com/github/DNAProject/core/sidechaingovernance/QuitSideChainParam.java b/src/main/java/com/github/DNAProject/core/sidechaingovernance/QuitSideChainParam.java new file mode 100644 index 0000000..71e1a76 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/sidechaingovernance/QuitSideChainParam.java @@ -0,0 +1,14 @@ +package com.github.DNAProject.core.sidechaingovernance; + + +import com.github.DNAProject.common.Address; + +public class QuitSideChainParam { + public String sideChainID; + public Address address; + public QuitSideChainParam(String sideChainID, Address address){ + this.sideChainID = sideChainID; + this.address = address; + } + +} diff --git a/src/main/java/com/github/DNAProject/core/sidechaingovernance/RegisterSideChainParam.java b/src/main/java/com/github/DNAProject/core/sidechaingovernance/RegisterSideChainParam.java new file mode 100644 index 0000000..ad8bc19 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/sidechaingovernance/RegisterSideChainParam.java @@ -0,0 +1,23 @@ +package com.github.DNAProject.core.sidechaingovernance; + + +import com.github.DNAProject.common.Address; + +public class RegisterSideChainParam { + public String sideChainID; + public Address address; + public int ratio; + public long deposit; + public long ongPool; + public byte[] caller; + public int keyNo; + public RegisterSideChainParam(String sideChainID, Address address, int ratio, long deposit, long ongPool, byte[] caller, int keyNo){ + this.sideChainID = sideChainID; + this.address = address; + this.ratio = ratio; + this.deposit = deposit; + this.ongPool = ongPool; + this.caller = caller; + this.keyNo = keyNo; + } +} diff --git a/src/main/java/com/github/DNAProject/core/sidechaingovernance/SideChain.java b/src/main/java/com/github/DNAProject/core/sidechaingovernance/SideChain.java new file mode 100644 index 0000000..abade5e --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/sidechaingovernance/SideChain.java @@ -0,0 +1,55 @@ +package com.github.DNAProject.core.sidechaingovernance; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class SideChain implements Serializable { + public String sideChainId; + public Address address; + public long ratio; + public long deposit; + public long ongNum; + public long ongPool; + public byte status; + + public SideChain(){} + @Override + public void deserialize(BinaryReader reader) throws IOException { + this.sideChainId = reader.readVarString(); + try { + this.address = reader.readSerializable(Address.class); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + this.ratio = reader.readLong(); + this.deposit = reader.readLong(); + this.ongNum = reader.readLong(); + this.ongPool = reader.readLong(); + this.status = reader.readByte(); + } + + @Override + public void serialize(BinaryWriter binaryWriter) throws IOException { + + } + public String toJson(){ + Map map = new HashMap<>(); + map.put("sideChainId",this.sideChainId); + map.put("address", this.address.toBase58()); + map.put("ratio", this.ratio); + map.put("deposit", this.deposit); + map.put("ongNum", this.ongNum); + map.put("ongPool", this.ongPool); + map.put("status", this.status); + return JSON.toJSONString(map); + } +} diff --git a/src/main/java/com/github/DNAProject/core/sidechaingovernance/SideChainNodeInfo.java b/src/main/java/com/github/DNAProject/core/sidechaingovernance/SideChainNodeInfo.java new file mode 100644 index 0000000..be06325 --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/sidechaingovernance/SideChainNodeInfo.java @@ -0,0 +1,36 @@ +package com.github.DNAProject.core.sidechaingovernance; + +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +public class SideChainNodeInfo implements Serializable { + public String sideChainId; + public Map nodeInfoMap; + + public SideChainNodeInfo(){ + this.nodeInfoMap = new HashMap(); + } + + @Override + public void deserialize(BinaryReader reader) throws IOException { + this.sideChainId = reader.readVarString(); + int n = reader.readInt(); + for(int i=0;i(); + map.put("sideChainId", sideChainId); + map.put("address", address.toBase58()); + map.put("ongXAccount",ongXAccount); + return JSON.toJSONString(map); + } +} diff --git a/src/main/java/com/github/DNAProject/core/transaction/Attribute.java b/src/main/java/com/github/DNAProject/core/transaction/Attribute.java new file mode 100644 index 0000000..25d315a --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/transaction/Attribute.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core.transaction; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; + + +public class Attribute implements Serializable { + + public AttributeUsage usage; + public byte[] data; + public int size; + + @Override + public void serialize(BinaryWriter writer) throws IOException { + writer.writeByte(usage.value()); + if (usage == AttributeUsage.Script + || usage == AttributeUsage.DescriptionUrl + || usage == AttributeUsage.Description + || usage == AttributeUsage.Nonce) { + writer.writeVarBytes(data); + } else { + throw new IOException(); + } + } + + @Override + public void deserialize(BinaryReader reader) throws IOException { + usage = AttributeUsage.valueOf(reader.readByte()); + if (usage == AttributeUsage.Script + || usage == AttributeUsage.DescriptionUrl + || usage == AttributeUsage.Description + || usage == AttributeUsage.Nonce) { + data = reader.readVarBytes(255); + } else { + throw new IOException(); + } + } + + public Object json() { + Map json = new HashMap<>(); + json.put("usage", usage.value()); + json.put("data", Helper.toHexString(data)); + return json; + } + + @Override + public String toString() { + return "TransactionAttribute [usage=" + usage + ", data=" + + Arrays.toString(data) + "]"; + } + +// @Override +// public void fromJson(JsonReader reader) { +// JObject json = reader.json(); +// usage = TransactionAttributeUsage.valueOf((byte)json.get("Usage").asNumber()); +// data = Helper.hexToBytes(json.get("Data").asString()); +// } +} diff --git a/src/main/java/com/github/DNAProject/core/transaction/AttributeUsage.java b/src/main/java/com/github/DNAProject/core/transaction/AttributeUsage.java new file mode 100644 index 0000000..478479c --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/transaction/AttributeUsage.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core.transaction; + + +public enum AttributeUsage { + + Nonce(0x00), + Script(0x20), + DescriptionUrl(0x81), + Description(0x90), + + ; + private byte value; + + AttributeUsage(int v) { + value = (byte)v; + } + + public byte value() { + return value; + } + + public static AttributeUsage valueOf(byte v) { + for (AttributeUsage e : AttributeUsage.values()) { + if (e.value == v) { + return e; + } + } + throw new IllegalArgumentException(); + } +} diff --git a/src/main/java/com/github/DNAProject/core/transaction/Transaction.java b/src/main/java/com/github/DNAProject/core/transaction/Transaction.java new file mode 100644 index 0000000..46dccdc --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/transaction/Transaction.java @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core.transaction; + +import java.io.*; +import java.util.*; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.common.*; +import com.github.DNAProject.core.Inventory; +import com.github.DNAProject.core.InventoryType; +import com.github.DNAProject.core.asset.Sig; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; + +/** + * + */ +public abstract class Transaction extends Inventory { + + public byte version = 0; + public TransactionType txType; + public int nonce = new Random().nextInt(); + public long gasPrice = 0; + public long gasLimit = 0; + public Address payer = new Address(); + public Attribute[] attributes; + public Sig[] sigs = new Sig[0]; + protected Transaction(TransactionType type) { + this.txType = type; + } + + public static Transaction deserializeFrom(byte[] value) throws IOException { + return deserializeFrom(value, 0); + } + + public static Transaction deserializeFrom(byte[] value, int offset) throws IOException { + try (ByteArrayInputStream ms = new ByteArrayInputStream(value, offset, value.length - offset)) { + try (BinaryReader reader = new BinaryReader(ms)) { + return deserializeFrom(reader); + } + } + } + + public static Transaction deserializeFrom(BinaryReader reader) throws IOException { + try { + byte ver = reader.readByte(); + TransactionType type = TransactionType.valueOf(reader.readByte()); + String typeName = "com.github.DNAProject.core.payload." + type.toString(); + Transaction transaction = (Transaction) Class.forName(typeName).newInstance(); + transaction.nonce = reader.readInt(); + transaction.version = ver; + transaction.gasPrice = reader.readLong(); + transaction.gasLimit = reader.readLong(); + transaction.payer = reader.readSerializable(Address.class); + transaction.deserializeUnsignedWithoutType(reader); + transaction.sigs = new Sig[(int) reader.readVarInt()]; + for (int i = 0; i < transaction.sigs.length; i++) { + transaction.sigs[i] = reader.readSerializable(Sig.class); + } + return transaction; + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) { + throw new IOException(ex); + } + } + @Override + public void deserialize(BinaryReader reader) throws IOException { + deserializeUnsigned(reader); + try { + sigs = reader.readSerializableArray(Sig.class); + } catch (InstantiationException | IllegalAccessException ex) { + throw new RuntimeException(ex); + } + } + + @Override + public void deserializeUnsigned(BinaryReader reader) throws IOException { + txType = TransactionType.valueOf(reader.readByte()); + nonce = reader.readInt(); + version = reader.readByte(); + gasPrice = reader.readLong(); + gasLimit = reader.readLong(); + try { + payer = reader.readSerializable(Address.class); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + deserializeUnsignedWithoutType(reader); + } + + private void deserializeUnsignedWithoutType(BinaryReader reader) throws IOException { + try { + deserializeExclusiveData(reader); + attributes = reader.readSerializableArray(Attribute.class); + } catch (InstantiationException | IllegalAccessException ex) { + throw new IOException(ex); + } + } + + protected void deserializeExclusiveData(BinaryReader reader) throws IOException { + } + + @Override + public void serialize(BinaryWriter writer) throws IOException { + serializeUnsigned(writer); + writer.writeSerializableArray(sigs); + } + + @Override + public void serializeUnsigned(BinaryWriter writer) throws IOException { + writer.writeByte(version); + writer.writeByte(txType.value()); + writer.writeInt(nonce); + writer.writeLong(gasPrice); + writer.writeLong(gasLimit); + writer.writeSerializable(payer); + serializeExclusiveData(writer); + writer.writeSerializableArray(attributes); + } + + protected void serializeExclusiveData(BinaryWriter writer) throws IOException { + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj == null) { + return false; + } + if (!(obj instanceof Transaction)) { + return false; + } + Transaction tx = (Transaction) obj; + return hash().equals(tx.hash()); + } + + @Override + public int hashCode() { + return hash().hashCode(); + } + + + @Override + public Address[] getAddressU160ForVerifying() { + return null; + } + + @Override + public final InventoryType inventoryType() { + return InventoryType.TX; + } + + public Object json() { + Map json = new HashMap(); + json.put("Hash", hash().toString()); + json.put("Version", (int) version); + json.put("Nonce", nonce& 0xFFFFFFFF); + json.put("TxType", txType.value() & 0xFF); + json.put("GasPrice",gasPrice); + json.put("GasLimit",gasLimit); + json.put("Payer",payer.toBase58()); + json.put("Attributes", Arrays.stream(attributes).map(p -> p.json()).toArray(Object[]::new)); + json.put("Sigs", Arrays.stream(sigs).map(p -> p.json()).toArray(Object[]::new)); + return json; + } + + @Override + public boolean verify() { + return true; + } + +} diff --git a/src/main/java/com/github/DNAProject/core/transaction/TransactionType.java b/src/main/java/com/github/DNAProject/core/transaction/TransactionType.java new file mode 100644 index 0000000..708ff1a --- /dev/null +++ b/src/main/java/com/github/DNAProject/core/transaction/TransactionType.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.core.transaction; + +/** + * list transaction types + */ +public enum TransactionType { + Bookkeeping(0x00), + Bookkeeper(0x02), + Claim(0x03), + Enrollment(0x04), + Vote(0x05), + DeployCode(0xd0), + InvokeCode(0xd1), + InvokeWasm(0xd2), + TransferTransaction(0x80); + + private byte value; + TransactionType(int v) { + value = (byte)v; + } + public byte value() { + return value; + } + + public static TransactionType valueOf(byte v) { + for (TransactionType e : TransactionType.values()) { + if (e.value == v) { + return e; + } + } + throw new IllegalArgumentException(); + } +} diff --git a/src/main/java/DNA/Cryptography/AES.java b/src/main/java/com/github/DNAProject/crypto/AES.java similarity index 78% rename from src/main/java/DNA/Cryptography/AES.java rename to src/main/java/com/github/DNAProject/crypto/AES.java index 00e7f03..beb13fb 100644 --- a/src/main/java/DNA/Cryptography/AES.java +++ b/src/main/java/com/github/DNAProject/crypto/AES.java @@ -1,4 +1,23 @@ -package DNA.Cryptography; +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.crypto; import java.io.UnsupportedEncodingException; import java.security.*; @@ -81,8 +100,7 @@ public static byte[] generateKey(String password) { byte[] passwordBytes = null, passwordHash = null; try { passwordBytes = password.getBytes("UTF-8"); - passwordHash = Digest.sha256(passwordBytes); - return Digest.sha256(passwordHash); + return Digest.hash256(passwordBytes); } catch (UnsupportedEncodingException ex) { throw new RuntimeException(ex); } finally { diff --git a/src/main/java/com/github/DNAProject/crypto/Base58.java b/src/main/java/com/github/DNAProject/crypto/Base58.java new file mode 100644 index 0000000..76cbb07 --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/Base58.java @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.crypto; + +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.sdk.exception.SDKException; + +import java.math.BigInteger; +import java.util.Arrays; + +public class Base58 { + /** + * base58 + */ + public static final String ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + private static final BigInteger BASE = BigInteger.valueOf(ALPHABET.length()); + + /** + * decode base58 + * @param input + * @return + */ + public static byte[] decode(String input) { + BigInteger bi = BigInteger.ZERO; + for (int i = input.length() - 1; i >= 0; i--) { + int index = ALPHABET.indexOf(input.charAt(i)); + if (index == -1) { + throw new IllegalArgumentException(); + } + bi = bi.add(BASE.pow(input.length() - 1 - i).multiply(BigInteger.valueOf(index))); + } + byte[] bytes = bi.toByteArray(); + boolean stripSignByte = bytes.length > 1 && bytes[0] == 0 && bytes[1] < 0; + int leadingZeros = 0; + for (; leadingZeros < input.length() && input.charAt(leadingZeros) == ALPHABET.charAt(0); leadingZeros++){}; + byte[] tmp = new byte[bytes.length - (stripSignByte ? 1 : 0) + leadingZeros]; + System.arraycopy(bytes, stripSignByte ? 1 : 0, tmp, leadingZeros, tmp.length - leadingZeros); + return tmp; + } + + /** + * encode + * @param input + * @return + */ + public static String encode(byte[] input) { + BigInteger value = new BigInteger(1, input); + StringBuilder sb = new StringBuilder(); + while (value.compareTo(BASE) >= 0) { + BigInteger[] r = value.divideAndRemainder(BASE); + sb.insert(0, ALPHABET.charAt(r[1].intValue())); + value = r[0]; + } + sb.insert(0, ALPHABET.charAt(value.intValue())); + for (byte b : input) { + if (b == 0) { + sb.insert(0, ALPHABET.charAt(0)); + } else { + break; + } + } + return sb.toString(); + } + public static String checkSumEncode(byte[] in) { + byte[] hash = Digest.sha256(Digest.sha256(in)); + byte[] checksum = Arrays.copyOfRange(hash, 0, 4); + byte[] input = new byte[in.length+4]; + System.arraycopy(in, 0, input, 0, in.length); + System.arraycopy(checksum, 0, input, in.length, 4); + return encode(input); + } + + public static byte[] decodeChecked(String input) throws Exception { + + byte[] decoded = decode(input); + if (decoded.length < 4) { + throw new Exception(ErrorCode.InputTooShort); + } + byte[] data = Arrays.copyOfRange(decoded, 0, decoded.length - 4); + byte[] checksum = Arrays.copyOfRange(decoded, decoded.length - 4, decoded.length); + byte[] actualChecksum = Arrays.copyOfRange(Digest.sha256(Digest.sha256(data)), 0, 4); + if (!Arrays.equals(checksum, actualChecksum)) { + throw new SDKException(ErrorCode.ChecksumNotValidate); + } + return decoded; + } +} diff --git a/src/main/java/com/github/DNAProject/crypto/Curve.java b/src/main/java/com/github/DNAProject/crypto/Curve.java new file mode 100644 index 0000000..7911114 --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/Curve.java @@ -0,0 +1,51 @@ +package com.github.DNAProject.crypto; + +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.sdk.exception.SDKException; +import org.bouncycastle.jce.ECNamedCurveTable; +import org.bouncycastle.math.ec.ECCurve; + +public enum Curve { + P224(1, "P-224"), + P256(2, "P-256"), + P384(3, "P-384"), + P521(4, "P-521"), + SM2P256V1(20, "sm2p256v1"), + ED25519(25, "ED25519"); + + private int label; + private String name; + + private Curve(int v0, String v1) { + label = v0; + name = v1; + } + + public int getLabel() { + return label; + } + @Override + public String toString() { + return name; + } + + public static Curve valueOf(ECCurve v) throws Exception { + for (Curve c : Curve.values()) { + if (ECNamedCurveTable.getParameterSpec(c.toString()).getCurve().equals(v)) { + return c; + } + } + + throw new Exception(ErrorCode.UnknownCurve); + } + + public static Curve fromLabel(int v) throws Exception { + for (Curve c : Curve.values()) { + if (c.label == v) { + return c; + } + } + + throw new SDKException(ErrorCode.UnknownCurveLabel); + } +} diff --git a/src/main/java/com/github/DNAProject/crypto/Digest.java b/src/main/java/com/github/DNAProject/crypto/Digest.java new file mode 100644 index 0000000..c231b0e --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/Digest.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ +package com.github.DNAProject.crypto; + +import java.security.*; + + +import org.bouncycastle.crypto.digests.SHA512Digest; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.digests.SHA1Digest; +import org.bouncycastle.crypto.macs.HMac; +import org.bouncycastle.crypto.params.KeyParameter; + +public class Digest { + static { + Security.addProvider(new BouncyCastleProvider()); + } + + public static byte[] hash160(byte[] value) { + return ripemd160(sha256(value)); + } + + public static byte[] hash256(byte[] value) { + return sha256(sha256(value)); + } + + public static byte[] hash256(byte[] value, int offset, int length) { + if (offset != 0 || length != value.length) { + byte[] array = new byte[length]; + System.arraycopy(value, offset, array, 0, length); + value = array; + } + return sha256(sha256(value)); + } + + public static byte[] ripemd160(byte[] value) { + try { + MessageDigest md = MessageDigest.getInstance("RipeMD160"); + return md.digest(value); + } catch (NoSuchAlgorithmException ex) { + throw new RuntimeException(ex); + } + } + + public static byte[] sha256(byte[] value) { + try { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + return md.digest(value); + } catch (NoSuchAlgorithmException ex) { + throw new RuntimeException(ex); + } + } + + public static byte[] sha256(byte[] value, int offset, int length) { + if (offset != 0 || length != value.length) { + byte[] array = new byte[length]; + System.arraycopy(value, offset, array, 0, length); + value = array; + } + return sha256(value); + } + + public static byte[] hmacSha512(byte[] keyBytes, byte[] text) { + HMac hmac = new HMac(new SHA512Digest()); + byte[] resBuf = new byte[hmac.getMacSize()]; + CipherParameters pm = new KeyParameter(keyBytes); + hmac.init(pm); + hmac.update(text, 0, text.length); + hmac.doFinal(resBuf, 0); + return resBuf; + } + +} diff --git a/src/main/java/com/github/DNAProject/crypto/ECC.java b/src/main/java/com/github/DNAProject/crypto/ECC.java new file mode 100644 index 0000000..269ec41 --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/ECC.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.crypto; + +import java.security.*; + +import com.github.DNAProject.common.Helper; +import org.bouncycastle.asn1.x9.*; +import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.math.ec.ECPoint; + +public class ECC { + private static final X9ECParameters secp256r1nc = ECNamedCurveTable.getByName("secp256r1"); + public static final ECDomainParameters secp256r1 = new ECDomainParameters(secp256r1nc.getCurve(), secp256r1nc.getG(), secp256r1nc.getN(), secp256r1nc.getH(), secp256r1nc.getSeed()); + private static final X9ECParameters sm2p256v1nc = ECNamedCurveTable.getByName("sm2p256v1"); + public static final ECDomainParameters sm2p256v1 = new ECDomainParameters(sm2p256v1nc.getCurve(), sm2p256v1nc.getG(), sm2p256v1nc.getN(), sm2p256v1nc.getH(), sm2p256v1nc.getSeed()); + + public static int compare(ECPoint a, ECPoint b) { + if (a == b) { + return 0; + } + int result = a.getXCoord().toBigInteger().compareTo(b.getXCoord().toBigInteger()); + if (result != 0) { + return result; + } + return a.getYCoord().toBigInteger().compareTo(b.getYCoord().toBigInteger()); + } + + + public static String toString(ECPoint p) { + return Helper.toHexString(p.getEncoded(true)); + } + + + public static byte[] generateKey(int len) { + byte[] key = new byte[len]; + SecureRandom sr = new SecureRandom(); + sr.nextBytes(key); + return key; + } + + public static byte[] generateKey() { + return generateKey(32); + } +} diff --git a/src/main/java/com/github/DNAProject/crypto/KeyType.java b/src/main/java/com/github/DNAProject/crypto/KeyType.java new file mode 100644 index 0000000..1904952 --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/KeyType.java @@ -0,0 +1,43 @@ +package com.github.DNAProject.crypto; + +import com.github.DNAProject.common.ErrorCode; + +public enum KeyType { + ECDSA(0x12), + SM2(0x13), + EDDSA(0x14); + + + private int label; + + private KeyType(int b) { + this.label = b; + } + + + // get the crypto.KeyType according to the input label + public static KeyType fromLabel(byte label) throws Exception { + for (KeyType k : KeyType.values()) { + if (k.label == label) { + return k; + } + } + throw new Exception(ErrorCode.UnknownAsymmetricKeyType); + } + public static KeyType fromPubkey(byte[] pubkey) { + try { + if(pubkey.length == 33){ + return KeyType.ECDSA; + }else { + return KeyType.fromLabel(pubkey[0]); + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public int getLabel() { + return label; + } +} diff --git a/src/main/java/DNA/Cryptography/MerkleTree.java b/src/main/java/com/github/DNAProject/crypto/MerkleTree.java similarity index 60% rename from src/main/java/DNA/Cryptography/MerkleTree.java rename to src/main/java/com/github/DNAProject/crypto/MerkleTree.java index 33e0a58..6eaae74 100644 --- a/src/main/java/DNA/Cryptography/MerkleTree.java +++ b/src/main/java/com/github/DNAProject/crypto/MerkleTree.java @@ -1,17 +1,36 @@ -package DNA.Cryptography; +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.crypto; import java.util.Arrays; -import DNA.UInt256; +import com.github.DNAProject.common.UInt256; /** - * 哈希树 + * MerkleTree */ public class MerkleTree { /** - * 计算根节点的值 - * 子节点列表 - * 返回计算的结果 + * + * @param hashes + * @return */ public static UInt256 computeRoot(UInt256[] hashes) { if (hashes.length == 0) { diff --git a/src/main/java/com/github/DNAProject/crypto/MnemonicCode.java b/src/main/java/com/github/DNAProject/crypto/MnemonicCode.java new file mode 100644 index 0000000..cfb4533 --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/MnemonicCode.java @@ -0,0 +1,141 @@ +package com.github.DNAProject.crypto; + + +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.crypto.bip32.HdPrivateKey; +import com.github.DNAProject.crypto.bip32.Bitcoin; +import com.github.DNAProject.sdk.exception.SDKException; + +import java.nio.charset.StandardCharsets; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.Base64; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import io.github.novacrypto.bip39.MnemonicGenerator; +import io.github.novacrypto.bip39.SeedCalculator; +import io.github.novacrypto.bip39.Words; +import io.github.novacrypto.bip39.wordlists.English; +import org.bouncycastle.crypto.generators.SCrypt; + +public class MnemonicCode { + + public static String generateMnemonicCodesStr(){ + return generateMnemonicCodesStr(Words.TWELVE); + } + + public static String generateMnemonicCodesStr(Words words){ + final StringBuilder sb = new StringBuilder(); + byte[] entropy = new byte[words.byteLength()]; + new SecureRandom().nextBytes(entropy); + new MnemonicGenerator(English.INSTANCE).createMnemonic(entropy, new MnemonicGenerator.Target() { + @Override + public void append(CharSequence string) { + sb.append(string); + } + }); + new SecureRandom().nextBytes(entropy); + return sb.toString(); + } + + public static byte[] getSeedFromMnemonicCodesStr(String mnemonicCodesStr) throws SDKException { + if(mnemonicCodesStr == null || mnemonicCodesStr.equals("")){ + throw new SDKException(ErrorCode.ParamErr("mnemonicCodesStr should not be null")); + } + String[] mnemonicCodesArray = mnemonicCodesStr.split(" "); + byte[] seed = new SeedCalculator() + .withWordsFromWordList(English.INSTANCE) + .calculateSeed(Arrays.asList(mnemonicCodesArray), ""); + return seed; + } + + public static byte[] getPrikeyFromMnemonicCodesStrBip44(String mnemonicCodesStr) throws Exception{ + if(mnemonicCodesStr == null || mnemonicCodesStr.equals("")){ + throw new SDKException(ErrorCode.ParamErr("mnemonicCodesStr should not be null")); + } + byte[] seed = MnemonicCode.getSeedFromMnemonicCodesStr(mnemonicCodesStr); + HdPrivateKey key = HdPrivateKey.fromSeed(seed,"Nist256p1 seed".getBytes(StandardCharsets.UTF_8), Bitcoin.MAIN_NET); + HdPrivateKey child = key.fromPath(); + byte[] p = child.toByteArray(); + byte[] tmp = new byte[32]; + System.arraycopy(p, 46, tmp, 0, 32); + return tmp; + } + public static String encryptMnemonicCodesStr(String mnemonicCodesStr, String password, String address) throws Exception { + if(mnemonicCodesStr == null || mnemonicCodesStr.equals("") || password==null || password.equals("")||address==null||address.equals("")){ + throw new SDKException(ErrorCode.ParamError); + } + int N = 4096; + int r = 8; + int p = 8; + int dkLen = 64; + + byte[] addresshashTmp = Digest.sha256(Digest.sha256(address.getBytes())); + byte[] salt = Arrays.copyOfRange(addresshashTmp, 0, 4); + byte[] derivedkey = SCrypt.generate(password.getBytes(StandardCharsets.UTF_8), salt, N, r, p, dkLen); + password = null; + + byte[] derivedhalf2 = new byte[32]; + byte[] iv = new byte[16]; + System.arraycopy(derivedkey, 0, iv, 0, 16); + System.arraycopy(derivedkey, 32, derivedhalf2, 0, 32); + + SecretKeySpec skeySpec = new SecretKeySpec(derivedhalf2, "AES"); + Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding"); + cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(iv)); + byte[] encryptedkey = cipher.doFinal(mnemonicCodesStr.getBytes()); + mnemonicCodesStr = null; + + return new String(Base64.getEncoder().encode(encryptedkey)); + + } + + public static String decryptMnemonicCodesStr(String encryptedMnemonicCodesStr, String password,String address) throws Exception { + if (encryptedMnemonicCodesStr == null) { + throw new SDKException(ErrorCode.ParamError); + } + byte[] encryptedkey = Base64.getDecoder().decode(encryptedMnemonicCodesStr); + + int N = 4096; + int r = 8; + int p = 8; + int dkLen = 64; + + byte[] addresshashTmp = Digest.sha256(Digest.sha256(address.getBytes())); + byte[] salt = Arrays.copyOfRange(addresshashTmp, 0, 4); + + byte[] derivedkey = SCrypt.generate(password.getBytes(StandardCharsets.UTF_8), salt, N, r, p, dkLen); + password = null; + byte[] derivedhalf2 = new byte[32]; + byte[] iv = new byte[16]; + System.arraycopy(derivedkey, 0, iv, 0, 16); + System.arraycopy(derivedkey, 32, derivedhalf2, 0, 32); + + SecretKeySpec skeySpec = new SecretKeySpec(derivedhalf2, "AES"); + Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding"); + cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(iv)); + byte[] rawMns = cipher.doFinal(encryptedkey); + String mnemonicCodesStr = new String(rawMns); + byte[] rawkey = MnemonicCode.getPrikeyFromMnemonicCodesStrBip44(mnemonicCodesStr); + String addressNew = new Account(rawkey, SignatureScheme.SHA256WITHECDSA).getAddressU160().toBase58(); + byte[] addressNewHashTemp = Digest.sha256(Digest.sha256(addressNew.getBytes())); + byte[] saltNew = Arrays.copyOfRange(addressNewHashTemp, 0, 4); + if (!Arrays.equals(saltNew, salt)) { + throw new SDKException(ErrorCode.EncryptedPriKeyError); + } + return mnemonicCodesStr; + } + + + public static char[] getChars(byte[] bytes) { + char[] chars = new char[bytes.length]; + for (int i = 0; i < bytes.length; i++) { + chars[i] = (char) bytes[i]; + } + return chars; + } +} diff --git a/src/main/java/com/github/DNAProject/crypto/Signature.java b/src/main/java/com/github/DNAProject/crypto/Signature.java new file mode 100644 index 0000000..982deb4 --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/Signature.java @@ -0,0 +1,74 @@ +package com.github.DNAProject.crypto; + +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.sdk.exception.SDKException; +import org.bouncycastle.jcajce.spec.SM2ParameterSpec; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.spec.AlgorithmParameterSpec; +import java.util.Arrays; + +public class Signature { + private SignatureScheme scheme; + private AlgorithmParameterSpec param; + private byte[] value; + + public Signature(SignatureScheme scheme, AlgorithmParameterSpec param, byte[] signature) { + this.scheme = scheme; + this.param = param; + this.value = signature; + } + + // parse a serialized bytes to signature structure + public Signature(byte[] data) throws Exception { + if (data == null) { + throw new SDKException(ErrorCode.ParamError); + } + + if (data.length < 2) { + throw new Exception(ErrorCode.InvalidSignatureDataLen); + } + + this.scheme = SignatureScheme.values()[data[0]]; + if (scheme == SignatureScheme.SM3WITHSM2) { + int i = 0; + while (i < data.length && data[i] != 0){ + i++; + } + if (i >= data.length) { + throw new Exception(ErrorCode.InvalidSignatureData); + } + this.param = new SM2ParameterSpec(Arrays.copyOfRange(data, 1, i)); + this.value = Arrays.copyOfRange(data, i + 1, data.length); + } else { + this.value = Arrays.copyOfRange(data, 1, data.length); + } + } + + // serialize to byte array + public byte[] toBytes() { + ByteArrayOutputStream bs = new ByteArrayOutputStream(); + try { + bs.write((byte)scheme.ordinal()); + if (scheme == SignatureScheme.SM3WITHSM2) { + // adding the ID + bs.write(((SM2ParameterSpec)param).getID()); + // padding a 0 as the terminator + bs.write((byte)0); + } + bs.write(value); + } + catch (IOException e) { + e.printStackTrace(); + } + + return bs.toByteArray(); + } + + public SignatureScheme getScheme() { return scheme; } + + public byte[] getValue() { + return this.value; + } +} diff --git a/src/main/java/com/github/DNAProject/crypto/SignatureHandler.java b/src/main/java/com/github/DNAProject/crypto/SignatureHandler.java new file mode 100644 index 0000000..6f4080e --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/SignatureHandler.java @@ -0,0 +1,115 @@ +package com.github.DNAProject.crypto; + +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.sdk.exception.SDKException; +import org.bouncycastle.asn1.*; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.AlgorithmParameterSpec; +import java.util.Arrays; + +public class SignatureHandler { + private KeyType type; + private SignatureScheme scheme; + private java.security.Signature ctx; + + public SignatureHandler(KeyType type, SignatureScheme scheme) throws Exception { + this.type = type; + this.scheme = scheme; + + switch (this.type) { + case ECDSA: + switch (scheme) { + case SHA224WITHECDSA: + case SHA256WITHECDSA: + case SHA384WITHECDSA: + case SHA512WITHECDSA: + ctx = java.security.Signature.getInstance(scheme.toString(), "BC"); + break; + default: + throw new Exception(ErrorCode.UnsupportedSignatureScheme + scheme.toString()); + } + break; + case SM2: + if (scheme.compareTo(SignatureScheme.SM3WITHSM2) != 0) { + throw new SDKException(ErrorCode.UnsupportedSignatureScheme); + } + ctx = java.security.Signature.getInstance(scheme.toString(), "BC"); + break; + default: + throw new SDKException(ErrorCode.UnknownKeyType); + } + + } + + public byte[] generateSignature(PrivateKey priKey, byte[] msg, AlgorithmParameterSpec param) throws Exception { + if (param != null) { + ctx.setParameter(param); + } + ctx.initSign(priKey); + ctx.update(msg); + byte[] sig = ctx.sign(); + switch (type) { + case ECDSA: + case SM2: + sig = DSADERtoPlain(sig); + break; + } + + return sig; + } + + public boolean verifySignature(PublicKey pubKey, byte[] msg, byte[] sig) throws Exception { + ctx.initVerify(pubKey); + ctx.update(msg); + byte[] v; + switch (type) { + case ECDSA: + case SM2: + v = DSAPlaintoDER(sig); + break; + default: + v = sig; + break; + } + return ctx.verify(v); + } + + private byte[] DSADERtoPlain(byte[] sig) throws IOException { + ASN1Sequence seq = (ASN1Sequence) ASN1Primitive.fromByteArray(sig); + if (seq.size() != 2) { + throw new IOException(ErrorCode.MalformedSignature); + } else if (!Arrays.equals(sig, seq.getEncoded("DER"))) { + throw new IOException(ErrorCode.MalformedSignature); + } + + byte[] r = ASN1Integer.getInstance(seq.getObjectAt(0)).getValue().toByteArray(); + byte[] s = ASN1Integer.getInstance(seq.getObjectAt(1)).getValue().toByteArray(); + int ri = (r[0] == 0) ? 1 : 0; + int rl = r.length - ri; + int si = (s[0] == 0) ? 1 : 0; + int sl = s.length - si; + byte[] res; + if (rl > sl) { + res = new byte[rl * 2]; + } else { + res = new byte[sl * 2]; + } + System.arraycopy(r, ri, res, res.length/2 - rl, rl); + System.arraycopy(s, si, res, res.length-sl, sl); + return res; + } + + private byte[] DSAPlaintoDER(byte[] sig) throws IOException { + BigInteger r = new BigInteger(1, Arrays.copyOfRange(sig, 0, sig.length/2)); + BigInteger s = new BigInteger(1, Arrays.copyOfRange(sig, sig.length/2, sig.length)); + + ASN1EncodableVector var3 = new ASN1EncodableVector(); + var3.add(new ASN1Integer(r)); + var3.add(new ASN1Integer(s)); + return (new DERSequence(var3)).getEncoded("DER"); + } +} diff --git a/src/main/java/com/github/DNAProject/crypto/SignatureScheme.java b/src/main/java/com/github/DNAProject/crypto/SignatureScheme.java new file mode 100644 index 0000000..e417e05 --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/SignatureScheme.java @@ -0,0 +1,36 @@ +package com.github.DNAProject.crypto; + +import com.github.DNAProject.common.ErrorCode; + +public enum SignatureScheme { + SHA224WITHECDSA("SHA224withECDSA"), + SHA256WITHECDSA("SHA256withECDSA"), + SHA384WITHECDSA("SHA384withECDSA"), + SHA512WITHECDSA("SHA512withECDSA"), + SHA3_224WITHECDSA("SHA3-224withECDSA"), + SHA3_256WITHECDSA("SHA3-256withECDSA"), + SHA3_384WITHECDSA("SHA3-384withECDSA"), + SHA3_512WITHECDSA("SHA3-512withECDSA"), + RIPEMD160WITHECDSA("RIPEMD160withECDSA"), + + SM3WITHSM2("SM3withSM2"); + + private String name; + + private SignatureScheme(String v) { + name = v; + } + @Override + public String toString() { + return name; + } + + public static SignatureScheme fromScheme(String name) throws Exception { + for (SignatureScheme k : SignatureScheme.values()) { + if (k.name().equals(name.toUpperCase())) { + return k; + } + } + throw new Exception(ErrorCode.UnknownAsymmetricKeyType); + } +} diff --git a/src/main/java/com/github/DNAProject/crypto/bip32/Bitcoin.java b/src/main/java/com/github/DNAProject/crypto/bip32/Bitcoin.java new file mode 100644 index 0000000..38e8d66 --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/bip32/Bitcoin.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.crypto.bip32; + +public enum Bitcoin implements Network { + MAIN_NET { + @Override + public int getPrivateVersion() { + return 0x488ade4; + } + + @Override + public int getPublicVersion() { + return 0x0488b21e; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/crypto/bip32/ByteArrayReader.java b/src/main/java/com/github/DNAProject/crypto/bip32/ByteArrayReader.java new file mode 100644 index 0000000..2b118c6 --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/bip32/ByteArrayReader.java @@ -0,0 +1,58 @@ +/* + * BIP32 library, a Java implementation of BIP32 + * Copyright (C) 2017 Alan Evans, NovaCrypto + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Original source: https://github.com/NovaCrypto/BIP32 + * You can contact the authors via github issues. + */ + +package com.github.DNAProject.crypto.bip32; + +import java.util.Arrays; + +final class ByteArrayReader { + + private final byte[] bytes; + private int idx = 0; + + ByteArrayReader(final byte[] source) { + this.bytes = source; + } + + byte[] readRange(final int length) { + final byte[] range = Arrays.copyOfRange(this.bytes, idx, idx + length); + idx += length; + return range; + } + + /** + * deserialize a 32-bit unsigned integer i as a 4-byte sequence, most significant byte first. + */ + int readSer32() { + int result = read(); + result <<= 8; + result |= read(); + result <<= 8; + result |= read(); + result <<= 8; + result |= read(); + return result; + } + + int read() { + return 0xff & bytes[idx++]; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/crypto/bip32/ByteArrayWriter.java b/src/main/java/com/github/DNAProject/crypto/bip32/ByteArrayWriter.java new file mode 100644 index 0000000..fbcbb5c --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/bip32/ByteArrayWriter.java @@ -0,0 +1,69 @@ +/* + * BIP32 library, a Java implementation of BIP32 + * Copyright (C) 2017 Alan Evans, NovaCrypto + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Original source: https://github.com/NovaCrypto/BIP32 + * You can contact the authors via github issues. + */ + +package com.github.DNAProject.crypto.bip32; + +import java.util.Arrays; + +final class ByteArrayWriter { + + private final byte[] bytes; + private int idx = 0; + + ByteArrayWriter(final byte[] target) { + this.bytes = target; + } + + void concat(final byte[] bytesSource, final int length) { + System.arraycopy(bytesSource, 0, bytes, idx, length); + idx += length; + } + + void concat(final byte[] bytesSource) { + concat(bytesSource, bytesSource.length); + } + + /** + * ser32(i): serialize a 32-bit unsigned integer i as a 4-byte sequence, most significant byte first. + * + * @param i a 32-bit unsigned integer + */ + void concatSer32(final int i) { + concat((byte) (i >> 24)); + concat((byte) (i >> 16)); + concat((byte) (i >> 8)); + concat((byte) (i)); + } + + void concat(final byte b) { + bytes[idx++] = b; + } + + static byte[] tail32(final byte[] bytes64) { + final byte[] ir = new byte[bytes64.length - 32]; + System.arraycopy(bytes64, 32, ir, 0, ir.length); + return ir; + } + + static byte[] head32(final byte[] bytes64) { + return Arrays.copyOf(bytes64, 32); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/crypto/bip32/CKDpriv.java b/src/main/java/com/github/DNAProject/crypto/bip32/CKDpriv.java new file mode 100644 index 0000000..e8a7f78 --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/bip32/CKDpriv.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.crypto.bip32; + +public interface CKDpriv { + + /** + * Calculates the private key of the child at index. + * + * @param index The child index to calculate. + * @return The private key of the child. + */ + HdPrivateKey cKDpriv(final int index); +} diff --git a/src/main/java/com/github/DNAProject/crypto/bip32/CKDpub.java b/src/main/java/com/github/DNAProject/crypto/bip32/CKDpub.java new file mode 100644 index 0000000..3e5f2b3 --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/bip32/CKDpub.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.crypto.bip32; + +public interface CKDpub { + HdPublicKey cKDpub(int var1); +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/crypto/bip32/Derivation.java b/src/main/java/com/github/DNAProject/crypto/bip32/Derivation.java new file mode 100644 index 0000000..dd840cd --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/bip32/Derivation.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.crypto.bip32; + +import com.github.DNAProject.crypto.bip32.derivation.CkdFunction; + +public interface Derivation { + + /** + * Traverse the nodes from the root key node to find the node referenced by the path. + * + * @param rootKey The root of the path + * @param path The path to follow + * @param ckdFunction Allows you to follow one link + * @param The type of node we are visiting + * @return The final node found at the end of the path + */ + Key derive(final Key rootKey, final Path path, final CkdFunction ckdFunction); +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/crypto/bip32/Deserializer.java b/src/main/java/com/github/DNAProject/crypto/bip32/Deserializer.java new file mode 100644 index 0000000..42993ab --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/bip32/Deserializer.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.crypto.bip32; + +import com.github.DNAProject.sdk.exception.SDKException; + +public interface Deserializer { + + /** + * Deserializes the data into a {@link T}. + * + * @param extendedBase58Key Base58 CharSequence containing the serialized extended key. + * @return The {@link T} + */ + T deserialize(CharSequence extendedBase58Key) throws SDKException; + + /** + * Deserializes the data into a {@link T}. + * + * @param extendedKeyData Byte array containing the serialized extended key. + * @return The {@link T} + */ + T deserialize(byte[] extendedKeyData) throws SDKException; +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/crypto/bip32/HdKey.java b/src/main/java/com/github/DNAProject/crypto/bip32/HdKey.java new file mode 100644 index 0000000..4076c8d --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/bip32/HdKey.java @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.crypto.bip32; + +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.sdk.exception.SDKException; + +import java.math.BigInteger; +import java.util.Arrays; + +import static com.github.DNAProject.crypto.Digest.hash160; +import static com.github.DNAProject.crypto.bip32.Secp256r1SC.pointSerP_gMultiply; +import static io.github.novacrypto.hashing.Sha256.sha256Twice; + +public class HdKey { + + private final boolean neutered; + private final Network network; + private final byte[] chainCode; + private final byte[] key; + private final Serializer serializer; + private final int parentFingerprint; + private final int childNumber; + private final int depth; + + private HdKey(final Builder builder) { + neutered = builder.neutered; + network = builder.network; + key = builder.key; + parentFingerprint = builder.parentFingerprint; + childNumber = builder.childNumber; + chainCode = builder.chainCode; + depth = builder.depth; + serializer = new Serializer.Builder() + .network(builder.network) + .neutered(builder.neutered) + .depth(builder.depth) + .childNumber(builder.childNumber) + .fingerprint(builder.parentFingerprint) + .build(); + } + + static BigInteger parse256(final byte[] bytes) { + return new BigInteger(1, bytes); + } + + static void ser256(final byte[] target, final BigInteger integer) { + if (integer.bitLength() > target.length * 8) + throw new RuntimeException("ser256 failed, cannot fit integer in buffer"); + final byte[] modArr = integer.toByteArray(); + Arrays.fill(target, (byte) 0); + copyTail(modArr, target); + Arrays.fill(modArr, (byte) 0); + } + + private static void copyTail(final byte[] src, final byte[] dest) { + if (src.length < dest.length) { + System.arraycopy(src, 0, dest, dest.length - src.length, src.length); + } else { + System.arraycopy(src, src.length - dest.length, dest, 0, dest.length); + } + } + + byte[] serialize() { + return serializer.serialize(key, chainCode); + } + + byte[] getPoint() { + return pointSerP_gMultiply(parse256(key)); + } + + byte[] getKey() { + return key; + } + + boolean getNeutered() { + return neutered; + } + + int getParentFingerprint() { + return parentFingerprint; + } + + int calculateFingerPrint() { + final byte[] point = getPublicBuffer(); + final byte[] o = hash160(point); + return ((o[0] & 0xFF) << 24) | + ((o[1] & 0xFF) << 16) | + ((o[2] & 0xFF) << 8) | + (o[3] & 0xFF); + } + + static void confirmHdKeyChecksum(final byte[] extendedKeyData) throws SDKException { + final byte[] checkSum = checksum(extendedKeyData); + for (int i = 0; i < 4; i++) { + if (extendedKeyData[78 + i] != checkSum[i]) + throw new SDKException(ErrorCode.OtherError("Checksum error")); + } + } + + static byte[] checksum(final byte[] privateKey) { + return sha256Twice(privateKey, 0, 78); + } + + private byte[] getPublicBuffer() { + return neutered ? key : getPoint(); + } + + public int depth() { + return depth; + } + + Network getNetwork() { + return network; + } + + byte[] getChainCode() { + return chainCode; + } + + int getChildNumber() { + return childNumber; + } + + Builder toBuilder() { + return new Builder() + .neutered(neutered) + .chainCode(chainCode) + .key(key) + .depth(depth) + .childNumber(childNumber) + .parentFingerprint(parentFingerprint); + } + + static class Builder { + + private Network network; + private boolean neutered; + private byte[] chainCode; + private byte[] key; + private int depth; + private int childNumber; + private int parentFingerprint; + + Builder network(final Network network) { + this.network = network; + return this; + } + + Builder neutered(final boolean neutered) { + this.neutered = neutered; + return this; + } + + Builder key(final byte[] key) { + this.key = key; + return this; + } + + Builder chainCode(final byte[] chainCode) { + this.chainCode = chainCode; + return this; + } + + Builder depth(final int depth) { + this.depth = depth; + return this; + } + + Builder childNumber(final int childNumber) { + this.childNumber = childNumber; + return this; + } + + Builder parentFingerprint(final int parentFingerprint) { + this.parentFingerprint = parentFingerprint; + return this; + } + + HdKey build() { + return new HdKey(this); + } + + } +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/crypto/bip32/HdPrivateKey.java b/src/main/java/com/github/DNAProject/crypto/bip32/HdPrivateKey.java new file mode 100644 index 0000000..3f4909a --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/bip32/HdPrivateKey.java @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ +package com.github.DNAProject.crypto.bip32; + +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.crypto.Base58; +import com.github.DNAProject.crypto.Curve; +import com.github.DNAProject.crypto.Digest; +import com.github.DNAProject.crypto.bip32.derivation.CkdFunction; +import com.github.DNAProject.crypto.bip32.derivation.CkdFunctionDerive; +import com.github.DNAProject.crypto.bip32.derivation.Derive; +import com.github.DNAProject.crypto.bip32.derivation.Derivation; + +import com.github.DNAProject.sdk.exception.SDKException; +import io.github.novacrypto.bip39.SeedCalculator; +import io.github.novacrypto.bip39.wordlists.English; +import io.github.novacrypto.toruntime.CheckedExceptionToRuntime; +import org.bouncycastle.jce.ECNamedCurveTable; +import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; +import org.bouncycastle.math.ec.ECPoint; + +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; + +import static com.github.DNAProject.crypto.bip32.ByteArrayWriter.head32; +import static com.github.DNAProject.crypto.bip32.ByteArrayWriter.tail32; +import static com.github.DNAProject.crypto.bip32.HdKey.parse256; +import static com.github.DNAProject.crypto.bip32.HdKey.ser256; +import static com.github.DNAProject.crypto.bip32.Secp256r1SC.n; +import static com.github.DNAProject.crypto.bip32.derivation.CharSequenceDerivation.isHardened; + +import static io.github.novacrypto.toruntime.CheckedExceptionToRuntime.toRuntime; + +public class HdPrivateKey implements + Derive, + CKDpriv, + CKDpub { + + private static final byte[] BITCOIN_SEED = "Bitcoin seed".getBytes(StandardCharsets.UTF_8); + + private static final byte[] SEED_NAME = "Nist256p1 seed".getBytes(StandardCharsets.UTF_8); + + private static Deserializer deserializer() { + return HdPrivateKeyDeserializer.DEFAULT; + } + + public static Deserializer deserializer(final Network network) { + return new HdPrivateKeyDeserializer(network); + } + + private static final CkdFunction CKD_FUNCTION = HdPrivateKey::cKDpriv; + + public static HdPrivateKey masterKeyFromMnemonic(String code, String passphrase) { + byte[] seed = new SeedCalculator() + .withWordsFromWordList(English.INSTANCE) + .calculateSeed(Arrays.asList(code.split(" ")), passphrase); + return HdPrivateKey.fromSeed(seed, SEED_NAME, Bitcoin.MAIN_NET); + } + + public static HdPrivateKey masterKeyFromMnemonic(String code) { + return masterKeyFromMnemonic(code, ""); + } + + public String toHexString() { + return Helper.toHexString(hdKey.getKey()); + } + + public byte[] getPrivateKey() { + return hdKey.getKey(); + } + + public Address getAddress() throws Exception { + return getHdPublicKey().getAddress(); + } + + public HdPublicKey getHdPublicKey() throws Exception { + ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec((String) new Object[]{Curve.P256.toString()}[0]); + ECPoint Q = spec.getG().multiply(new BigInteger(1, getPrivateKey())).normalize(); + if (Q == null || Q.getAffineXCoord() == null || Q.getAffineYCoord() == null) { + throw new SDKException(ErrorCode.OtherError("normalize error")); + } + return new HdPublicKey(new HdKey.Builder() + .network(hdKey.getNetwork()) + .neutered(true) + .key(Q.getEncoded(true)) + .parentFingerprint(hdKey.getParentFingerprint()) + .depth(hdKey.depth()) + .childNumber(hdKey.getChildNumber()) + .chainCode(hdKey.getChainCode()) + .build()); + } + + private final HdKey hdKey; + + private HdPrivateKey(final Network network, final byte[] key, final byte[] chainCode) { + this(new HdKey.Builder() + .network(network) + .neutered(false) + .key(key) + .chainCode(chainCode) + .depth(0) + .childNumber(0) + .parentFingerprint(0) + .build()); + } + + public HdPrivateKey(final HdKey hdKey) { + this.hdKey = hdKey; + } + + public static HdPrivateKey fromSeed(final byte[] seed, final Network network) { + final byte[] I = Digest.hmacSha512(BITCOIN_SEED, seed); + + final byte[] Il = head32(I); + final byte[] Ir = tail32(I); + + return new HdPrivateKey(network, Il, Ir); + } + + public static HdPrivateKey fromSeed(final byte[] seed, byte[] byteKey, final Network network) { + final byte[] I = Digest.hmacSha512(byteKey, seed); + + final byte[] Il = head32(I); + final byte[] Ir = tail32(I); + + return new HdPrivateKey(network, Il, Ir); + } + + private static byte[] getBytes(final String seed) { + return toRuntime(new CheckedExceptionToRuntime.Func() { + @Override + public byte[] run() throws Exception { + return seed.getBytes(StandardCharsets.UTF_8); + } + }); + } + + public static HdPrivateKey base58Decode(String key) throws SDKException { + return HdPrivateKey.deserializer().deserialize(Base58.decode(key)); + } + + @Override + public HdPrivateKey cKDpriv(final int index) { + final byte[] data = new byte[37]; + final ByteArrayWriter writer = new ByteArrayWriter(data); + final HdKey parent = this.hdKey; + if (isHardened(index)) { + writer.concat((byte) 0); + writer.concat(parent.getKey(), 32); + } else { + writer.concat(parent.getPoint()); + } + writer.concatSer32(index); + + final byte[] I = Digest.hmacSha512(parent.getChainCode(), data); + Arrays.fill(data, (byte) 0); + + final byte[] Il = head32(I); + final byte[] Ir = tail32(I); + + final byte[] key = parent.getKey(); + final BigInteger parse256_Il = parse256(Il); + final BigInteger ki = parse256_Il.add(parse256(key)).mod(n()); + + if (parse256_Il.compareTo(n()) >= 0 || ki.equals(BigInteger.ZERO)) { + return cKDpriv(index + 1); + } + + ser256(Il, ki); + + return new HdPrivateKey(new HdKey.Builder() + .network(parent.getNetwork()) + .neutered(false) + .key(Il) + .chainCode(Ir) + .depth(parent.depth() + 1) + .childNumber(index) + .parentFingerprint(parent.calculateFingerPrint()) + .build()); + } + + @Override + public HdPublicKey cKDpub(final int index) { + return cKDpriv(index).neuter(); + } + + public HdPublicKey neuter() { + return HdPublicKey.from(hdKey); + } + + private Derive derive() { + return new CkdFunctionDerive<>(CKD_FUNCTION, this); + } + + @Override + public HdPrivateKey fromPath(final CharSequence derivationPath) { + final int length = derivationPath.length(); + if (length == 0) + throw new IllegalArgumentException("Path cannot be empty"); + if (length == 1) + return this; + if (derivationPath.charAt(0) == 'm' && depth() == 0) { + if (derivationPath.charAt(1) != '/') + throw new IllegalArgumentException("Root key must be a master key if the path start with m/"); + return derive().fromPath(derivationPath.subSequence(2, derivationPath.length())); + } + return derive().fromPath(derivationPath); + } + + public HdPrivateKey fromPath() { + return fromPath("m/44'/1024'/0'"); + } + + @Override + public HdPrivateKey fromPath(Path derivationPath, Derivation derivation) { + return derive().fromPath(derivationPath, derivation); + } + + public byte[] toByteArray() { + return hdKey.serialize(); + } + + public Network network() { + return hdKey.getNetwork(); + } + + public int depth() { + return hdKey.depth(); + } + + public int childNumber() { + return hdKey.getChildNumber(); + } + + public String base58Encode() { + return Base58.encode(toByteArray()); + } + +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/crypto/bip32/HdPrivateKeyDeserializer.java b/src/main/java/com/github/DNAProject/crypto/bip32/HdPrivateKeyDeserializer.java new file mode 100644 index 0000000..edd0acb --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/bip32/HdPrivateKeyDeserializer.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.crypto.bip32; + +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.sdk.exception.SDKException; + +import java.util.Arrays; + +import static com.github.DNAProject.crypto.bip32.HdKey.confirmHdKeyChecksum; +import static io.github.novacrypto.base58.Base58.base58Decode; + +final class HdPrivateKeyDeserializer implements Deserializer { + + static final HdPrivateKeyDeserializer DEFAULT = new HdPrivateKeyDeserializer(Bitcoin.MAIN_NET); + + private final Network network; + + HdPrivateKeyDeserializer(final Network network) { + this.network = network; + } + + @Override + public HdPrivateKey deserialize(final CharSequence extendedBase58Key) throws SDKException { + final byte[] extendedKeyData = base58Decode(extendedBase58Key); + try { + return deserialize(extendedKeyData); + } finally { + Arrays.fill(extendedKeyData, (byte) 0); + } + } + + @Override + public HdPrivateKey deserialize(final byte[] extendedKeyData) throws SDKException { + confirmHdKeyChecksum(extendedKeyData); + final ByteArrayReader reader = new ByteArrayReader(extendedKeyData); + final int version = reader.readSer32(); + if (version != Bitcoin.MAIN_NET.getPrivateVersion()) { + throw new SDKException(ErrorCode.OtherError(String.format("Can't find network that matches private version 0x%x", version))); + } + return new HdPrivateKey(new HdKey + .Builder() + .network(Bitcoin.MAIN_NET) + .depth(reader.read()) + .parentFingerprint(reader.readSer32()) + .childNumber(reader.readSer32()) + .chainCode(reader.readRange(32)) + .key(getKey(reader)) + .neutered(false) + .build() + ); + } + + private byte[] getKey(final ByteArrayReader reader) throws SDKException { + if (reader.read() != 0) { + throw new SDKException(ErrorCode.OtherError("Expected 0 padding at position 45")); + } + return reader.readRange(32); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/crypto/bip32/HdPublicKey.java b/src/main/java/com/github/DNAProject/crypto/bip32/HdPublicKey.java new file mode 100644 index 0000000..debd700 --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/bip32/HdPublicKey.java @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.crypto.bip32; + +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.crypto.Base58; +import com.github.DNAProject.crypto.Digest; +import com.github.DNAProject.crypto.bip32.derivation.CkdFunction; +import com.github.DNAProject.crypto.bip32.derivation.Derivation; +import com.github.DNAProject.crypto.bip32.derivation.CkdFunctionDerive; +import com.github.DNAProject.crypto.bip32.derivation.Derive; +import com.github.DNAProject.sdk.exception.SDKException; +import org.spongycastle.math.ec.ECPoint; + +import java.math.BigInteger; + +import static com.github.DNAProject.crypto.bip32.ByteArrayWriter.head32; +import static com.github.DNAProject.crypto.bip32.ByteArrayWriter.tail32; +import static com.github.DNAProject.crypto.bip32.HdKey.parse256; +import static com.github.DNAProject.crypto.bip32.Secp256r1SC.gMultiplyAndAddPoint; +import static com.github.DNAProject.crypto.bip32.Secp256r1SC.n; +import static com.github.DNAProject.crypto.bip32.Secp256r1SC.pointSerP; +import static com.github.DNAProject.crypto.bip32.derivation.CharSequenceDerivation.isHardened; + +public final class HdPublicKey implements + Derive, + CKDpub { + + private static Deserializer deserializer() { + return HdPublicKeyDeserializer.DEFAULT; + } + + public static Deserializer deserializer(final Network network) { + return new HdPublicKeyDeserializer(network); + } + + private static final CkdFunction CKD_FUNCTION = HdPublicKey::cKDpub; + + static HdPublicKey from(final HdKey hdKey) { + return new HdPublicKey(new HdKey.Builder() + .network(hdKey.getNetwork()) + .neutered(true) + .key(hdKey.getPoint()) + .parentFingerprint(hdKey.getParentFingerprint()) + .depth(hdKey.depth()) + .childNumber(hdKey.getChildNumber()) + .chainCode(hdKey.getChainCode()) + .build()); + } + + private final HdKey hdKey; + + HdPublicKey(final HdKey hdKey) { + this.hdKey = hdKey; + } + + @Override + public HdPublicKey cKDpub(final int index) { + if (isHardened(index)) { + return null; + } + + final HdKey parent = this.hdKey; + final byte[] kPar = parent.getKey(); + + final byte[] data = new byte[37]; + final ByteArrayWriter writer = new ByteArrayWriter(data); + writer.concat(kPar, 33); + writer.concatSer32(index); + + final byte[] I = Digest.hmacSha512(parent.getChainCode(), data); + final byte[] Il = head32(I); + final byte[] Ir = tail32(I); + + final BigInteger parse256_Il = parse256(Il); + final ECPoint ki = gMultiplyAndAddPoint(parse256_Il, kPar); + + if (parse256_Il.compareTo(n()) >= 0 || ki.isInfinity()) { + return cKDpub(index + 1); + } + + final byte[] key = pointSerP(ki); + + return new HdPublicKey(new HdKey.Builder() + .network(parent.getNetwork()) + .neutered(true) + .depth(parent.depth() + 1) + .parentFingerprint(parent.calculateFingerPrint()) + .key(key) + .chainCode(Ir) + .childNumber(index) + .build()); + } + + public static HdPublicKey base58Decode(String key) throws SDKException { + return HdPublicKey.deserializer().deserialize(Base58.decode(key)); + } + + public Address getAddress() { + return Address.addressFromPubKey(hdKey.getKey()); + } + + private Derive derive() { + return new CkdFunctionDerive<>(CKD_FUNCTION, this); + } + + @Override + public HdPublicKey fromPath(final CharSequence derivationPath) { + final int length = derivationPath.length(); + if (length == 0) + throw new IllegalArgumentException("Path cannot be empty"); + if (length == 1) + return this; + if (derivationPath.charAt(0) == 'm' && depth() == 0) { + if (derivationPath.charAt(1) != '/') + throw new IllegalArgumentException("Root key must be a master key if the path start with m/"); + return derive().fromPath(derivationPath.subSequence(2, derivationPath.length())); + } + return derive().fromPath(derivationPath); + } + + @Override + public HdPublicKey fromPath(final Path derivationPath, final Derivation derivation) { + return derive().fromPath(derivationPath, derivation); + } + + public byte[] toByteArray() { + return hdKey.serialize(); + } + + public Network network() { + return hdKey.getNetwork(); + } + + public int depth() { + return hdKey.depth(); + } + + public int childNumber() { + return hdKey.getChildNumber(); + } + + public String toHexString() { + return Helper.toHexString(hdKey.getKey()); + } + + public String base58Encode() { + return Base58.encode(toByteArray()); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/crypto/bip32/HdPublicKeyDeserializer.java b/src/main/java/com/github/DNAProject/crypto/bip32/HdPublicKeyDeserializer.java new file mode 100644 index 0000000..afaaf23 --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/bip32/HdPublicKeyDeserializer.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.crypto.bip32; + +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.sdk.exception.SDKException; + +import java.util.Arrays; + +import static com.github.DNAProject.crypto.bip32.HdKey.confirmHdKeyChecksum; +import static io.github.novacrypto.base58.Base58.base58Decode; + +final class HdPublicKeyDeserializer implements Deserializer { + + static final HdPublicKeyDeserializer DEFAULT = new HdPublicKeyDeserializer(Bitcoin.MAIN_NET); + + private final Network network; + + HdPublicKeyDeserializer(final Network network) { + this.network = network; + } + + @Override + public HdPublicKey deserialize(final CharSequence extendedBase58Key) throws SDKException { + final byte[] extendedKeyData = base58Decode(extendedBase58Key); + try { + return deserialize(extendedKeyData); + } finally { + Arrays.fill(extendedKeyData, (byte) 0); + } + } + + @Override + public HdPublicKey deserialize(final byte[] extendedKeyData) throws SDKException { + confirmHdKeyChecksum(extendedKeyData); + final ByteArrayReader reader = new ByteArrayReader(extendedKeyData); + final int version = reader.readSer32(); + if (version != Bitcoin.MAIN_NET.getPublicVersion()) { + throw new SDKException(ErrorCode.OtherError(String.format("Can't find network that matches private version 0x%x", version))); + } + return new HdPublicKey(new HdKey + .Builder() + .network(Bitcoin.MAIN_NET) + .depth(reader.read()) + .parentFingerprint(reader.readSer32()) + .childNumber(reader.readSer32()) + .chainCode(reader.readRange(32)) + .key(reader.readRange(33)) + .neutered(true) + .build() + ); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/crypto/bip32/Network.java b/src/main/java/com/github/DNAProject/crypto/bip32/Network.java new file mode 100644 index 0000000..26b579a --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/bip32/Network.java @@ -0,0 +1,32 @@ +/* + * BIP32 library, a Java implementation of BIP32 + * Copyright (C) 2017-2019 Alan Evans, NovaCrypto + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Original source: https://github.com/NovaCrypto/BIP32 + * You can contact the authors via github issues. + */ + +package com.github.DNAProject.crypto.bip32; + +/** + * Network represents the network to use. + */ +public interface Network { + + int getPrivateVersion(); + + int getPublicVersion(); +} diff --git a/src/main/java/com/github/DNAProject/crypto/bip32/Secp256r1SC.java b/src/main/java/com/github/DNAProject/crypto/bip32/Secp256r1SC.java new file mode 100644 index 0000000..452facb --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/bip32/Secp256r1SC.java @@ -0,0 +1,58 @@ +/* + * BIP32 library, a Java implementation of BIP32 + * Copyright (C) 2017 Alan Evans, NovaCrypto + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Original source: https://github.com/NovaCrypto/BIP32 + * You can contact the authors via github issues. + */ + +package com.github.DNAProject.crypto.bip32; + +import org.spongycastle.asn1.x9.X9ECParameters; +import org.spongycastle.crypto.ec.CustomNamedCurves; +import org.spongycastle.math.ec.ECPoint; + +import java.math.BigInteger; + +final class Secp256r1SC { + + static final X9ECParameters CURVE = CustomNamedCurves.getByName("secp256r1"); + + static BigInteger n() { + return CURVE.getN(); + } + + static byte[] pointSerP(final ECPoint point) { + return point.getEncoded(true); + } + + static byte[] pointSerP_gMultiply(final BigInteger p) { + return pointSerP(gMultiply(p)); + } + + static ECPoint gMultiplyAndAddPoint(final BigInteger p, final byte[] toAdd) { + return gMultiply(p).add(decode(toAdd)); + } + + private static ECPoint decode(final byte[] toAdd) { + return CURVE.getCurve().decodePoint(toAdd); + } + + private static ECPoint gMultiply(BigInteger p) { + return CURVE.getG() + .multiply(p); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/crypto/bip32/Serializer.java b/src/main/java/com/github/DNAProject/crypto/bip32/Serializer.java new file mode 100644 index 0000000..2d24cee --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/bip32/Serializer.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.crypto.bip32; + +import static com.github.DNAProject.crypto.bip32.HdKey.checksum; + +final class Serializer { + + private final Network network; + private final boolean neutered; + private final int depth; + private final int childNumber; + private final int fingerprint; + + private Serializer(final Builder builder) { + network = builder.network; + neutered = builder.neutered; + depth = builder.depth; + childNumber = builder.childNumber; + fingerprint = builder.fingerprint; + } + + byte[] serialize(final byte[] key, final byte[] chainCode) { + if (key == null) { + throw new IllegalArgumentException("Key is null"); + } + if (chainCode == null) { + throw new IllegalArgumentException("Chain code is null"); + } + if (chainCode.length != 32) { + throw new IllegalArgumentException("Chain code must be 32 bytes"); + } + if (neutered) { + if (key.length != 33) { + throw new IllegalArgumentException("Key must be 33 bytes for neutered serialization"); + } + } else { + if (key.length != 32) { + throw new IllegalArgumentException("Key must be 32 bytes for non neutered serialization"); + } + } + + final byte[] privateKey = new byte[82]; + final ByteArrayWriter writer = new ByteArrayWriter(privateKey); + writer.concatSer32(getVersion()); + writer.concat((byte) depth); + writer.concatSer32(fingerprint); + writer.concatSer32(childNumber); + writer.concat(chainCode); + if (!neutered) { + writer.concat((byte) 0); + writer.concat(key); + } else { + writer.concat(key); + } + writer.concat(checksum(privateKey), 4); + return privateKey; + } + + private int getVersion() { + return neutered ? network.getPublicVersion() : network.getPrivateVersion(); + } + + static class Builder { + + private Network network; + private boolean neutered; + private int depth; + private int childNumber; + private int fingerprint; + + Builder network(final Network network) { + this.network = network; + return this; + } + + Builder neutered(final boolean neutered) { + this.neutered = neutered; + return this; + } + + Builder depth(final int depth) { + if (depth < 0 || depth > 255) { + throw new IllegalArgumentException("Depth must be [0..255]"); + } + this.depth = depth; + return this; + } + + Builder childNumber(final int childNumber) { + this.childNumber = childNumber; + return this; + } + + Builder fingerprint(final int fingerprint) { + this.fingerprint = fingerprint; + return this; + } + + Serializer build() { + return new Serializer(this); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/crypto/bip32/derivation/CharSequenceDerivation.java b/src/main/java/com/github/DNAProject/crypto/bip32/derivation/CharSequenceDerivation.java new file mode 100644 index 0000000..c5f052e --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/bip32/derivation/CharSequenceDerivation.java @@ -0,0 +1,61 @@ +/* + * BIP32 library, a Java implementation of BIP32 + * Copyright (C) 2017-2019 Alan Evans, NovaCrypto + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Original source: https://github.com/NovaCrypto/BIP32 + * You can contact the authors via github issues. + */ + +package com.github.DNAProject.crypto.bip32.derivation; + +public enum CharSequenceDerivation implements Derivation { + INSTANCE; + + public static int hard(final int index) { + return index | 0x80000000; + } + + public static boolean isHardened(final int i) { + return (i & 0x80000000) != 0; + } + + @Override + public T derive(final T rootKey, final CharSequence derivationPath, final CkdFunction ckdFunction) { + final int length = derivationPath.length(); + T currentKey = rootKey; + int buffer = 0; + for (int i = 0; i < length; i++) { + final char c = derivationPath.charAt(i); + switch (c) { + case '\'': + buffer = hard(buffer); + break; + case '/': + currentKey = ckdFunction.deriveChildKey(currentKey, buffer); + buffer = 0; + break; + default: + buffer *= 10; + if (c < '0' || c > '9') + throw new IllegalArgumentException("Illegal character in path: " + c); + buffer += c - '0'; + if (isHardened(buffer)) + throw new IllegalArgumentException("Index number too large"); + } + } + return ckdFunction.deriveChildKey(currentKey, buffer); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/crypto/bip32/derivation/CkdFunction.java b/src/main/java/com/github/DNAProject/crypto/bip32/derivation/CkdFunction.java new file mode 100644 index 0000000..caf44e6 --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/bip32/derivation/CkdFunction.java @@ -0,0 +1,34 @@ +/* + * BIP32derivation + * Copyright (C) 2017-2019 Alan Evans, NovaCrypto + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Original source: https://github.com/NovaCrypto/BIP32derivation + * You can contact the authors via github issues. + */ + +package com.github.DNAProject.crypto.bip32.derivation; + +public interface CkdFunction { + /** + * Derives the child at the given index on the parent. + * + * @param parent The parent to find the child of + * @param childIndex The index of the child + * @return the {@link KeyNode} for the child + */ + KeyNode deriveChildKey(final KeyNode parent, final int childIndex); + +} diff --git a/src/main/java/com/github/DNAProject/crypto/bip32/derivation/CkdFunctionDerive.java b/src/main/java/com/github/DNAProject/crypto/bip32/derivation/CkdFunctionDerive.java new file mode 100644 index 0000000..e1feb00 --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/bip32/derivation/CkdFunctionDerive.java @@ -0,0 +1,43 @@ +/* + * BIP32derivation + * Copyright (C) 2017-2019 Alan Evans, NovaCrypto + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Original source: https://github.com/NovaCrypto/BIP32derivation + * You can contact the authors via github issues. + */ + +package com.github.DNAProject.crypto.bip32.derivation; + +public final class CkdFunctionDerive implements Derive { + + private final CkdFunction standardCkdFunction; + private final Node rootNode; + + public CkdFunctionDerive(final CkdFunction standardCkdFunction, final Node rootNode) { + this.standardCkdFunction = standardCkdFunction; + this.rootNode = rootNode; + } + + @Override + public Node fromPath(final CharSequence derivationPath) { + return fromPath(derivationPath, CharSequenceDerivation.INSTANCE); + } + + @Override + public Node fromPath(final Path derivationPath, final Derivation derivation) { + return derivation.derive(rootNode, derivationPath, standardCkdFunction); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/crypto/bip32/derivation/CkdFunctionResultCacheDecorator.java b/src/main/java/com/github/DNAProject/crypto/bip32/derivation/CkdFunctionResultCacheDecorator.java new file mode 100644 index 0000000..f95e592 --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/bip32/derivation/CkdFunctionResultCacheDecorator.java @@ -0,0 +1,63 @@ +/* + * BIP32derivation + * Copyright (C) 2017-2019 Alan Evans, NovaCrypto + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Original source: https://github.com/NovaCrypto/BIP32derivation + * You can contact the authors via github issues. + */ + +package com.github.DNAProject.crypto.bip32.derivation; + +import java.util.HashMap; +import java.util.Map; + +/** + * Non-thread safe result cache for ckd functions. + *

+ * If the same child of the same parent is requested a second time, the original result will be returned. + * + * @param Key Node type. + */ +public final class CkdFunctionResultCacheDecorator implements CkdFunction { + + private final CkdFunction decoratedCkdFunction; + + private final Map> cache = new HashMap<>(); + + private CkdFunctionResultCacheDecorator(final CkdFunction decoratedCkdFunction) { + this.decoratedCkdFunction = decoratedCkdFunction; + } + + @Override + public Key deriveChildKey(final Key parent, final int childIndex) { + final Map mapForParent = getMapOf(parent); + Key child = mapForParent.get(childIndex); + if (child == null) { + child = decoratedCkdFunction.deriveChildKey(parent, childIndex); + mapForParent.put(childIndex, child); + } + return child; + } + + private Map getMapOf(final Key parentKey) { + HashMap mapForParent = cache.get(parentKey); + if (mapForParent == null) { + mapForParent = new HashMap<>(); + cache.put(parentKey, mapForParent); + } + return mapForParent; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/crypto/bip32/derivation/Derivation.java b/src/main/java/com/github/DNAProject/crypto/bip32/derivation/Derivation.java new file mode 100644 index 0000000..be384fb --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/bip32/derivation/Derivation.java @@ -0,0 +1,36 @@ +/* + * BIP32 library, a Java implementation of BIP32 + * Copyright (C) 2017-2019 Alan Evans, NovaCrypto + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Original source: https://github.com/NovaCrypto/BIP32 + * You can contact the authors via github issues. + */ + +package com.github.DNAProject.crypto.bip32.derivation; + +public interface Derivation { + + /** + * Traverse the nodes from the root key node to find the node referenced by the path. + * + * @param rootKey The root of the path + * @param path The path to follow + * @param ckdFunction Allows you to follow one link + * @param The type of node we are visiting + * @return The final node found at the end of the path + */ + Key derive(final Key rootKey, final Path path, final CkdFunction ckdFunction); +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/crypto/bip32/derivation/Derive.java b/src/main/java/com/github/DNAProject/crypto/bip32/derivation/Derive.java new file mode 100644 index 0000000..e82c657 --- /dev/null +++ b/src/main/java/com/github/DNAProject/crypto/bip32/derivation/Derive.java @@ -0,0 +1,43 @@ +/* + * BIP32 library, a Java implementation of BIP32 + * Copyright (C) 2017-2019 Alan Evans, NovaCrypto + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * Original source: https://github.com/NovaCrypto/BIP32 + * You can contact the authors via github issues. + */ + +package com.github.DNAProject.crypto.bip32.derivation; + +public interface Derive { + + /** + * Derive from a string path such as m/44'/0'/0'/0/1 + * + * @param derivationPath Path + * @return Key at the path + */ + Key fromPath(final CharSequence derivationPath); + + /** + * Derive from a generic path using the {@link Derivation} supplied to extract the child indexes + * + * @param derivationPath Path + * @param derivation The class that extracts the path elements + * @param The generic type of the path + * @return Key at the path + */ + Key fromPath(final Path derivationPath, final Derivation derivation); +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/io/BinaryReader.java b/src/main/java/com/github/DNAProject/io/BinaryReader.java new file mode 100644 index 0000000..b7c18a8 --- /dev/null +++ b/src/main/java/com/github/DNAProject/io/BinaryReader.java @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.io; + +import java.io.*; +import java.lang.reflect.Array; +import java.nio.*; + +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.core.scripts.ScriptOp; +import org.bouncycastle.math.ec.ECPoint; + +import com.github.DNAProject.crypto.ECC; + +/* + ****************************************************************************** + * public func for outside calling + ****************************************************************************** + * 1. WriteVarUint func, depend on the inpute number's Actual number size, + * serialize to bytes. + * uint8 => (LittleEndian)num in 1 byte = 1bytes + * uint16 => 0xfd(1 byte) + (LittleEndian)num in 2 bytes = 3bytes + * uint32 => 0xfe(1 byte) + (LittleEndian)num in 4 bytes = 5bytes + * uint64 => 0xff(1 byte) + (LittleEndian)num in 8 bytes = 9bytes + * 2. ReadVarUint func, this func will read the first byte to determined + * the num length to read.and retrun the uint64 + * first byte = 0xfd, read the next 2 bytes as uint16 + * first byte = 0xfe, read the next 4 bytes as uint32 + * first byte = 0xff, read the next 8 bytes as uint64 + * other else, read this byte as uint8 + * 3. WriteVarBytes func, this func will output two item as serialization. + * length of bytes (uint8/uint16/uint32/uint64) + bytes + * 4. WriteString func, this func will output two item as serialization. + * length of string(uint8/uint16/uint32/uint64) + bytes(string) + * 5. ReadVarBytes func, this func will first read a uint to identify the + * length of bytes, and use it to get the next length's bytes to return. + * 6. ReadString func, this func will first read a uint to identify the + * length of string, and use it to get the next bytes as a string. + * 7. GetVarUintSize func, this func will return the length of a uint when it + * serialized by the WriteVarUint func. + * 8. ReadBytes func, this func will read the specify lenth's bytes and retun. + * 9. ReadUint8,16,32,64 read uint with fixed length + * 10.WriteUint8,16,32,64 Write uint with fixed length + * 11.ToArray SerializableData to ToArray() func. + ****************************************************************************** + */ +public class BinaryReader implements AutoCloseable { + private DataInputStream reader; + private byte[] array = new byte[8]; + private ByteBuffer buffer = ByteBuffer.wrap(array).order(ByteOrder.LITTLE_ENDIAN); + + public BinaryReader(InputStream stream) { + this.reader = new DataInputStream(stream); + } + + @Override + public void close() throws IOException { + reader.close(); + } + + public void read(byte[] buffer) throws IOException { + reader.readFully(buffer); + } + + public void read(byte[] buffer, int index, int length) throws IOException { + reader.readFully(buffer, index, length); + } + + public boolean readBoolean() throws IOException { + return reader.readBoolean(); + } + + public byte readByte() throws IOException { + return reader.readByte(); + } + + public byte[] readBytes(int count) throws IOException { + byte[] buffer = new byte[count]; + reader.readFully(buffer); + return buffer; + } + + public double readDouble() throws IOException { + reader.readFully(array, 0, 8); + return buffer.getDouble(0); + } + + public ECPoint readECPoint() throws IOException { + byte[] encoded; + byte fb = reader.readByte(); + switch (fb) + { + case 0x00: + encoded = new byte[1]; + break; + case 0x02: + case 0x03: + encoded = new byte[33]; + encoded[0] = fb; + reader.readFully(encoded, 1, 32); + break; + case 0x04: + encoded = new byte[65]; + encoded[0] = fb; + reader.readFully(encoded, 1, 64); + break; + default: + throw new IOException(ErrorCode.ParamError); + } + return ECC.secp256r1.getCurve().decodePoint(encoded); + } + + public String readFixedString(int length) throws IOException { + byte[] data = readBytes(length); + int count = -1; + while (data[++count] != 0); + return new String(data, 0, count, "UTF-8"); + } + + public float readFloat() throws IOException { + reader.readFully(array, 0, 4); + return buffer.getFloat(0); + } + + public int readInt() throws IOException { + reader.readFully(array, 0, 4); + return buffer.getInt(0); + } + + public long readLong() throws IOException { + reader.readFully(array, 0, 8); + return buffer.getLong(0); + } + + public T readSerializable(Class t) throws InstantiationException, IllegalAccessException, IOException { + T obj = t.newInstance(); + obj.deserialize(this); + return obj; + } + + public T[] readSerializableArray(Class t) throws InstantiationException, IllegalAccessException, IOException { + @SuppressWarnings("unchecked") + T[] array = (T[])Array.newInstance(t, (int)readVarInt(0x10000000)); + for (int i = 0; i < array.length; i++) { + array[i] = t.newInstance(); + array[i].deserialize(this); + } + return array; + } + + public short readShort() throws IOException { + reader.readFully(array, 0, 2); + return buffer.getShort(0); + } + + public byte[] readVarBytes() throws IOException { + return readVarBytes(0X7fffffc7); + } + public byte[] readVarBytes2() throws IOException { + return readBytes((int)readVarInt2(0X7fffffc7)); + } + public byte[] readVarBytes(int max) throws IOException { + return readBytes((int)readVarInt(max)); + } + + public long readVarInt() throws IOException { + return readVarInt(Long.MAX_VALUE); + } + + public long readVarInt(long max) throws IOException { + long fb = Byte.toUnsignedLong(readByte()); + long value; + if (fb == 0xFD) { + value = Short.toUnsignedLong(readShort()); + } else if (fb == 0xFE) { + value = Integer.toUnsignedLong(readInt()); + } else if (fb == 0xFF) { + value = readLong(); + } else { + value = fb; + } + if (Long.compareUnsigned(value, max) > 0) { + throw new IOException(ErrorCode.ParamError); + } + return value; + } + public long readVarInt2(long max) throws IOException { + long fb = Byte.toUnsignedLong(readByte()); + long value; + if (fb == ScriptOp.OP_PUSHDATA1.getByte()) { + value = Byte.toUnsignedLong(readByte()); + } else if (fb == ScriptOp.OP_PUSHDATA2.getByte()) { + value = Short.toUnsignedLong(readShort()); + } else if (fb == ScriptOp.OP_PUSHDATA4.getByte()) { + value = Integer.toUnsignedLong(readInt()); + } else{ + value = fb; + } + if (Long.compareUnsigned(value, max) > 0) { + throw new IOException(ErrorCode.ParamError); + } + return value; + } + public String readVarString() throws IOException { + return new String(readVarBytes(), "UTF-8"); + } + public int available() throws IOException { + return reader.available(); + } + public long Seek(long n) throws IOException { + reader.reset(); + return reader.skip(n); + } +} diff --git a/src/main/java/DNA/IO/BinaryWriter.java b/src/main/java/com/github/DNAProject/io/BinaryWriter.java similarity index 78% rename from src/main/java/DNA/IO/BinaryWriter.java rename to src/main/java/com/github/DNAProject/io/BinaryWriter.java index 69dfa6a..cfa68e4 100644 --- a/src/main/java/DNA/IO/BinaryWriter.java +++ b/src/main/java/com/github/DNAProject/io/BinaryWriter.java @@ -1,4 +1,23 @@ -package DNA.IO; +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.io; import java.io.*; import java.nio.*; @@ -117,7 +136,7 @@ public void writeVarInt(long v) throws IOException { } else if (v <= 0xFFFF) { writeByte((byte)0xFD); writeShort((short)v); - } else if (v <= 0xFFFFFFFF) { + } else if (v <= 0xFFFFFFFFL) { writeByte((byte)0xFE); writeInt((int)v); } else { diff --git a/src/main/java/com/github/DNAProject/io/Serializable.java b/src/main/java/com/github/DNAProject/io/Serializable.java new file mode 100644 index 0000000..4972da2 --- /dev/null +++ b/src/main/java/com/github/DNAProject/io/Serializable.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.io; + +import com.github.DNAProject.common.Helper; + +import java.io.*; + +/** + * Serialize interface + */ +public interface Serializable { + static T from(byte[] value, Class t) throws InstantiationException, IllegalAccessException { + try (ByteArrayInputStream ms = new ByteArrayInputStream(value)) { + try (BinaryReader reader = new BinaryReader(ms)) { + return reader.readSerializable(t); + } + } catch (IOException ex) { + throw new IllegalArgumentException(ex); + } + } + + /** + * @param reader + * @throws IOException + */ + void deserialize(BinaryReader reader) throws IOException; + + /** + * @param writer + * @throws IOException + */ + void serialize(BinaryWriter writer) throws IOException; + + default byte[] toArray() { + try (ByteArrayOutputStream ms = new ByteArrayOutputStream()) { + try (BinaryWriter writer = new BinaryWriter(ms)) { + serialize(writer); + writer.flush(); + return ms.toByteArray(); + } + } catch (IOException ex) { + throw new UnsupportedOperationException(ex); + } + } + + default String toHexString() { + return Helper.toHexString(toArray()); + } + + +} diff --git a/src/main/java/com/github/DNAProject/io/utils.java b/src/main/java/com/github/DNAProject/io/utils.java new file mode 100644 index 0000000..f3b25d2 --- /dev/null +++ b/src/main/java/com/github/DNAProject/io/utils.java @@ -0,0 +1,20 @@ +package com.github.DNAProject.io; + +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; + +import java.io.IOException; +import java.math.BigInteger; + +public class utils { + + public static long readVarInt(BinaryReader reader) throws IOException { + byte[] r = reader.readVarBytes(); + BigInteger b = Helper.BigIntFromNeoBytes(r); + return b.longValue(); + } + public static Address readAddress(BinaryReader reader) throws IOException { + byte[] r = reader.readVarBytes(); + return new Address(r); + } +} diff --git a/src/main/java/com/github/DNAProject/merkle/MerkleVerifier.java b/src/main/java/com/github/DNAProject/merkle/MerkleVerifier.java new file mode 100644 index 0000000..0c11fbc --- /dev/null +++ b/src/main/java/com/github/DNAProject/merkle/MerkleVerifier.java @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.merkle; + +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.common.UInt256; +import com.github.DNAProject.sdk.exception.SDKException; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class MerkleVerifier { + private static TreeHasher hasher = new TreeHasher(); + + + public static boolean VerifyLeafHashInclusion(UInt256 leaf_hash, + int leaf_index, UInt256[] proof, UInt256 root_hash, int tree_size) throws Exception { + + if (tree_size <= leaf_index) { + throw new SDKException(ErrorCode.MerkleVerifierErr); + } + UInt256 calculated_root_hash = calculate_root_hash_from_audit_path(leaf_hash, + leaf_index, proof, tree_size); + if (calculated_root_hash.equals(new UInt256())) { + return false; + } + if (!calculated_root_hash.equals(root_hash)) { + throw new Exception("Constructed root hash differs from provided root hash. Constructed: %x, Expected: " + + calculated_root_hash + root_hash); + } + return true; + } + + public static UInt256 calculate_root_hash_from_audit_path(UInt256 leaf_hash, + int node_index, UInt256[] audit_path, int tree_size) { + UInt256 calculated_hash = leaf_hash; + int last_node = tree_size - 1; + int pos = 0; + int path_len = audit_path.length; + for (; last_node > 0; ) { + if (pos >= path_len) { + return new UInt256(); + } + if (node_index % 2 == 1) { + calculated_hash = hasher.hash_children(audit_path[pos], calculated_hash); + pos += 1; + } else if (node_index < last_node) { + calculated_hash = hasher.hash_children(calculated_hash, audit_path[pos]); + pos += 1; + } + node_index /= 2; + last_node /= 2; + } + + if (pos < path_len) { + return new UInt256(); + } + + return calculated_hash; + } + + public static List getProof(UInt256 leaf_hash, int node_index, UInt256[] audit_path, int tree_size) { + List nodes = new ArrayList<>(); + int last_node = tree_size - 1; + int pos = 0; + for (; last_node > 0; ) { + if (node_index % 2 == 1) { + Map map = new HashMap(); + map.put("Direction","Left"); + map.put("TargetHash",audit_path[pos].toHexString()); + nodes.add(map); + pos += 1; + } else if (node_index < last_node) { + Map map = new HashMap(); + map.put("Direction","Right"); + map.put("TargetHash",audit_path[pos].toHexString()); + nodes.add(map); + pos += 1; + } + node_index /= 2; + last_node /= 2; + } + return nodes; + } + public static boolean Verify(UInt256 leaf_hash,List targetHashes, UInt256 root_hash) throws SDKException { + UInt256 calculated_hash = leaf_hash; + for(int i=0;i. + * + */ + +package com.github.DNAProject.network.rest; + +import com.alibaba.fastjson.JSON; + +public class Result { + public String Action; + public long Error; + public String Desc; + public Object Result; + public String Version; + @Override + public String toString() { + return JSON.toJSONString(this); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/network/rest/UrlConsts.java b/src/main/java/com/github/DNAProject/network/rest/UrlConsts.java new file mode 100644 index 0000000..73be37a --- /dev/null +++ b/src/main/java/com/github/DNAProject/network/rest/UrlConsts.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.network.rest; + +/** + * + */ +public class UrlConsts { + + public static String Url_send_transaction = "/api/v1/transaction"; + public static String Url_get_transaction = "/api/v1/transaction/"; + public static String Url_get_generate_block_time = "/api/v1/node/generateblocktime"; + public static String Url_get_node_count = "/api/v1/node/connectioncount"; + public static String Url_get_block_height = "/api/v1/block/height"; + public static String Url_get_block_by_height = "/api/v1/block/details/height/"; + public static String Url_get_block_by_hash = "/api/v1/block/details/hash/"; + public static String Url_get_account_balance = "/api/v1/balance/"; + public static String Url_get_contract_state = "/api/v1/contract/"; + public static String Url_get_smartcodeevent_txs_by_height = "/api/v1/smartcode/event/transactions/"; + public static String Url_get_smartcodeevent_by_txhash = "/api/v1/smartcode/event/txhash/"; + public static String Url_get_block_height_by_txhash = "/api/v1/block/height/txhash/"; + public static String Url_get_storage = "/api/v1/storage/"; + public static String Url_get_merkleproof = "/api/v1/merkleproof/"; + public static String Url_get_mem_pool_tx_count= "/api/v1/mempool/txcount"; + public static String Url_get_mem_pool_tx_state = "/api/v1/mempool/txstate/"; + public static String Url_get_allowance = "/api/v1/allowance/"; + public static String Url_get_version = "/api/v1/version"; + public static String Url_get_grant_ong = "/api/v1/grantong"; + public static String Url_get_networkid = "/api/v1/networkid"; + public static String Url_get_syncstatus = "/api/v1/node/syncstatus"; +} diff --git a/src/main/java/com/github/DNAProject/network/rest/X509.java b/src/main/java/com/github/DNAProject/network/rest/X509.java new file mode 100644 index 0000000..33c92d8 --- /dev/null +++ b/src/main/java/com/github/DNAProject/network/rest/X509.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.network.rest; + +import javax.net.ssl.X509TrustManager; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +/** + * + */ +public class X509 implements X509TrustManager { + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; + } + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + } + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException { + } +} diff --git a/src/main/java/com/github/DNAProject/network/rpc/Interfaces.java b/src/main/java/com/github/DNAProject/network/rpc/Interfaces.java new file mode 100644 index 0000000..a3d3aff --- /dev/null +++ b/src/main/java/com/github/DNAProject/network/rpc/Interfaces.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.network.rpc; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.network.exception.RpcException; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +/** + * + */ +public class Interfaces { + private final URL url; + + + + public Interfaces(String url) throws MalformedURLException { + this.url = new URL(url); + } + + private static double getNextId() { + double d = 0.0; + do { + d = Math.random(); + } while (("" + d).indexOf("E") != -1); + return d; + } + public String getHost() { + return url.getHost() + " " + url.getPort(); + } + public Object call(String method, Object... params) throws RpcException, IOException { + Map req = makeRequest(method, params); + Map response = (Map) send(req); + if (response == null) { + throw new RpcException(0,ErrorCode.ConnectUrlErr( url + "response is null. maybe is connect error")); + } else if ((int) response.get("error") == 0) { + return response.get("result"); + } else { + throw new RpcException(0, JSON.toJSONString(response)); + } + } + + private Map makeRequest(String method, Object[] params) { + Map request = new HashMap(); + request.put("jsonrpc", "2.0"); + request.put("method", method); + request.put("params", params); + request.put("id", 1); + System.out.println(String.format("POST url=%s,%s", this.url, JSON.toJSONString(request))); + return request; + } + + + public Object send(Object request) throws IOException { + try { + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setConnectTimeout(10000); + connection.setReadTimeout(10000); + connection.setDoOutput(true); + try (OutputStreamWriter w = new OutputStreamWriter(connection.getOutputStream())) { + w.write(JSON.toJSONString(request)); + } + try (InputStreamReader r = new InputStreamReader(connection.getInputStream())) { + StringBuffer temp = new StringBuffer(); + int c = 0; + while ((c = r.read()) != -1) { + temp.append((char) c); + } + //System.out.println("result:"+temp.toString()); + return JSON.parseObject(temp.toString(), Map.class); + } + } catch (IOException e) { + } + return null; + } +} diff --git a/src/main/java/com/github/DNAProject/network/rpc/RpcClient.java b/src/main/java/com/github/DNAProject/network/rpc/RpcClient.java new file mode 100644 index 0000000..0ac072c --- /dev/null +++ b/src/main/java/com/github/DNAProject/network/rpc/RpcClient.java @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.network.rpc; + +import java.io.IOException; +import java.net.MalformedURLException; + +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.common.UInt256; +import com.github.DNAProject.core.block.Block; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.io.Serializable; +import com.github.DNAProject.network.connect.AbstractConnector; +import com.github.DNAProject.network.exception.ConnectorException; +import com.github.DNAProject.network.exception.RpcException; + +public class RpcClient extends AbstractConnector { + private Interfaces rpc; + + public RpcClient(String url) { + try { + this.rpc = new Interfaces(url); + } catch (MalformedURLException e) { + e.printStackTrace(); + } + } + + @Override + public String getUrl() { + return rpc.getHost(); + } + + @Override + public Object getBalance(String address) throws ConnectorException,IOException { + Object result = null; + result = rpc.call("getbalance", address); + return result; + } + + @Override + public String sendRawTransaction(String sData) throws RpcException, IOException { + Object result = rpc.call("sendrawtransaction", sData); + return (String) result; + } + + @Override + public Object sendRawTransaction(boolean preExec, String userid, String sData) throws RpcException, IOException { + Object result = null; + if(preExec){ + result = rpc.call("sendrawtransaction", sData,1); + }else { + result = rpc.call("sendrawtransaction", sData); + } + return result; + } + + @Override + public Transaction getRawTransaction(String txhash) throws RpcException, IOException { + Object result = rpc.call("getrawtransaction", txhash.toString()); + return Transaction.deserializeFrom(Helper.hexToBytes((String) result)); + } + + @Override + public Object getRawTransactionJson(String txhash) throws RpcException, IOException { + Object result = null; + result = rpc.call("getrawtransaction", txhash.toString()); + return Transaction.deserializeFrom(Helper.hexToBytes((String) result)).json(); + } + + @Override + public int getNodeCount() throws RpcException, IOException { + Object result = rpc.call("getconnectioncount"); + return (int) result; + } + + @Override + public int getBlockHeight() throws RpcException, IOException { + Object result = rpc.call("getblockcount"); + return (int) result - 1; + } + + @Override + public Object getBlockJson(int index) throws RpcException,IOException { + Object result = null; + result = rpc.call("getblock", index, 1); + return result; + } + + @Override + public Object getBlockJson(String hash) throws RpcException,IOException { + Object result = null; + result = rpc.call("getblock", hash, 1); + return result; + } + + @Override + public Object getContract(String hash) throws RpcException,IOException { + Object result = null; + result = rpc.call("getcontractstate", hash); + return result; + } + + @Override + public Object getContractJson(String hash) throws RpcException,IOException { + Object result = null; + result = rpc.call("getcontractstate", hash,1); + return result; + } + + public String getRawTransaction(UInt256 txhash) throws RpcException, IOException { + Object result = rpc.call("getrawtransaction", txhash.toString()); + return (String) result; + } + + + public Block getBlock(UInt256 hash) throws RpcException, IOException { + Object result = rpc.call("getblock", hash.toString()); + try { + Block bb = Serializable.from(Helper.hexToBytes((String) result), Block.class); + return bb; + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + @Override + public Block getBlock(int index) throws RpcException, IOException { + Object result = rpc.call("getblock", index); + try { + Block bb = Serializable.from(Helper.hexToBytes((String) result), Block.class); + return bb; + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + public int getBlockCount() throws RpcException, IOException { + Object result = rpc.call("getblockcount"); + return (int) result; + } + + @Override + public Block getBlock(String hash) throws ConnectorException, IOException { + Object result = rpc.call("getblock", hash.toString()); + try { + Block bb = Serializable.from(Helper.hexToBytes((String) result), Block.class); + return bb; + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException(e); + } + } + + @Override + public Object getSmartCodeEvent(int height) throws ConnectorException, IOException { + Object result = rpc.call("getsmartcodeevent", height); + try { + return result; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public Object getSmartCodeEvent(String hash) throws ConnectorException, IOException { + Object result = rpc.call("getsmartcodeevent", hash.toString()); + try { + return result; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public int getBlockHeightByTxHash(String hash) throws ConnectorException, IOException { + Object result = rpc.call("getblockheightbytxhash", hash.toString()); + try { + return (int)result; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public String getStorage(String codehash, String key) throws ConnectorException, IOException { + Object result = rpc.call("getstorage", codehash, key); + try { + return (String)result; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + @Override + public Object getMerkleProof(String hash) throws ConnectorException, IOException { + Object result = rpc.call("getmerkleproof", hash); + try { + return result; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + @Override + public String getAllowance(String asset,String from,String to) throws ConnectorException, IOException { + Object result = rpc.call("getallowance", asset,from,to); + try { + return (String)result; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + @Override + public Object getMemPoolTxCount() throws ConnectorException, IOException { + Object result = rpc.call("getmempooltxcount"); + try { + return result; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + @Override + public Object getMemPoolTxState(String hash) throws ConnectorException, IOException { + Object result = rpc.call("getmempooltxstate", hash); + try { + return result; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + @Override + public String getVersion() throws ConnectorException, IOException { + Object result = rpc.call("getversion"); + try { + return (String)result; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public String getGrantOng(String address) throws ConnectorException, IOException { + Object result = rpc.call("getgrantong",address); + try { + return (String) result; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public int getNetworkId() throws ConnectorException, IOException { + Object result = rpc.call("getnetworkid"); + try { + return (int)result; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + @Override + public Object getNodeSyncStatus() throws ConnectorException, IOException { + Object result = rpc.call("getsyncstatus"); + try { + return result; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + @Override + public String getSideChainData(String sideChainID) throws ConnectorException, IOException { + Object result = rpc.call("getsidechaindata", sideChainID); + try { + return (String) result; + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} + diff --git a/src/main/java/com/github/DNAProject/sdk/claim/Claim.java b/src/main/java/com/github/DNAProject/sdk/claim/Claim.java new file mode 100644 index 0000000..c2820c8 --- /dev/null +++ b/src/main/java/com/github/DNAProject/sdk/claim/Claim.java @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.sdk.claim; + +import com.alibaba.fastjson.annotation.JSONField; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.DataSignature; +import com.github.DNAProject.crypto.Digest; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.DNAProject.crypto.SignatureScheme; + +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * Claim + */ +public class Claim { + private String context = ""; + private String id = UUID.randomUUID().toString(); + private Map claim = new HashMap(); + String ClaimStr = ""; + + public Claim(SignatureScheme scheme, Account acct, String ctx, Map claimMap, Map metadata,String publicKeyId) { + context = ctx; + claim.put("Context", context); + if (claimMap != null) { + claim.put("Content", claimMap); + } + claim.put("Metadata", new MetaData(metadata).getJson()); + id = Helper.toHexString(Digest.sha256(JSON.toJSONString(claim).getBytes())); + claim.put("Id", id); + claim.put("Version", "v1.0"); + DataSignature sign = new DataSignature(scheme, acct, getClaim()); + byte[] signature = sign.signature(); + SignatureInfo info = new SignatureInfo("", "",publicKeyId, signature); + claim.put("Signature", info.getJson()); + + } + + /** + * + * @param scheme + * @param acct + * @param ctx + * @param clmMap + * @param metadata + * @param publicKeyId + * @param expireTime + * @throws Exception + */ + public Claim(SignatureScheme scheme, Account acct, String ctx, Map clmMap, Map metadata,Map clmRevMap,String publicKeyId,long expireTime) throws Exception { + String iss = metadata.get("Issuer"); + String sub = metadata.get("Subject"); + Header header = new Header("","",publicKeyId); + Payload payload = new Payload("v1.0",iss,sub,System.currentTimeMillis()/1000,expireTime,ctx,clmMap,clmRevMap); + String headerStr = JSONObject.toJSONString(header.getJson()); + String payloadStr = JSONObject.toJSONString(payload.getJson()); + byte[] headerBytes = Base64.getEncoder().encode(headerStr.getBytes()); + byte[] payloadBytes = Base64.getEncoder().encode(payloadStr.getBytes()); + DataSignature sign = new DataSignature(scheme, acct, new String(headerBytes) + "." + new String(payloadBytes)); + byte[] signature = sign.signature(); + ClaimStr += new String(headerBytes) + "." + new String(payloadBytes) + "." + new String(Base64.getEncoder().encode(signature)); + } + + + public String getClaim() { + Map tmp = new HashMap(); + for (Map.Entry e : claim.entrySet()) { + tmp.put(e.getKey(), e.getValue()); + } + return JSONObject.toJSONString(tmp); + } + public String getClaimStr() { + return ClaimStr; + } +} + +class Header { + public String Alg = "ONT-ES256"; + public String Typ = "JWT-X"; + public String Kid; + public Header(String alg,String typ, String kid) { +// Alg = alg; +// Typ = typ; + Kid = kid; + } + public Object getJson() { + Map header = new HashMap(); + header.put("alg", Alg); + header.put("typ", Typ); + header.put("kid", Kid); + return header; + } +} +class Payload { + public String Ver; + public String Iss; + public String Sub; + public long Iat; + public long Exp; + public String Jti; + @JSONField(name = "@context") + public String Context; + public Map ClmMap = new HashMap(); + public Map ClmRevMap = new HashMap(); + + public Payload(String ver,String iss,String sub,long iat,long exp,String ctx,Map clmMap,Map clmRevMap) { + Ver = ver; + Iss = iss; + Sub = sub; + Iat = iat; + Exp = exp; + Context = ctx; + ClmMap = clmMap; + ClmRevMap = clmRevMap; + Jti = Helper.toHexString(Digest.sha256(JSON.toJSONString(getJson()).getBytes())); + } + + public Object getJson() { + Map payload = new HashMap(); + payload.put("ver", Ver); + payload.put("iss", Iss); + payload.put("sub", Sub); + payload.put("iat", Iat); + payload.put("exp", Exp); + payload.put("jti", Jti); + payload.put("@context", Context); + payload.put("clm",ClmMap); + payload.put("clm-rev",ClmRevMap); + return payload; + } +} +class SignatureInfo { + + private String Format = "pgp"; + private String Algorithm = "ECDSAwithSHA256"; + private byte[] Value; + private String PublicKeyId; + + public SignatureInfo(String format, String alg ,String publicKeyId,byte[] val) { + Value = val; + PublicKeyId = publicKeyId; + } + + public Object getJson() { + Map signature = new HashMap(); + signature.put("Format", Format); + signature.put("Algorithm", Algorithm); + signature.put("Value", Value); + signature.put("PublicKeyId", PublicKeyId); + return signature; + } +} + +class MetaData { + + private String CreateTime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(new Date());//"2017-08-25T10:03:04Z"; + private Map meta = new HashMap(); + + public MetaData(Map map) { + if (map != null) { + meta = map; + } + } + + public Object getJson() { + meta.put("CreateTime", CreateTime); + Map tmp = new HashMap(); + for (Map.Entry e : meta.entrySet()) { + tmp.put(e.getKey(), e.getValue()); + } + return tmp; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/sdk/exception/SDKException.java b/src/main/java/com/github/DNAProject/sdk/exception/SDKException.java new file mode 100644 index 0000000..e9b4f73 --- /dev/null +++ b/src/main/java/com/github/DNAProject/sdk/exception/SDKException.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.sdk.exception; + + +import com.alibaba.fastjson.JSON; + +public class SDKException extends Exception { + + private static final long serialVersionUID = -3056715808373341597L; + + public SDKException(String message) { + super(message); + initExMsg(message); + } + public SDKException(String message, Throwable ex) { + super(message, ex); + initExMsg(message); + } + public SDKException(Throwable ex) { + super(ex); + } + + private void initExMsg(String message) { + } + +} + diff --git a/src/main/java/com/github/DNAProject/sdk/exception/SDKRuntimeException.java b/src/main/java/com/github/DNAProject/sdk/exception/SDKRuntimeException.java new file mode 100644 index 0000000..c694395 --- /dev/null +++ b/src/main/java/com/github/DNAProject/sdk/exception/SDKRuntimeException.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.sdk.exception; + +import com.alibaba.fastjson.JSON; + +public class SDKRuntimeException extends RuntimeException { + + private static final long serialVersionUID = 2005335065357755315L; + public SDKRuntimeException(String message) { + super(message); + initExMsg(message); + } + + public SDKRuntimeException(String message, Throwable ex) { + super(message, ex); + initExMsg(message); + } + + private void initExMsg(String message) { + } +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/sdk/info/AccountInfo.java b/src/main/java/com/github/DNAProject/sdk/info/AccountInfo.java new file mode 100644 index 0000000..f715d7f --- /dev/null +++ b/src/main/java/com/github/DNAProject/sdk/info/AccountInfo.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.sdk.info; + +import com.alibaba.fastjson.JSON; + +/** + * + */ +public class AccountInfo { + public String addressBase58; + public String pubkey; + + public String encryptedPrikey; + public String addressU160; + private String prikey; + private String prikeyWif; + + public void setPrikey(String prikey) { + //this.prikey = prikey; + } + + public void setPriwif(String priwif) { + //this.prikeyWif = priwif; + } + + public String getPrikeyWif() { + return prikeyWif; + } + + @Override + public String toString() { + return JSON.toJSONString(this); + } + + +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/sdk/info/IdentityInfo.java b/src/main/java/com/github/DNAProject/sdk/info/IdentityInfo.java new file mode 100644 index 0000000..7029565 --- /dev/null +++ b/src/main/java/com/github/DNAProject/sdk/info/IdentityInfo.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.sdk.info; + +import com.alibaba.fastjson.JSON; + +/** + * + */ +public class IdentityInfo { + public String dnaid; + public String pubkey; + + public String encryptedPrikey; + public String addressU160; + private String prikey; + private String prikeyWif; + + public void setPrikey(String prikey) { + //this.prikey = prikey; + } + + public void setPriwif(String priwif) { + //this.prikeyWif = priwif; + } + + public String getPrikeyWif() { + return prikeyWif; + } + + @Override + public String toString() { + return JSON.toJSONString(this); + } + + +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/sdk/manager/ConnectMgr.java b/src/main/java/com/github/DNAProject/sdk/manager/ConnectMgr.java new file mode 100644 index 0000000..26b96aa --- /dev/null +++ b/src/main/java/com/github/DNAProject/sdk/manager/ConnectMgr.java @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.sdk.manager; + +import java.io.IOException; +import java.util.Map; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.block.Block; +import com.github.DNAProject.network.rpc.RpcClient; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.network.exception.ConnectorException; +import com.github.DNAProject.network.connect.IConnector; +import com.github.DNAProject.network.rest.RestClient; +import com.github.DNAProject.network.rest.Result; +import com.github.DNAProject.network.websocket.WebsocketClient; +import com.github.DNAProject.sdk.exception.SDKException; + +/** + * + */ +public class ConnectMgr { + private IConnector connector; + + public ConnectMgr(String url, String type, Object lock) { + if (type.equals("websocket")) { + setConnector(new WebsocketClient(url, lock)); + } + } + + public ConnectMgr(String url, String type) { + url = url.replace("://localhost","://127.0.0.1"); + if (type.equals("rpc")) { + setConnector(new RpcClient(url)); + } else if (type.equals("restful")) { + setConnector(new RestClient(url)); + } + } + + public void startWebsocketThread(boolean log) { + if (connector instanceof WebsocketClient) { + ((WebsocketClient) connector).startWebsocketThread(log); + } + } + + public void setReqId(long n) { + if (connector instanceof WebsocketClient) { + ((WebsocketClient) connector).setReqId(n); + } + } + + public void send(Map map) { + if (connector instanceof WebsocketClient) { + ((WebsocketClient) connector).send(map); + } + } + + public void sendHeartBeat() { + if (connector instanceof WebsocketClient) { + ((WebsocketClient) connector).sendHeartBeat(); + } + } + + public void sendSubscribe(Map map) { + if (connector instanceof WebsocketClient) { + ((WebsocketClient) connector).sendSubscribe(map); + } + } + + public ConnectMgr(IConnector connector) { + setConnector(connector); + } + + public void setConnector(IConnector connector) { + this.connector = connector; + } + + private String getUrl() { + return connector.getUrl(); + } + + public boolean sendRawTransaction(Transaction tx) throws ConnectorException, IOException { + String rs = (String) connector.sendRawTransaction(Helper.toHexString(tx.toArray())); + if (connector instanceof RpcClient) { + return true; + } + if (connector instanceof WebsocketClient) { + return true; + } + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return true; + } + return false; + } + + public boolean sendRawTransaction(String hexData) throws ConnectorException, IOException { + String rs = (String) connector.sendRawTransaction(hexData); + if (connector instanceof RpcClient) { + return true; + } + if (connector instanceof WebsocketClient) { + return true; + } + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return true; + } + return false; + } + /** + * wait result after send + * @param hexData + * @return + * @throws ConnectorException + * @throws Exception + */ + public Object sendRawTransactionSync(String hexData) throws ConnectorException, Exception { + return syncSendRawTransaction(hexData); + } + + /** + * wait result after send + * @param hexData + * @return + * @throws ConnectorException + * @throws Exception + */ + public Object syncSendRawTransaction(String hexData) throws ConnectorException, Exception { + String rs = (String) connector.sendRawTransaction(hexData); + String hash = Transaction.deserializeFrom(Helper.hexToBytes(hexData)).hash().toString(); + System.out.println("Transaction hash is: " + hash + ", Please waitting result... "); + return waitResult(hash); + } + + public Object sendRawTransactionPreExec(String hexData) throws ConnectorException, IOException { + Object rs = connector.sendRawTransaction(true, null, hexData); + if (connector instanceof RpcClient) { + return rs; + } + if (connector instanceof WebsocketClient) { + return rs; + } + Result rr = JSON.parseObject((String) rs, Result.class); + if (rr.Error == 0) { + return rr.Result; + } + return null; + } + + public Transaction getTransaction(String txhash) throws ConnectorException, IOException { + txhash = txhash.replace("0x", ""); + return connector.getRawTransaction(txhash); + } + + public Object getTransactionJson(String txhash) throws ConnectorException, IOException { + txhash = txhash.replace("0x", ""); + return connector.getRawTransactionJson(txhash); + } + + public int getNodeCount() throws ConnectorException, IOException { + return connector.getNodeCount(); + } + + public int getBlockHeight() throws ConnectorException, IOException { + return connector.getBlockHeight(); + } + + public Block getBlock(int height) throws ConnectorException, IOException, SDKException { + if (height < 0) { + throw new SDKException(ErrorCode.ParamError); + } + return connector.getBlock(height); + } + + public Block getBlock(String hash) throws ConnectorException, IOException { + return connector.getBlock(hash); + + } + + public Object getBalance(String address) throws ConnectorException, IOException { + return connector.getBalance(address); + } + + public Object getBlockJson(int height) throws ConnectorException, IOException { + return connector.getBlockJson(height); + } + + public Object getBlockJson(String hash) throws ConnectorException, IOException { + return connector.getBlockJson(hash); + } + + public Object getContract(String hash) throws ConnectorException, IOException { + hash = hash.replace("0x", ""); + return connector.getContractJson(hash); + } + + public Object getContractJson(String hash) throws ConnectorException, IOException { + hash = hash.replace("0x", ""); + return connector.getContractJson(hash); + } + + public Object getSmartCodeEvent(int height) throws ConnectorException, IOException { + return connector.getSmartCodeEvent(height); + } + + public Object getSmartCodeEvent(String hash) throws ConnectorException, IOException { + return connector.getSmartCodeEvent(hash); + } + + public int getBlockHeightByTxHash(String hash) throws ConnectorException, IOException { + hash = hash.replace("0x", ""); + return connector.getBlockHeightByTxHash(hash); + } + + public String getStorage(String codehash, String key) throws ConnectorException, IOException { + codehash = codehash.replace("0x", ""); + return connector.getStorage(codehash, key); + } + + public Object getMerkleProof(String hash) throws ConnectorException, IOException { + hash = hash.replace("0x", ""); + return connector.getMerkleProof(hash); + } + + public String getAllowance(String asset, String from, String to) throws ConnectorException, IOException { + return connector.getAllowance(asset, from, to); + } + + public Object getMemPoolTxCount() throws ConnectorException, IOException { + return connector.getMemPoolTxCount(); + } + + public Object getMemPoolTxState(String hash) throws ConnectorException, IOException { + hash = hash.replace("0x", ""); + return connector.getMemPoolTxState(hash); + } + public String getVersion() throws ConnectorException, IOException { + return connector.getVersion(); + } + + public String getGrantOng(String address) throws ConnectorException, IOException { + return connector.getGrantOng(address); + } + public int getNetworkId() throws ConnectorException, IOException { + return connector.getNetworkId(); + } + public Object getNodeSyncStatus() throws ConnectorException, IOException { + return connector.getNodeSyncStatus(); + } + public String getSideChainData(String sideChianId) throws ConnectorException, IOException { + return connector.getSideChainData(sideChianId); + } + + public Object waitResult(String hash) throws Exception { + Object objEvent = null; + Object objTxState = null; + int notInpool = 0; + for (int i = 0; i < 20; i++) { + try { + Thread.sleep(3000); + objEvent = connector.getSmartCodeEvent(hash); + if (objEvent == null || objEvent.equals("")) { + Thread.sleep(1000); + objTxState = connector.getMemPoolTxState(hash); + continue; + } + if (((Map) objEvent).get("Notify") != null) { + return objEvent; + } + } catch (Exception e) { + if (e.getMessage().contains("UNKNOWN TRANSACTION") && e.getMessage().contains("getmempooltxstate")) { + notInpool++; + if ((objEvent.equals("") || objEvent == null) && notInpool >1){ + throw new SDKException(e.getMessage()); + } + } else { + continue; + } + } + } + throw new SDKException(ErrorCode.OtherError("time out")); + } +} + + diff --git a/src/main/java/com/github/DNAProject/sdk/manager/ECIES.java b/src/main/java/com/github/DNAProject/sdk/manager/ECIES.java new file mode 100644 index 0000000..e981029 --- /dev/null +++ b/src/main/java/com/github/DNAProject/sdk/manager/ECIES.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.sdk.manager; + +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.crypto.KeyType; +import com.github.DNAProject.crypto.SignatureScheme; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.Digest; +import org.bouncycastle.crypto.digests.SHA1Digest; +import org.bouncycastle.crypto.digests.SHA256Digest; +import org.bouncycastle.crypto.generators.KDF2BytesGenerator; +import org.bouncycastle.crypto.kems.ECIESKeyEncapsulation; +import org.bouncycastle.crypto.params.ECDomainParameters; +import org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import org.bouncycastle.crypto.params.ECPublicKeyParameters; +import org.bouncycastle.crypto.params.KeyParameter; +import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey; +import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey; +import org.bouncycastle.jce.ECNamedCurveTable; +import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; +import org.bouncycastle.util.encoders.Hex; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.security.Key; +import java.security.SecureRandom; + +public class ECIES { + public static KeyType keyType = KeyType.ECDSA; + public static Object[] curveParaSpec = new Object[]{"P-256"}; + public static SignatureScheme signatureScheme = SignatureScheme.SHA256WITHECDSA; + public static Digest defaultDigest = new SHA256Digest(); + public ECIES(Digest dig){ + defaultDigest = dig; + } + public static void setDigest(Digest dig){ + defaultDigest = dig; + } + public static String[] Encrypt(String pubkey, byte[] msg) throws Exception{ + return Encrypt(pubkey, msg, 32); + } + + //keylen: 16/24/32 + public static String[] Encrypt(String pubkey, byte[] msg, int keylen) throws Exception{ + try { + com.github.DNAProject.account.Account account = new com.github.DNAProject.account.Account(false, Helper.hexToBytes(pubkey)); + + ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec((String) curveParaSpec[0]); + ECDomainParameters ecDomain = new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN()); + AsymmetricCipherKeyPair keys = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters(((BCECPublicKey) account.getPublicKey()).getQ(), ecDomain), null); + + byte[] out = new byte[(ecDomain.getCurve().getFieldSize() / 8) * 2 + 1]; + ECIESKeyEncapsulation kem = new ECIESKeyEncapsulation(new KDF2BytesGenerator(defaultDigest), new SecureRandom()); + KeyParameter key1; + + kem.init(keys.getPublic()); + key1 = (KeyParameter) kem.encrypt(out, keylen); //AES key = key1 (is encrypted in out) + + byte[] IV = Hex.decode(getRandomString(keylen)); //choose random IV of length = keylen + byte[] ciphertext; + try { + Cipher en = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC"); + Key key = new SecretKeySpec(key1.getKey(), "AES"); + en.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(IV)); + ciphertext = en.doFinal(msg); + } catch (Exception e) { + throw new Exception("AES failed initialisation - " + e.toString(), e); + } + //(IV, out, ciphertext) + return new String[]{Helper.toHexString(IV), Helper.toHexString(out), Helper.toHexString(ciphertext)}; + } catch (Exception e) { + throw new Exception("Encrypt failed initialisation - " + e.toString(), e); + } + } + + public static byte[] Decrypt(Account account, String[] params) throws Exception { + if (params.length != 3) { + throw new Exception(ErrorCode.ParamError); + } + return Decrypt(account.serializePrivateKey(), Helper.hexToBytes(params[0]), Helper.hexToBytes(params[1]), Helper.hexToBytes(params[2]), 32); + } + + public static byte[] Decrypt(String prikey, String[] params) throws Exception { + if (params.length != 3) { + throw new Exception(ErrorCode.ParamError); + } + return Decrypt(Helper.hexToBytes(prikey), Helper.hexToBytes(params[0]), Helper.hexToBytes(params[1]), Helper.hexToBytes(params[2]), 32); + } + + public static byte[] Decrypt(byte[] prikey, byte[] IV, byte[] key_cxt, byte[] ciphertext) throws Exception { + return Decrypt(prikey, IV, key_cxt, ciphertext, 32); + } + + public static byte[] Decrypt(byte[] prikey, byte[] IV, byte[] key_cxt, byte[] ciphertext, int keylen) throws Exception { + try { + com.github.DNAProject.account.Account account = new com.github.DNAProject.account.Account(prikey, signatureScheme); + + ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec((String) curveParaSpec[0]); + ECDomainParameters ecDomain = new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN()); + AsymmetricCipherKeyPair keys = new AsymmetricCipherKeyPair( + null, + new ECPrivateKeyParameters(((BCECPrivateKey) account.getPrivateKey()).getD(), ecDomain)); + + byte[] out = key_cxt; + ECIESKeyEncapsulation kem = new ECIESKeyEncapsulation(new KDF2BytesGenerator(defaultDigest), new SecureRandom()); + + KeyParameter key1; + + kem.init(keys.getPrivate()); + key1 = (KeyParameter) kem.decrypt(out, keylen); + + byte[] plaintext; + try { + Cipher dec = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC"); + Key key = new SecretKeySpec(key1.getKey(), "AES"); + dec.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(IV)); + plaintext = dec.doFinal(ciphertext); + } catch (Exception e) { + throw new Exception("AES failed initialisation - " + e.toString(), e); + } + return plaintext; + } catch (Exception e) { + throw new Exception("AES failed initialisation - " + e.toString(), e); + } + } + + public static String getRandomString(int length) { + String KeyStr = "ABCDEF0123456789"; + StringBuffer sb = new StringBuffer(); + int len = KeyStr.length(); + for (int i = 0; i < length; i++) { + sb.append(KeyStr.charAt((int) Math.round(Math.random() * (len - 1)))); + } + return sb.toString(); + } +} diff --git a/src/main/java/com/github/DNAProject/sdk/manager/SignServer.java b/src/main/java/com/github/DNAProject/sdk/manager/SignServer.java new file mode 100644 index 0000000..423063e --- /dev/null +++ b/src/main/java/com/github/DNAProject/sdk/manager/SignServer.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.sdk.manager; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.network.exception.RpcException; +import com.github.DNAProject.network.rpc.Interfaces; + +import java.util.HashMap; +import java.util.Map; + +public class SignServer { + private Interfaces rpcClient; + private String url = ""; + + public SignServer(String url) throws Exception { + this.url = url; + rpcClient = new Interfaces(url); + } + + public Object sendSigRawTx(String rawTx) throws Exception { + Map req = new HashMap(); + req.put("jsonrpc", "2.0"); + req.put("method", "sigrawtx"); + Map params = new HashMap(); + params.put("raw_tx", rawTx); + req.put("params", params); + req.put("id", 1); + return send(req); + } + + public Object sendMultiSigRawTx(String rawTx, int m, String[] pubkeys) throws Exception { + Map req = new HashMap(); + req.put("jsonrpc", "2.0"); + req.put("method", "sigmutilrawtx"); + Map params = new HashMap(); + params.put("raw_tx", rawTx); + params.put("m", m); + params.put("pub_keys", pubkeys); + req.put("params", params); + req.put("id", 1); + return send(req); + } + + public Object sendSigTransferTx(String asset, String from, String to, long amount, long gasLimit, long gasPrice) throws Exception { + Map req = new HashMap(); + req.put("jsonrpc", "2.0"); + req.put("method", "sigtransfertx"); + Map params = new HashMap(); + params.put("asset", asset); + params.put("from", from); + params.put("to", to); + params.put("amount", amount); + params.put("gas_limit", gasLimit); + params.put("gas_price", gasPrice); + req.put("params", params); + req.put("id", 1); + return send(req); + } + + public Object sendSigNativeInvokeTx(String contractAddr, String method, int version, long gasLimit, long gasPrice, Map parameters) throws Exception { + Map req = new HashMap(); + req.put("jsonrpc", "2.0"); + req.put("method", "sigtransfertx"); + Map params = new HashMap(); + params.put("address", contractAddr); + params.put("method", method); + params.put("version", version); + params.put("gas_limit", gasLimit); + params.put("gas_price", gasPrice); + params.put("params", parameters); + req.put("params", params); + req.put("id", 1); + return send(req); + } + + public Object sendSigNeoInvokeTx(String contractAddr, int version, long gasLimit, long gasPrice, Map parameters) throws Exception { + Map req = new HashMap(); + req.put("jsonrpc", "2.0"); + req.put("method", "sigtransfertx"); + Map params = new HashMap(); + params.put("address", contractAddr); + params.put("version", version); + params.put("gas_limit", gasLimit); + params.put("gas_price", gasPrice); + params.put("params", parameters); + req.put("params", params); + req.put("id", 1); + return send(req); + } + + private Object send(Map req) throws Exception { + Map response = (Map) rpcClient.send(req); + System.out.println(response); + if (response == null) { + throw new RpcException(0, ErrorCode.ConnectUrlErr(url + "response is null. maybe is connect error")); + } else if ((int) response.get("error_code") == 0) { + return response.get("result"); + } else { + throw new RpcException(0, JSON.toJSONString(response)); + } + } +} diff --git a/src/main/java/com/github/DNAProject/sdk/manager/WalletMgr.java b/src/main/java/com/github/DNAProject/sdk/manager/WalletMgr.java new file mode 100644 index 0000000..b41d3aa --- /dev/null +++ b/src/main/java/com/github/DNAProject/sdk/manager/WalletMgr.java @@ -0,0 +1,422 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.sdk.manager; + +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.crypto.*; +import com.github.DNAProject.sdk.exception.*; +import com.github.DNAProject.sdk.info.AccountInfo; +import com.github.DNAProject.sdk.info.IdentityInfo; +import com.github.DNAProject.sdk.wallet.Account; +import com.github.DNAProject.sdk.wallet.Control; +import com.github.DNAProject.sdk.wallet.Identity; +import com.github.DNAProject.sdk.wallet.Wallet; +import com.github.DNAProject.common.Common; +import com.alibaba.fastjson.JSON; + +import java.io.*; +import java.security.SecureRandom; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * + */ +public class WalletMgr { + private Wallet walletInMem; + private Wallet walletFile; + private SignatureScheme scheme = null; + private String filePath = null; + public WalletMgr(Wallet wallet,SignatureScheme scheme) throws Exception { + this.scheme = scheme; + this.walletInMem = wallet; + this.walletFile = wallet; + } + public WalletMgr(String path, SignatureScheme scheme) throws Exception { + this.scheme = scheme; + this.filePath = path; + File file = new File(filePath); + if (!file.exists()) { + walletInMem = new Wallet(); + walletInMem.setCreateTime(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(new Date())); + walletFile = new Wallet(); + file.createNewFile(); + writeWallet(); + } + InputStream inputStream = new FileInputStream(filePath); + byte[] bytes = new byte[inputStream.available()]; + inputStream.read(bytes); + String text = new String(bytes); + walletInMem = JSON.parseObject(text, Wallet.class); + walletFile = JSON.parseObject(text, Wallet.class); + if (walletInMem.getIdentities() == null) { + walletInMem.setIdentities(new ArrayList()); + } + if (walletInMem.getAccounts() == null) { + walletInMem.setAccounts(new ArrayList()); + } + writeWallet(); + } + + private WalletMgr(String path, String label, String password, SignatureScheme scheme) throws Exception { + this.scheme = scheme; + this.filePath = path; + File file = new File(filePath); + if (!file.exists()) { + walletInMem = new Wallet(); + walletInMem.setCreateTime(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'").format(new Date())); + walletFile = new Wallet(); + file.createNewFile(); + createIdentity(label, password); + writeWallet(); + } + InputStream inputStream = new FileInputStream(filePath); + byte[] bytes = new byte[inputStream.available()]; + inputStream.read(bytes); + String text = new String(bytes); + walletInMem = JSON.parseObject(text, Wallet.class); + walletFile = JSON.parseObject(text, Wallet.class); + if (walletInMem.getIdentities() == null) { + walletInMem.setIdentities(new ArrayList()); + } + if (walletInMem.getAccounts() == null) { + walletInMem.setAccounts(new ArrayList()); + } + if (walletInMem.getIdentities().size() == 0) { + createIdentity(label, password); + writeWallet(); + } + } + + private static void writeFile(String filePath, String sets) throws IOException { + FileWriter fw = new FileWriter(filePath); + PrintWriter out = new PrintWriter(fw); + out.write(sets); + out.println(); + fw.close(); + out.close(); + } + + /** + * + * @return wallet file data + */ + public Wallet getWalletFile() { + return walletFile; + } + + /** + * + * @return wallet in memory + */ + public Wallet getWallet() { + return walletInMem; + } + + /** + * wallet in memory = wallet file data + * @return + */ + public Wallet resetWallet() { + walletInMem = walletFile.clone(); + return walletInMem; + } + public Wallet saveWallet() throws Exception { + return writeWallet(); + } + public Wallet writeWallet() throws Exception { + writeFile(filePath, JSON.toJSONString(walletInMem)); + walletFile = walletInMem.clone(); + return walletFile; + } + + public SignatureScheme getSignatureScheme() { + return scheme; + } + + public void setSignatureScheme(SignatureScheme scheme) { + this.scheme = scheme; + } + + public Identity importIdentity(String encryptedPrikey, String password,byte[] salt, String address) throws Exception { + return importIdentity("",encryptedPrikey,password,salt,address); + } + public Identity importIdentity(String label,String encryptedPrikey, String password,byte[] salt, String address) throws Exception { + String prikey = com.github.DNAProject.account.Account.getGcmDecodedPrivateKey(encryptedPrikey, password, address,salt, walletFile.getScrypt().getN(), scheme); + IdentityInfo info = createIdentity(label,password,salt, Helper.hexToBytes(prikey)); + prikey = null; + return getWallet().getIdentity(info.dnaid); + } + + + public Identity createIdentity(String password) throws Exception { + return createIdentity("",password); + } + public Identity createIdentity(String label,String password) throws Exception { + IdentityInfo info = createIdentity(label,password, ECC.generateKey()); + return getWallet().getIdentity(info.dnaid); + } + + public Identity createIdentityFromPriKey(String label,String password, String prikey) throws Exception { + IdentityInfo info = createIdentity(label,password, Helper.hexToBytes(prikey)); + return getWallet().getIdentity(info.dnaid); + } + + public Identity createIdentityFromPriKey(String password, String prikey) throws Exception { + IdentityInfo info = createIdentity("", password, Helper.hexToBytes(prikey)); + prikey = null; + return getWallet().getIdentity(info.dnaid); + } + + public IdentityInfo createIdentityInfo(String password) throws Exception { + return createIdentityInfo("",password); + } + public IdentityInfo createIdentityInfo(String label,String password) throws Exception { + IdentityInfo info = createIdentity(label,password, ECC.generateKey()); + return info; + } + + + public IdentityInfo getIdentityInfo(String dnaid, String password,byte[] salt) throws Exception { + com.github.DNAProject.account.Account acct = getAccountByAddressOrDnaId(dnaid, password,salt); + IdentityInfo info = new IdentityInfo(); + info.dnaid = Common.diddna + Address.addressFromPubKey(acct.serializePublicKey()).toBase58(); + info.pubkey = Helper.toHexString(acct.serializePublicKey()); + info.setPrikey(Helper.toHexString(acct.serializePrivateKey())); + info.setPriwif(acct.exportWif()); + info.encryptedPrikey = acct.exportGcmEncryptedPrikey(password, salt,walletFile.getScrypt().getN()); + info.addressU160 = acct.getAddressU160().toString(); + return info; + } + + private IdentityInfo createIdentity(String label,String password, byte[] prikey) throws Exception { + byte[] salt = ECC.generateKey(16); + return createIdentity(label,password,salt,prikey); + } + private IdentityInfo createIdentity(String label,String password,byte[] salt, byte[] prikey) throws Exception { + com.github.DNAProject.account.Account acct = createAccount(label,password,salt, prikey, false); + IdentityInfo info = new IdentityInfo(); + info.dnaid = Common.diddna + Address.addressFromPubKey(acct.serializePublicKey()).toBase58(); + info.pubkey = Helper.toHexString(acct.serializePublicKey()); + info.setPrikey(Helper.toHexString(acct.serializePrivateKey())); + info.setPriwif(acct.exportWif()); + info.encryptedPrikey = acct.exportGcmEncryptedPrikey(password, salt,walletFile.getScrypt().getN()); + info.addressU160 = acct.getAddressU160().toHexString(); + return info; + } + public Account importAccount(String encryptedPrikey, String password, String address,byte[] salt) throws Exception { + return importAccount("",encryptedPrikey,password,address,salt); + } + + public Account importAccount(String label,String encryptedPrikey, String password, String address,byte[] salt) throws Exception { + String prikey = com.github.DNAProject.account.Account.getGcmDecodedPrivateKey(encryptedPrikey, password, address,salt, walletFile.getScrypt().getN(), scheme); + AccountInfo info = createAccountInfo(label,password, salt,Helper.hexToBytes(prikey)); + prikey = null; + password = null; + return getWallet().getAccount(info.addressBase58); + } + + public void createAccounts(int count, String password) throws Exception { + for (int i = 0; i < count; i++) { + createAccount("", password); + } + } + public Account createAccount(String password) throws Exception { + Account account = createAccount("", password); + return account; + } + public Account createAccount(String label,String password) throws Exception { + AccountInfo info = createAccountInfo(label,password, ECC.generateKey()); + return getWallet().getAccount(info.addressBase58); + } + private AccountInfo createAccountInfo(String label,String password,byte[] prikey) throws Exception { + byte[] salt = ECC.generateKey(16); + return createAccountInfo(label,password,salt,prikey); + } + + private AccountInfo createAccountInfo(String label,String password,byte[] salt, byte[] prikey) throws Exception { + com.github.DNAProject.account.Account acct = createAccount(label,password,salt, prikey, true); + new SecureRandom().nextBytes(prikey); + AccountInfo info = new AccountInfo(); + info.addressBase58 = Address.addressFromPubKey(acct.serializePublicKey()).toBase58(); + info.pubkey = Helper.toHexString(acct.serializePublicKey()); + info.setPrikey(Helper.toHexString(acct.serializePrivateKey())); + info.setPriwif(acct.exportWif()); + info.encryptedPrikey = acct.exportGcmEncryptedPrikey(password, salt,walletFile.getScrypt().getN()); + info.addressU160 = acct.getAddressU160().toHexString(); + return info; + } + + public Account createAccountFromPriKey(String password, String prikey) throws Exception { + AccountInfo info = createAccountInfo("",password, Helper.hexToBytes(prikey)); + return getWallet().getAccount(info.addressBase58); + } + public Account createAccountFromPriKey(String label,String password, String prikey) throws Exception { + AccountInfo info = createAccountInfo(label,password, Helper.hexToBytes(prikey)); + return getWallet().getAccount(info.addressBase58); + } + public AccountInfo createAccountInfo(String password) throws Exception { + return createAccountInfo("",password); + } + public AccountInfo createAccountInfo(String label,String password) throws Exception { + AccountInfo info = createAccountInfo(label,password, ECC.generateKey()); + return info; + } + public AccountInfo createAccountInfoFromPriKey(String password, String prikey) throws Exception { + return createAccountInfo("",password, Helper.hexToBytes(prikey)); + } + public AccountInfo createAccountInfoFromPriKey(String label,String password, String prikey) throws Exception { + return createAccountInfo(label,password, Helper.hexToBytes(prikey)); + } + + public IdentityInfo createIdentityInfoFromPriKey(String label,String password, String prikey) throws Exception { + return createIdentity(label,password, Helper.hexToBytes(prikey)); + } + + public String privateKeyToWif(String privateKey) throws Exception { + com.github.DNAProject.account.Account act = new com.github.DNAProject.account.Account(Helper.hexToBytes(privateKey), scheme); + return act.exportWif(); + } + public com.github.DNAProject.account.Account getAccount(String address, String password) throws Exception { + return getAccount(address, password,getWallet().getAccount(address).getSalt()); + } + public com.github.DNAProject.account.Account getAccount(String addressOrDnaId, String password, byte[] salt) throws Exception { + return getAccountByAddressOrDnaId(addressOrDnaId, password,salt); + } + + public AccountInfo getAccountInfo(String addressOrDnaId, String password,byte[] salt) throws Exception { + AccountInfo info = new AccountInfo(); + com.github.DNAProject.account.Account acc = getAccountByAddressOrDnaId(addressOrDnaId, password,salt); + info.addressBase58 = addressOrDnaId.replace(Common.diddna, ""); + info.pubkey = Helper.toHexString(acc.serializePublicKey()); + info.setPrikey(Helper.toHexString(acc.serializePrivateKey())); + info.encryptedPrikey = acc.exportGcmEncryptedPrikey(password,salt, walletFile.getScrypt().getN()); + info.setPriwif(acc.exportWif()); + info.addressU160 = acc.getAddressU160().toString(); + return info; + } + + + private com.github.DNAProject.account.Account createAccount(String label, String password, byte[] salt, byte[] privateKey, boolean accountFlag) throws Exception { + com.github.DNAProject.account.Account account = new com.github.DNAProject.account.Account(privateKey, scheme); + Account acct; + switch (scheme) { + case SHA256WITHECDSA: + acct = new Account("ECDSA", new Object[]{Curve.P256.toString()}, "aes-256-gcm", "SHA256withECDSA", "sha256"); + break; + case SM3WITHSM2: + acct = new Account("SM2", new Object[]{Curve.SM2P256V1.toString()}, "aes-256-gcm", "SM3withSM2", "sha256"); + break; + default: + throw new SDKException(ErrorCode.OtherError("scheme type error")); + } + if (password != null) { + acct.key = account.exportGcmEncryptedPrikey(password,salt, walletFile.getScrypt().getN()); + password = null; + } else { + acct.key = Helper.toHexString(account.serializePrivateKey()); + } + acct.address = Address.addressFromPubKey(account.serializePublicKey()).toBase58(); + if (label == null || label.equals("")) { + String uuidStr = UUID.randomUUID().toString(); + label = uuidStr.substring(0, 8); + } + if (accountFlag) { + for (Account e : walletInMem.getAccounts()) { + if (e.address.equals(acct.address)) { + throw new SDKException(ErrorCode.ParamErr("wallet account exist")); + } + } + if (walletInMem.getAccounts().size() == 0) { + acct.isDefault = true; + walletInMem.setDefaultAccountAddress(acct.address); + } + acct.label = label; + acct.setSalt(salt); + acct.setPublicKey(Helper.toHexString(account.serializePublicKey())); + walletInMem.getAccounts().add(acct); + } else { + for (Identity e : walletInMem.getIdentities()) { + if (e.dnaid.equals(Common.diddna + acct.address)) { + throw new SDKException(ErrorCode.ParamErr("wallet Identity exist")); + } + } + Identity idt = new Identity(); + idt.dnaid = Common.diddna + acct.address; + idt.label = label; + if (walletInMem.getIdentities().size() == 0) { + idt.isDefault = true; + walletInMem.setDefaultDnaid(idt.dnaid); + } + idt.controls = new ArrayList(); + Control ctl = new Control(acct.key, "keys-1",Helper.toHexString(account.serializePublicKey())); + ctl.setSalt(salt); + ctl.setAddress(acct.address); + idt.controls.add(ctl); + walletInMem.getIdentities().add(idt); + } + return account; + } + + private com.github.DNAProject.account.Account getAccountByAddressOrDnaId(String addressOrDnaId, String password, byte[] salt) throws Exception { + try { + if(addressOrDnaId.startsWith(Common.diddna)){ + for (Identity e : walletInMem.getIdentities()) { + if (e.dnaid.equals(addressOrDnaId)) { + String addr = e.dnaid.replace(Common.diddna, ""); + String prikey = com.github.DNAProject.account.Account.getGcmDecodedPrivateKey(e.controls.get(0).key, password, addr,salt, walletFile.getScrypt().getN(), scheme); + return new com.github.DNAProject.account.Account(Helper.hexToBytes(prikey), scheme); + } + } + }else { + for (Account e : walletInMem.getAccounts()) { + if (e.address.equals(addressOrDnaId)) { + String prikey = com.github.DNAProject.account.Account.getGcmDecodedPrivateKey(e.key, password, e.address,salt, walletFile.getScrypt().getN(), scheme); + return new com.github.DNAProject.account.Account(Helper.hexToBytes(prikey), scheme); + } + } + } + + } catch (Exception e) { + throw new SDKException(ErrorCode.OtherError(e.getMessage())); + } + throw new SDKException(ErrorCode.OtherError("Account null")); + } + + + public Identity getDefaultIdentity() { + for (Identity e : getWallet().getIdentities()) { + if (e.isDefault) { + return e; + } + } + return null; + } + public Account getDefaultAccount() { + for (Account e : getWallet().getAccounts()) { + if (e.isDefault) { + return e; + } + } + return null; + } +} diff --git a/src/main/java/com/github/DNAProject/sdk/wallet/Account.java b/src/main/java/com/github/DNAProject/sdk/wallet/Account.java new file mode 100644 index 0000000..b55bf34 --- /dev/null +++ b/src/main/java/com/github/DNAProject/sdk/wallet/Account.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.sdk.wallet; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONField; + +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +/** + * + */ +public class Account { + public String label = ""; + public String address = ""; + public boolean isDefault = false; + public boolean lock = false; + public String algorithm = ""; + public Map parameters = new HashMap() ; + public String key = ""; + @JSONField(name = "enc-alg") + public String encAlg = "aes-256-gcm"; + public String salt = ""; + public String hash = "sha256"; + public String publicKey = ""; + public String signatureScheme = "SHA256withECDSA"; + public Object extra = null; + public Account(){ + + } + public Account(String alg,Object[] params,String encAlg,String scheme,String hash){ + this.algorithm = alg; + this.parameters.put("curve",params[0]); + this.signatureScheme = scheme; + this.encAlg = encAlg; + this.hash = hash; + this.extra = null; + } + + public Object getExtra(){ + return extra; + } + + public void setExtra(Object extra){ + this.extra = extra; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public String getEncAlg(){ + return encAlg; + } + public void setEncAlg(String encAlg){ + this.encAlg = encAlg; + } + public String getHash(){ + return hash; + } + + public void setHash(String hash) { + this.hash = hash; + } + + public byte[] getSalt(){ + return Base64.getDecoder().decode(salt); + } + public void setSalt(byte[] salt){ + this.salt = new String(Base64.getEncoder().encode(salt)); + } + public String getPublicKey(){ + return publicKey; + } + public void setPublicKey(String pk){ + this.publicKey = pk; + } + @Override + public String toString() { + return JSON.toJSONString(this); + } + + +} + diff --git a/src/main/java/com/github/DNAProject/sdk/wallet/Control.java b/src/main/java/com/github/DNAProject/sdk/wallet/Control.java new file mode 100644 index 0000000..e32e41a --- /dev/null +++ b/src/main/java/com/github/DNAProject/sdk/wallet/Control.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.sdk.wallet; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONField; + +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +public class Control { + public String algorithm = "ECDSA"; + public Map parameters = new HashMap() ; + public String id = ""; + public String key = ""; + public String salt = ""; + public String hash = "sha256"; + @JSONField(name = "enc-alg") + public String encAlg = "aes-256-gcm"; + public String address = ""; + public String publicKey = ""; + public Control(){ + + } + public Control(String key,String id,String pubkey){ + this.key = key; + this.algorithm = "ECDSA"; + this.id = id; + this.publicKey = pubkey; + this.parameters.put("curve","P-256"); + } + public String getEncAlg(){ + return encAlg; + } + public void setEncAlg(String encAlg){ + this.encAlg = encAlg; + } + public byte[] getSalt(){ + return Base64.getDecoder().decode(salt); + } + public void setSalt(byte[] salt){ + this.salt = new String(Base64.getEncoder().encode(salt)); + } + public String getAddress(){ + return address; + } + public void setAddress(String address){ + this.address = address; + } + public String getPublicKey(){ + return publicKey; + } + public void setPublicKey(String pk){ + this.publicKey = pk; + } + @Override + public String toString() { + return JSON.toJSONString(this); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/sdk/wallet/Identity.java b/src/main/java/com/github/DNAProject/sdk/wallet/Identity.java new file mode 100644 index 0000000..e32b3bf --- /dev/null +++ b/src/main/java/com/github/DNAProject/sdk/wallet/Identity.java @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.sdk.wallet; + +import com.alibaba.fastjson.JSON; + +import java.util.ArrayList; +import java.util.List; + +/** + * + */ +public class Identity { + public String label = ""; + public String dnaid = ""; + public boolean isDefault = false; + public boolean lock = false; + public List controls = new ArrayList(); + public Object extra = null; + + public Object getExtra(){ + return extra; + } + public void setExtra(Object extra){ + this.extra = extra; + } + @Override + public String toString() { + return JSON.toJSONString(this); + } +} + diff --git a/src/main/java/com/github/DNAProject/sdk/wallet/Scrypt.java b/src/main/java/com/github/DNAProject/sdk/wallet/Scrypt.java new file mode 100644 index 0000000..edd9adc --- /dev/null +++ b/src/main/java/com/github/DNAProject/sdk/wallet/Scrypt.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.sdk.wallet; + +import com.alibaba.fastjson.JSON; + +/** + */ +public class Scrypt implements Cloneable{ + private int n = 16384; + private int r = 8; + private int p = 8; + private int DkLen = 64; + private String Salt; + + public int getDkLen() { + return DkLen; + } + + public void setDkLen(int dkLen) { + DkLen = dkLen; + } + + + public Scrypt() { + } + + public Scrypt(int n, int r, int p) { + this.n = n; + this.r = r; + this.p = p; + } + + public int getN() { + return n; + } + + public void setN(int n) { + this.n = n; + } + + public int getR() { + return r; + } + + public void setR(int r) { + this.r = r; + } + + public int getP() { + return p; + } + + public void setP(int p) { + this.p = p; + } + + @Override + public Scrypt clone() { + Scrypt o = null; + try { + o = (Scrypt) super.clone(); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + return o; + } + @Override + public String toString() { + return JSON.toJSONString(this); + } +} diff --git a/src/main/java/com/github/DNAProject/sdk/wallet/Wallet.java b/src/main/java/com/github/DNAProject/sdk/wallet/Wallet.java new file mode 100644 index 0000000..d9693f0 --- /dev/null +++ b/src/main/java/com/github/DNAProject/sdk/wallet/Wallet.java @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.sdk.wallet; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.sdk.exception.SDKException; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * + */ +public class Wallet implements Cloneable { + private String name = "com.github.DNAProject"; + private String version = "1.0"; + private String createTime = ""; + private String defaultDnaid = ""; + private String defaultAccountAddress = ""; + private Scrypt scrypt = new Scrypt(); + private Object extra = null; + private List identities = new ArrayList(); + private List accounts = new ArrayList(); + + public Wallet() { + identities.clear(); + } + + public Object getExtra() { + return extra; + } + + public void setExtra(Object extra) { + this.extra = extra; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDefaultDnaid() { + return defaultDnaid; + } + + public void setDefaultDnaid(String defaultDnaid) { + this.defaultDnaid = defaultDnaid; + } + + public String getCreateTime() { + return createTime; + } + + public void setCreateTime(String createTime) { + this.createTime = createTime; + } + + public String getDefaultAccountAddress() { + return defaultAccountAddress; + } + + public void setDefaultAccountAddress(String defaultAccountAddress) { + this.defaultAccountAddress = defaultAccountAddress; + } + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public Scrypt getScrypt() { + return scrypt; + } + + public void setScrypt(Scrypt scrypt) { + this.scrypt = scrypt; + } + + public List getIdentities() { + return identities; + } + + public void setIdentities(List identityList) { + this.identities = identityList; + } + + public List getAccounts() { + return accounts; + } + + public void setAccounts(List accountList) { + this.accounts = accountList; + } + + public boolean removeAccount(String address) { + for (Account e : accounts) { + if (e.address.equals(address)) { + accounts = new ArrayList(accounts); + accounts.remove(e); + return true; + } + } + return false; + } + public boolean clearAccount() { + accounts = new ArrayList(); + return true; + } + + public Account getAccount(String address) { + for (Account e : accounts) { + if (e.address.equals(address)) { + return e; + } + } + return null; + } + + public boolean removeIdentity(String dnaid) { + for (Identity e : identities) { + if (e.dnaid.equals(dnaid)) { + identities = new ArrayList(identities); + identities.remove(e); + return true; + } + } + return false; + } + + public boolean clearIdentity() { + identities = new ArrayList(); + return true; + } + + public Identity getIdentity(String dnaid) { + for (Identity e : identities) { + if (e.dnaid.equals(dnaid)) { + return e; + } + } + return null; + } + + public void setDefaultAccount(int index) throws Exception { + if (index >= accounts.size()) { + throw new SDKException(ErrorCode.ParamError); + } + for (Account e : accounts) { + e.isDefault = false; + } + accounts.get(index).isDefault = true; + defaultAccountAddress = accounts.get(index).address; + } + + public void setDefaultAccount(String address) { + for (Account e : accounts) { + if (e.address.equals(address)) { + e.isDefault = true; + defaultAccountAddress = address; + } else { + e.isDefault = false; + } + } + } + + public void setDefaultIdentity(int index) throws Exception { + if (index >= identities.size()) { + throw new SDKException(ErrorCode.ParamError); + } + for (Identity e : identities) { + e.isDefault = false; + } + identities.get(index).isDefault = true; + defaultDnaid = identities.get(index).dnaid; + } + + public void setDefaultIdentity(String dnaid) { + for (Identity e : identities) { + if (e.dnaid.equals(dnaid)) { + e.isDefault = true; + defaultDnaid = dnaid; + } else { + e.isDefault = false; + } + } + } + + private Identity addIdentity(String dnaid) { + for (Identity e : getIdentities()) { + if (e.dnaid.equals(dnaid)) { + return e; + } + } + Identity identity = new Identity(); + identity.dnaid = dnaid; + identity.controls = new ArrayList(); + getIdentities().add(identity); + return identity; + } + + private void addIdentity(Identity idt) { + for (Identity e : getIdentities()) { + if (e.dnaid.equals(idt.dnaid)) { + return; + } + } + getIdentities().add(idt); + } + public Identity addDnaIdController(String dnaid, String key, String id,String pubkey) { + Identity identity = getIdentity(dnaid); + if (identity == null) { + identity = addIdentity(dnaid); + } + for (Control e : identity.controls) { + if (e.key.equals(key)) { + return identity; + } + } + Control control = new Control(key, id,pubkey); + identity.controls.add(control); + return identity; + } + @Override + public Wallet clone() { + Wallet o = null; + try { + o = (Wallet) super.clone(); + Account[] srcAccounts = o.accounts.toArray(new Account[0]); + Account[] destAccounts = new Account[srcAccounts.length]; + System.arraycopy(srcAccounts, 0, destAccounts, 0, srcAccounts.length); + o.accounts = Arrays.asList(destAccounts); + + Identity[] srcIdentitys = o.identities.toArray(new Identity[0]); + Identity[] destIdentitys = new Identity[srcIdentitys.length]; + System.arraycopy(srcIdentitys, 0, destIdentitys, 0, srcIdentitys.length); + o.identities = Arrays.asList(destIdentitys); + + o.scrypt = (Scrypt)o.scrypt.clone(); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + + return o; + } + @Override + public String toString() { + return JSON.toJSONString(this); + } +} diff --git a/src/main/java/example/ECIESDemo.java b/src/main/java/example/ECIESDemo.java new file mode 100644 index 0000000..294a968 --- /dev/null +++ b/src/main/java/example/ECIESDemo.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package example; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.sdk.manager.ECIES; +import org.bouncycastle.crypto.digests.SHA256Digest; + +/** + * + */ +public class ECIESDemo { + public static void main(String[] args) { + + try { + DnaSdk dnaSdk = getDnaSdk(); + + com.github.DNAProject.account.Account account = new com.github.DNAProject.account.Account(Helper.hexToBytes("9a31d585431ce0aa0aab1f0a432142e98a92afccb7bcbcaff53f758df82acdb3"), dnaSdk.defaultSignScheme); + System.out.println("PrivateKey:"+Helper.toHexString(account.serializePrivateKey())); + System.out.println("PublicKey:"+Helper.toHexString(account.serializePublicKey())); +// System.out.println(Helper.toHexString(account.serializePrivateKey())); + + //setDigest + ECIES.setDigest(new SHA256Digest()); + byte[] msg = new String("1234567890").getBytes(); + String[] ret = ECIES.Encrypt(Helper.toHexString(account.serializePublicKey()),msg); + byte[] msg2 = ECIES.Decrypt(Helper.toHexString(account.serializePrivateKey()),ret); +// byte[] msg3 = ECIES.Decrypt(account,ret); + System.out.println("Msg:"+Helper.toHexString(msg)); + System.out.println("Encrypted:"+JSON.toJSONString(ret)); + System.out.println("Decrypt:"+Helper.toHexString(msg2)); +// System.out.println(Helper.toHexString(msg3)); + + } catch (Exception e) { + e.printStackTrace(); + } + + } + + public static DnaSdk getDnaSdk() throws Exception { + String ip = "http://127.0.0.1"; +// String ip = "http://54.222.182.88; +// String ip = "http://101.132.193.149"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRestful()); + + wm.openWalletFile("Demo3.json"); + + return wm; + } +} diff --git a/src/main/java/example/MnemonicDemo.java b/src/main/java/example/MnemonicDemo.java new file mode 100644 index 0000000..b03fbe9 --- /dev/null +++ b/src/main/java/example/MnemonicDemo.java @@ -0,0 +1,50 @@ +package example; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.common.WalletQR; +import com.github.DNAProject.crypto.MnemonicCode; +import com.github.DNAProject.crypto.SignatureScheme; +import com.github.DNAProject.sdk.wallet.Scrypt; + +import java.util.Map; + +/** + * + * + */ +public class MnemonicDemo { + public static void main(String[] args) { + + try { + //Mnemonic Codes + String code = MnemonicCode.generateMnemonicCodesStr(); + + //get prikey from FromMnemonicCodes + byte[] prikey = MnemonicCode.getPrikeyFromMnemonicCodesStrBip44(code); + System.out.println(Helper.toHexString(prikey)); + + //get keystore + Scrypt scrypt = new Scrypt(); + com.github.DNAProject.sdk.wallet.Account account = new com.github.DNAProject.sdk.wallet.Account(); + //TODO change scrypt and account value + Map keystore = WalletQR.exportAccountQRCode(scrypt,account); + System.out.println(JSON.toJSONString(keystore)); + + //import keystore + String prikey2 = WalletQR.getPriKeyFromQrCode(JSON.toJSONString(keystore),"password"); + + //import from WIF + byte[] prikey3 = Account.getPrivateKeyFromWIF(""); + + //create account or from prikey + Account acct = new Account(SignatureScheme.SHA256WITHECDSA); + Account acct2 = new Account(prikey3,SignatureScheme.SHA256WITHECDSA); + + //WalletQR.exportAccountQRCode() + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/example/api/ApiDemo.java b/src/main/java/example/api/ApiDemo.java new file mode 100644 index 0000000..ffe1acf --- /dev/null +++ b/src/main/java/example/api/ApiDemo.java @@ -0,0 +1,38 @@ +package example.api; + +import com.github.DNAProject.DnaSdk; + +/** + * @Description: + * @date 2019/12/12 + */ +public class ApiDemo { + + public static void main(String[] args) { + + try { + DnaSdk dnaSdk = getDnaSdk(); + if (true) { + System.out.println(dnaSdk.getConnect().getBalance("AHX1wzvdw9Yipk7E9MuLY4GGX4Ym9tHeDe")); + System.out.println(dnaSdk.getConnect().getNodeSyncStatus()); + System.exit(0); + } + }catch (Exception ex){ + } + } + public static DnaSdk getDnaSdk() throws Exception { + + String ip = "http://127.0.0.1"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRpc()); + wm.openWalletFile("wallet2.dat"); + + return wm; + } +} diff --git a/src/main/java/example/api/Demo.java b/src/main/java/example/api/Demo.java new file mode 100644 index 0000000..3aa128d --- /dev/null +++ b/src/main/java/example/api/Demo.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package example.api; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.block.Block; +import com.github.DNAProject.sdk.wallet.Account; +import com.github.DNAProject.sdk.wallet.Identity; + +import java.util.Base64; +import java.util.List; +import java.util.Map; + +/** + * + */ +public class Demo { + public static void main(String[] args) { + try { + DnaSdk dnaSdk = getDnaSdk(); + + + if(false){ + Account account = dnaSdk.getWalletMgr().importAccount("UcZl6tYzuUwikWnlSBkv1aDrFG80RadPqwoKINRe0+wzCR5o5QqBrrklFXgC5uz9", + "LUlu@665211","AKSTMpAL1MWujdmE1oZNBXLTo4yr4sdF3g",Base64.getDecoder().decode("2kMG+JvubSz5Llw07ewiWQ==")); + System.out.println(account.address); + com.github.DNAProject.account.Account account1 = dnaSdk.getWalletMgr().getAccount(account.address,"LUlu@665211"); + System.out.println(account1.exportWif()); + return; + } + + +// System.out.println(dnaSdk.getConnect().getBalance("TA5NzM9iE3VT9X8SGk5h3dii6GPFQh2vme")); +// System.out.println(Helper.toHexString(dnaSdk.getConnect().getBlock(1).transactions[0].sigs[0].sigData[0])); + System.out.println(dnaSdk.getConnect().getBlock(15)); + System.out.println(dnaSdk.getConnect().getBlockHeight()); + System.out.println(dnaSdk.getConnect().getBlockJson(15)); +// System.out.println(dnaSdk.getConnect().getBlockJson("ee2d842fe7cdf48bc39b34d616a9e8f7f046970ed0a988dde3fe05c9126cce74")); + System.out.println(dnaSdk.getConnect().getNodeCount()); +// System.out.println(((InvokeCodeTransaction)dnaSdk.getConnect().getRawTransaction("c2592940837c2347f6a7b391d4940abb7171dd5dd156b7c031d20a5940142b5a"))); +// System.out.println((dnaSdk.getConnect().getTransaction("d441a967315989116bf0afad498e4016f542c1e7f8605da943f07633996c24cc"))); + System.out.println(dnaSdk.getConnect().getSmartCodeEvent(0)); +// System.out.println(dnaSdk.getConnect().getContractJson("803ca638069742da4b6871fe3d7f78718eeee78a")); +// System.out.println(dnaSdk.getConnect().getMerkleProof("0087217323d87284d21c3539f216dd030bf9da480372456d1fa02eec74c3226d")); + //System.out.println(dnaSdk.getConnect().getBlockHeightByTxHash("7c3e38afb62db28c7360af7ef3c1baa66aeec27d7d2f60cd22c13ca85b2fd4f3")); + //String v = (String)dnaSdk.getConnect().getStorage("ff00000000000000000000000000000000000001", Address.decodeBase58("TA63xZXqdPLtDeznWQ6Ns4UsbqprLrrLJk").toHexString()); + //System.out.println(v); + Block block = dnaSdk.getConnect().getBlock(dnaSdk.getConnect().getBlockHeight()); + String hash = block.transactions[0].hash().toHexString(); + System.out.println(dnaSdk.getConnect().getMerkleProof(hash)); + Object proof = dnaSdk.nativevm().dnaId().getMerkleProof(hash); + System.out.println(proof); + System.out.println(dnaSdk.nativevm().dnaId().verifyMerkleProof(JSON.toJSONString(proof))); + System.exit(0); + List list = (List) dnaSdk.getConnect().getSmartCodeEvent("a12117c319aa6906efd8869ba65c221f4e2ee44a8a2766fd326c8d7125beffbf"); + + List states = (List) ((Map) (list.get(0))).get("States"); + List state1 = (List) states.get(0); + + byte[] bys = new byte[state1.toArray().length]; + for (int i = 0; i < bys.length; i++) { + bys[i] = (byte) ((int) state1.get(i) & 0xff); + } + System.out.println(Address.parse(Helper.toHexString(bys)).toBase58()); + System.exit(0); + + + dnaSdk.getWalletMgr().createAccount("123456"); + System.out.println(dnaSdk.getWalletMgr().getWallet()); + System.out.println(dnaSdk.getWalletMgr().getWalletFile()); + System.exit(0); + System.out.println(dnaSdk.getWalletMgr().getWallet().getAccounts().get(0)); + dnaSdk.getWalletMgr().getWallet().removeAccount(dnaSdk.getWalletMgr().getWallet().getAccounts().get(0).address); + dnaSdk.getWalletMgr().writeWallet(); + System.out.println(dnaSdk.getWalletMgr().getWallet()); + dnaSdk.getWalletMgr().getWallet().setName("name"); + + System.exit(0); + Account acct = dnaSdk.getWalletMgr().createAccount("password"); + Identity identity = dnaSdk.getWalletMgr().createIdentity("password"); + //Block block = dnaSdk.getConnectManager().getBlock(757); + System.out.println(dnaSdk.getConnect().getNodeCount()); + // dnaSdk.getOepMgr().getAccount(dnaSdk.getOepMgr().getAccounts().get(0).address,"1234567"); + + Account info = dnaSdk.getWalletMgr().createAccount("123456"); + dnaSdk.getWalletMgr().writeWallet(); + // dnaSdk.getOepMgr().createDnaId("123456"); + // AccountInfo info2 = dnaSdk.getWalletMgr().getAccountInfo(info.address,"123456"); + // System.out.println(info2); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static DnaSdk getDnaSdk() throws Exception { +// String ip = "http://139.219.108.204"; + String ip = "http://127.0.0.1"; +// String ip = "http://101.132.193.149"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRestful()); + + wm.openWalletFile("Demo3.json"); + + return wm; + } +} diff --git a/src/main/java/example/api/WebsocketDemo.java b/src/main/java/example/api/WebsocketDemo.java new file mode 100644 index 0000000..b2f9818 --- /dev/null +++ b/src/main/java/example/api/WebsocketDemo.java @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package example.api; + +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.block.Block; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.io.Serializable; +import com.github.DNAProject.smartcontract.neovm.abi.AbiFunction; +import com.github.DNAProject.smartcontract.neovm.abi.AbiInfo; +import com.github.DNAProject.sdk.wallet.Account; +import com.github.DNAProject.sdk.wallet.Identity; +import com.github.DNAProject.sdk.wallet.Wallet; +import com.github.DNAProject.network.websocket.MsgQueue; +import com.github.DNAProject.network.websocket.Result; +import com.alibaba.fastjson.JSON; + +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + + +/** + * + */ + +public class WebsocketDemo { + public static Object lock = new Object(); + + public static void main(String[] args) { + try { + DnaSdk dnaSdk = getDnaSdk(); + String password = "passwordtest"; + Account payer = dnaSdk.getWalletMgr().createAccount(password); + + dnaSdk.getWebSocket().startWebsocketThread(false); + + Thread thread = new Thread( + new Runnable() { + @Override + public void run() { + waitResult(lock); + } + }); + thread.start(); + Thread.sleep(5000); + + Wallet oep6 = dnaSdk.getWalletMgr().getWallet(); + System.out.println("oep6:" + JSON.toJSONString(oep6)); + //System.exit(0); + + //System.out.println("================register================="); +// Identity ident = null; +// if (dnaSdk.getWalletMgr().getIdentitys().size() == 0) { +// ident = dnaSdk.neovm().dnaId().sendRegister("passwordtest","payer",0); +// } else { +// ident = dnaSdk.getWalletMgr().getIdentitys().get(0); +// } + +// String dnaid = ident.dnaid; + + + for (int i = 0; i >= 0; i++) { + + dnaSdk.getConnect().getNetworkId(); + dnaSdk.getConnect().getGrantOng("AHX1wzvdw9Yipk7E9MuLY4GGX4Ym9tHeDe"); + + //System.out.println(dnaid); + + + + + if (false) { + Account info1 = null; + Account info2 = null; + Account info3 = null; + if (dnaSdk.getWalletMgr().getWallet().getAccounts().size() < 3) { + info1 = dnaSdk.getWalletMgr().createAccountFromPriKey("passwordtest", "9a31d585431ce0aa0aab1f0a432142e98a92afccb7bcbcaff53f758df82acdb3"); + info2 = dnaSdk.getWalletMgr().createAccount("passwordtest"); + info3 = dnaSdk.getWalletMgr().createAccount("passwordtest"); + dnaSdk.getWalletMgr().writeWallet(); + } + info1 = dnaSdk.getWalletMgr().getWallet().getAccounts().get(0); + info2 = dnaSdk.getWalletMgr().getWallet().getAccounts().get(1); + Transaction tx = dnaSdk.nativevm().gas().makeTransfer( info1.address, info2.address, 100L,payer.address, dnaSdk.DEFAULT_GAS_LIMIT,0); + dnaSdk.signTx(tx, info1.address, password,new byte[]{}); + System.out.println(tx.toHexString()); + dnaSdk.getConnect().sendRawTransaction(tx.toHexString()); + } + + + //waitResult(dnaSdk, lock); + + if (false) { + dnaSdk.getConnect().getBalance("TA63xZXqdPLtDeznWQ6Ns4UsbqprLrrLJk"); + dnaSdk.getConnect().getBlockJson("c8c165bf0ac6107f7f324b0badb60af4dc4e1157b5eb9d3163c8f332a8612c98"); + dnaSdk.getConnect().getNodeCount(); + dnaSdk.getConnect().getContractJson("80e7d2fc22c24c466f44c7688569cc6e6d6c6f92"); + dnaSdk.getConnect().getSmartCodeEvent("7c3e38afb62db28c7360af7ef3c1baa66aeec27d7d2f60cd22c13ca85b2fd4f3"); + dnaSdk.getConnect().getBlockHeightByTxHash("7c3e38afb62db28c7360af7ef3c1baa66aeec27d7d2f60cd22c13ca85b2fd4f3"); + dnaSdk.getConnect().getStorage("ff00000000000000000000000000000000000001", Address.decodeBase58("TA63xZXqdPLtDeznWQ6Ns4UsbqprLrrLJk").toHexString()); + dnaSdk.getConnect().getTransactionJson("7c3e38afb62db28c7360af7ef3c1baa66aeec27d7d2f60cd22c13ca85b2fd4f3"); + } + if (false) { + + InputStream is = new FileInputStream("C:\\ZX\\huguanjun.abi.json");//IdContract + byte[] bys = new byte[is.available()]; + is.read(bys); + is.close(); + String abi = new String(bys); + + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + //System.out.println("Entrypoint:" + abiinfo.getEntrypoint()); + //System.out.println("Functions:" + abiinfo.getFunctions()); + + AbiFunction func0 = abiinfo.getFunction("Put"); + Identity did0 = dnaSdk.getWalletMgr().getWallet().getIdentities().get(0); + func0.setParamsValue("key".getBytes(), "value".getBytes()); + } + if(true){ + Map map = new HashMap(); + if(i >0) { + map.put("SubscribeEvent", true); + map.put("SubscribeRawBlock", false); + }else{ + map.put("SubscribeJsonBlock", false); + map.put("SubscribeRawBlock", true); + } + //System.out.println(map); + dnaSdk.getWebSocket().setReqId(i); + dnaSdk.getWebSocket().sendSubscribe(map); +// dnaSdk.getWebSocket().getBlockHeight(); + } + Thread.sleep(6000); + } + + System.exit(0); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void waitResult(Object lock) { + try { + synchronized (lock) { + while (true) { + lock.wait(); + for (String e : MsgQueue.getResultSet()) { + System.out.println("RECV: " + e); + Result rt = JSON.parseObject(e, Result.class); + //TODO + MsgQueue.removeResult(e); + if (rt.Action.equals("getblockbyheight")) { + Block bb = Serializable.from(Helper.hexToBytes((String) rt.Result), Block.class); + //System.out.println(bb.json()); + } + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static DnaSdk getDnaSdk() throws Exception { + String ip = "http://127.0.0.1"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setWesocket(wsUrl, lock); + wm.setDefaultConnect(wm.getWebSocket()); + wm.openWalletFile("WsDemo.json"); + return wm; + } +} diff --git a/src/main/java/example/dnaid/AuthDemo.java b/src/main/java/example/dnaid/AuthDemo.java new file mode 100644 index 0000000..ac34999 --- /dev/null +++ b/src/main/java/example/dnaid/AuthDemo.java @@ -0,0 +1,154 @@ +package example.dnaid; +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.sdk.wallet.Account; +import com.github.DNAProject.sdk.wallet.Identity; +import com.github.DNAProject.smartcontract.neovm.abi.AbiFunction; +import com.github.DNAProject.smartcontract.neovm.abi.AbiInfo; + +import java.util.List; + +public class AuthDemo { + + public static void main(String[] args){ + DnaSdk dnaSdk; + String password = "111111"; + String abi = "{\"hash\":\"0x4d0d780599010f943c37c795a22f6161d49436cf\",\"entrypoint\":\"Main\",\"functions\":[{\"name\":\"Main\",\"parameters\":[{\"name\":\"operation\",\"type\":\"String\"},{\"name\":\"token\",\"type\":\"Array\"},{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"Any\"},{\"name\":\"foo\",\"parameters\":[{\"name\":\"operation\",\"type\":\"ByteArray\"},{\"name\":\"token\",\"type\":\"Integer\"}],\"returntype\":\"Boolean\"},{\"name\":\"init\",\"parameters\":[],\"returntype\":\"Boolean\"}],\"events\":[]}"; + Account payer; + try { + dnaSdk = getDnaSdk(); +// System.out.println(Helper.toHexString("initContractAdmin".getBytes())); +// System.exit(0); + // 8007c33f29a892e3a36e2cfec657eff1d7431e8f + String privatekey0 = "523c5fcf74823831756f0bcb3634234f10b3beb1c05595058534577752ad2d9f"; + String privatekey1 ="83614c773f668a531132e765b5862215741c9148e7b2f9d386b667e4fbd93e39"; + com.github.DNAProject.account.Account acct0 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey0), dnaSdk.defaultSignScheme); + + com.github.DNAProject.account.Account account = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey1), dnaSdk.defaultSignScheme); + + payer = dnaSdk.getWalletMgr().createAccount(password); + com.github.DNAProject.account.Account payerAcct = dnaSdk.getWalletMgr().getAccount(payer.address,password,payer.getSalt()); + Identity identity = null; + Identity identity2 = null; + Identity identity3 = null; + List dids = dnaSdk.getWalletMgr().getWallet().getIdentities(); + if(dnaSdk.getWalletMgr().getWallet().getIdentities().size() < 3){ + // Identity identity1 = dnaSdk.getWalletMgr().importIdentity("",password,"".getBytes(),acct0.getAddressU160().toBase58()); + identity = dnaSdk.getWalletMgr().createIdentityFromPriKey(password,privatekey0); + + dnaSdk.nativevm().dnaId().sendRegister(identity,password,payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + // dnaSdk.nativevm().dnaId().sendRegister(identity1,password,payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + identity2 = dnaSdk.getWalletMgr().createIdentity(password); + dnaSdk.nativevm().dnaId().sendRegister(identity2,password,payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + + identity3 = dnaSdk.getWalletMgr().createIdentity(password); + dnaSdk.nativevm().dnaId().sendRegister(identity3,password,payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + + dnaSdk.getWalletMgr().writeWallet(); + + Thread.sleep(6000); + }else { + identity = dnaSdk.getWalletMgr().getWallet().getIdentity(dids.get(0).dnaid); + identity2 = dnaSdk.getWalletMgr().getWallet().getIdentity(dids.get(1).dnaid); + identity3 = dnaSdk.getWalletMgr().getWallet().getIdentity(dids.get(2).dnaid); + } + + + + System.out.println("dnaid1:" +dids.get(0).dnaid+" "+Helper.toHexString(dids.get(0).dnaid.getBytes())); + System.out.println("dnaid2:" +dids.get(1).dnaid); + System.out.println("dnaid3:" +dids.get(2).dnaid); + Account account1 = dnaSdk.getWalletMgr().createAccount(password); + System.out.println("####" + account1.address); + +// System.out.println("ddo1:" + dnaSdk.nativevm().dnaId().sendGetDDO(dids.get(0).dnaid)); +// System.out.println("ddo2:" + dnaSdk.nativevm().dnaId().sendGetDDO(dids.get(1).dnaid)); +// System.out.println("ddo3:" + dnaSdk.nativevm().dnaId().sendGetDDO(dids.get(2).dnaid)); + + String contractAddr = "b93f1d81a00f95d09228f1f8934a71dd0e89999f"; + + if(false){ + identity = dnaSdk.getWalletMgr().createIdentityFromPriKey(password,privatekey1); + dnaSdk.nativevm().dnaId().sendRegister(identity,password,payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + System.out.println(Helper.toHexString(identity.dnaid.getBytes())); + + } + //Identity identity = dnaSdk.getWalletMgr().createIdentityFromPriKey(password,privatekey1); + System.out.println(account.getAddressU160().toBase58()); + System.out.println(identity.dnaid); + System.out.println(Helper.toHexString(account.getAddressU160().toArray())); + System.out.println(Helper.toHexString(identity.dnaid.getBytes())); + + if(false){ + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + String name = "init"; + AbiFunction func = abiinfo.getFunction(name); + func.name = name; + System.out.println(func); + func.setParamsValue(); + //Object obj = dnaSdk.neovm().sendTransaction(Helper.reverse(contractAddr),null,null,0,0,func, true); + Object obj = dnaSdk.neovm().sendTransaction(Helper.reverse(contractAddr),acct0,acct0,30000,0,func, false); + System.out.println(obj); + } + + if(false){ + +// String txhash = dnaSdk.nativevm().auth().sendInit(dids.get(0).dnaid,password,codeaddress,account,dnaSdk.DEFAULT_GAS_LIMIT,0); + + //String txhash = dnaSdk.nativevm().auth().sendTransfer(identity.dnaid,password,identity.controls.get(0).getSalt(),1,Helper.reverse(contractAddr),identity2.dnaid,account,dnaSdk.DEFAULT_GAS_LIMIT,0); + + // String txhash = dnaSdk.nativevm().auth().assignFuncsToRole(identity2.dnaid,password,identity2.controls.get(0).getSalt(),1,Helper.reverse(contractAddr),"role",new String[]{"foo"},account,dnaSdk.DEFAULT_GAS_LIMIT,0); + String txhash = dnaSdk.nativevm().auth().assignDnaIdsToRole(identity2.dnaid,password,identity2.controls.get(0).getSalt(),1,Helper.reverse(contractAddr),"role",new String[]{identity2.dnaid},account,dnaSdk.DEFAULT_GAS_LIMIT,0); + //String txhash = dnaSdk.nativevm().auth().delegate(identity2.dnaid,password,identity2.controls.get(0).getSalt(),1,Helper.reverse(contractAddr),identity3.dnaid,"role",6000,1,account,dnaSdk.DEFAULT_GAS_LIMIT,0); + //String txhash = dnaSdk.nativevm().auth().withdraw(identity2.dnaid,password,identity2.controls.get(0).getSalt(),1,Helper.reverse(contractAddr),identity3.dnaid,"role",account,dnaSdk.DEFAULT_GAS_LIMIT,0); + // String txhash = dnaSdk.nativevm().auth().verifyToken(identity2.dnaid,password,identity2.controls.get(0).getSalt(),1,Helper.reverse(contractAddr),"foo"); +// Thread.sleep(6000); +// Object object = dnaSdk.getConnect().getSmartCodeEvent(txhash); +// System.out.println(object); + + +// String txhash2 = dnaSdk.nativevm().auth().withdraw(dids.get(0).dnaid,password,contractAddr,dids.get(1).dnaid,"role",1,payer.address,password,dnaSdk.DEFAULT_GAS_LIMIT,0); + Thread.sleep(6000); + Object object2 = dnaSdk.getConnect().getSmartCodeEvent(txhash); + System.out.println(object2); + } + if(true){ + dnaSdk.nativevm().auth().queryAuth(contractAddr,"role",identity2.dnaid); + } + if(false){ + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + String name = "foo"; + AbiFunction func = abiinfo.getFunction(name); + func.name = name; + System.out.println(func); + func.setParamsValue(identity2.dnaid.getBytes(),Long.valueOf(1)); + + acct0 = dnaSdk.getWalletMgr().getAccount(identity2.dnaid,password,identity2.controls.get(0).getSalt()); + System.out.println("pk:"+Helper.toHexString(acct0.serializePublicKey())); + Object obj = dnaSdk.neovm().sendTransaction(Helper.reverse(contractAddr),acct0,account,30000,0,func, true); + System.out.println(obj); + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + + public static DnaSdk getDnaSdk() throws Exception { + +// String ip = "http://139.219.129.55"; +// String ip = "http://101.132.193.149"; + String ip = "http://127.0.0.1"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRestful()); + wm.openWalletFile("AuthDemo.json"); + return wm; + } +} diff --git a/src/main/java/example/dnaid/ClaimDemo.java b/src/main/java/example/dnaid/ClaimDemo.java new file mode 100644 index 0000000..21a0351 --- /dev/null +++ b/src/main/java/example/dnaid/ClaimDemo.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package example.dnaid; + +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.sdk.wallet.Identity; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +/** + * + */ +public class ClaimDemo { + + public static void main(String[] args) { + + try { + DnaSdk dnaSdk = getDnaSdk(); + String privatekey0 = "c19f16785b8f3543bbaf5e1dbb5d398dfa6c85aaad54fc9d71203ce83e505c07"; + Account acct0 = new Account(Helper.hexToBytes(privatekey0), dnaSdk.defaultSignScheme); + List dids = dnaSdk.getWalletMgr().getWallet().getIdentities(); + if (dids.size() < 2) { + Identity identity = dnaSdk.getWalletMgr().createIdentity("passwordtest"); + dnaSdk.nativevm().dnaId().sendRegister(identity,"passwordtest",acct0,0,0); + identity = dnaSdk.getWalletMgr().createIdentity("passwordtest"); + dnaSdk.nativevm().dnaId().sendRegister(identity,"passwordtest",acct0,0,0); + dids = dnaSdk.getWalletMgr().getWallet().getIdentities(); + Thread.sleep(6000); + } + + Map map = new HashMap(); + map.put("Issuer", dids.get(0).dnaid); + map.put("Subject", dids.get(1).dnaid); + + + String claim = dnaSdk.nativevm().dnaId().createDnaIdClaim(dids.get(0).dnaid,"passwordtest",new byte[]{}, "claim:context", map, map,map,0); + System.out.println(claim); + boolean b = dnaSdk.nativevm().dnaId().verifyDnaIdClaim(claim); + System.out.println(b); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static DnaSdk getDnaSdk() throws Exception { + + String ip = "http://127.0.0.1"; +// String ip = "http://54.222.182.88; +// String ip = "http://101.132.193.149"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRestful()); + + wm.openWalletFile("ClaimDemo.json"); + + return wm; + } +} diff --git a/src/main/java/example/dnaid/ClaimRecordTxDemo.java b/src/main/java/example/dnaid/ClaimRecordTxDemo.java new file mode 100644 index 0000000..735c48e --- /dev/null +++ b/src/main/java/example/dnaid/ClaimRecordTxDemo.java @@ -0,0 +1,136 @@ +package example.dnaid; + + +import com.alibaba.fastjson.JSONObject; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.common.Common; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.crypto.SignatureScheme; +import com.github.DNAProject.sdk.info.AccountInfo; +import com.github.DNAProject.sdk.wallet.Account; +import com.github.DNAProject.sdk.wallet.Identity; + +import java.util.Base64; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class ClaimRecordTxDemo { + public static void main(String[] args) { + + try { + DnaSdk dnaSdk = getDnaSdk(); + + + + + String password = "111111"; + + Account payerAccInfo = dnaSdk.getWalletMgr().createAccount(password); + com.github.DNAProject.account.Account payerAcc = dnaSdk.getWalletMgr().getAccount(payerAccInfo.address,password,payerAccInfo.getSalt()); + + + if (dnaSdk.getWalletMgr().getWallet().getIdentities().size() < 2) { + Identity identity = dnaSdk.getWalletMgr().createIdentity(password); + + dnaSdk.nativevm().dnaId().sendRegister(identity,password,payerAcc,dnaSdk.DEFAULT_GAS_LIMIT,0); + + Identity identity2 = dnaSdk.getWalletMgr().createIdentity(password); + + dnaSdk.nativevm().dnaId().sendRegister(identity2,password,payerAcc,dnaSdk.DEFAULT_GAS_LIMIT,0); + + dnaSdk.getWalletMgr().writeWallet(); + + Thread.sleep(6000); + } + + List dids = dnaSdk.getWalletMgr().getWallet().getIdentities(); + + + Map map = new HashMap(); + map.put("Issuer", dids.get(0).dnaid); + map.put("Subject", dids.get(1).dnaid); + + Map clmRevMap = new HashMap(); + clmRevMap.put("typ","AttestContract"); + clmRevMap.put("addr",dids.get(1).dnaid.replace(Common.diddna,"")); + + String claim = dnaSdk.nativevm().dnaId().createDnaIdClaim(dids.get(0).dnaid,password,dids.get(0).controls.get(0).getSalt(), "claim:context", map, map,clmRevMap,System.currentTimeMillis()/1000 +100000); + System.out.println(claim); + + boolean b = dnaSdk.nativevm().dnaId().verifyDnaIdClaim(claim); + System.out.println(b); + +// System.exit(0); + + Account account = dnaSdk.getWalletMgr().importAccount("blDuHRtsfOGo9A79rxnJFo2iOMckxdFDfYe2n6a9X+jdMCRkNUfs4+C4vgOfCOQ5","111111","AazEvfQPcQ2GEFFPLF1ZLwQ7K5jDn81hve",Base64.getDecoder().decode("0hAaO6CT+peDil9s5eoHyw==")); + AccountInfo info = dnaSdk.getWalletMgr().getAccountInfo(account.address,"111111",account.getSalt()); + com.github.DNAProject.account.Account account1 = new com.github.DNAProject.account.Account(Helper.hexToBytes("75de8489fcb2dcaf2ef3cd607feffde18789de7da129b5e97c81e001793cb7cf"),SignatureScheme.SHA256WITHECDSA); + + + String[] claims = claim.split("\\."); + + JSONObject payload = JSONObject.parseObject(new String(Base64.getDecoder().decode(claims[1].getBytes()))); + + System.out.println("ClaimId:" + payload.getString("jti")); + +// dnaSdk.neovm().claimRecord().setContractAddress("9a4c79ee4379a0b5d10db03553ca7e61e17a8977"); + // +// String getstatusRes9 = dnaSdk.neovm().claimRecord().sendGetStatus(payload.getString("jti")); +// System.out.println("getstatusResBytes:" + getstatusRes9); + + String commitHash = dnaSdk.neovm().claimRecord().sendCommit(dids.get(0).dnaid,password,dids.get(0).controls.get(0).getSalt(),dids.get(1).dnaid,payload.getString("jti"),account1,dnaSdk.DEFAULT_GAS_LIMIT,0); + System.out.println("commitRes:" + commitHash); + Thread.sleep(6000); + Object obj = dnaSdk.getConnect().getSmartCodeEvent(commitHash); + System.out.println(obj); + + + System.out.println(Helper.toHexString(dids.get(0).dnaid.getBytes())); + System.out.println(Helper.toHexString(dids.get(1).dnaid.getBytes())); + System.out.println(Helper.toHexString(payload.getString("jti").getBytes())); + System.out.println(payload.getString("jti")); + + + String getstatusRes = dnaSdk.neovm().claimRecord().sendGetStatus(payload.getString("jti")); + System.out.println("getstatusResBytes:" + getstatusRes); + Thread.sleep(6000); + +// System.exit(0); + + String revokeHash = dnaSdk.neovm().claimRecord().sendRevoke(dids.get(0).dnaid,password,dids.get(0).controls.get(0).getSalt(),payload.getString("jti"),account1,dnaSdk.DEFAULT_GAS_LIMIT,0); + System.out.println("revokeRes:" + revokeHash); + Thread.sleep(6000); + System.out.println(dnaSdk.getConnect().getSmartCodeEvent(revokeHash)); + + + String getstatusRes2 = dnaSdk.neovm().claimRecord().sendGetStatus(payload.getString("jti")); + + System.out.println("getstatusResBytes2:" + getstatusRes2); + + System.exit(0); + + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static DnaSdk getDnaSdk() throws Exception { + String ip = "http://127.0.0.1"; +// String ip = "http://54.222.182.88; +// String ip = "http://101.132.193.149"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRestful()); + + wm.openWalletFile("ClaimRecordTxDemo.json"); + + return wm; + } +} + diff --git a/src/main/java/example/dnaid/DnaIdDemo.java b/src/main/java/example/dnaid/DnaIdDemo.java new file mode 100644 index 0000000..7441a99 --- /dev/null +++ b/src/main/java/example/dnaid/DnaIdDemo.java @@ -0,0 +1,171 @@ +package example.dnaid; + +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.dnaid.Attribute; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.crypto.SignatureScheme; +import com.github.DNAProject.sdk.info.IdentityInfo; +import com.github.DNAProject.sdk.wallet.Account; +import com.github.DNAProject.sdk.wallet.Identity; + +import java.util.List; + +public class DnaIdDemo { + + public static void main(String[] args) { + + String password = "111111"; + + try { + DnaSdk dnaSdk = getDnaSdk(); + + Account payer = dnaSdk.getWalletMgr().createAccount(password); + + com.github.DNAProject.account.Account payerAcct = dnaSdk.getWalletMgr().getAccount(payer.address,password,dnaSdk.getWalletMgr().getWallet().getAccount(payer.address).getSalt()); + String privatekey0 = "c19f16785b8f3543bbaf5e1dbb5d398dfa6c85aaad54fc9d71203ce83e505c07"; + String privatekey1 = "2ab720ff80fcdd31a769925476c26120a879e235182594fbb57b67c0743558d7"; + com.github.DNAProject.account.Account account1 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey1),SignatureScheme.SHA256WITHECDSA); + + if(false){ + Account account = dnaSdk.getWalletMgr().createAccount(password); + com.github.DNAProject.account.Account account2 = dnaSdk.getWalletMgr().getAccount(account.address,password,account.getSalt()); + Identity identity = dnaSdk.getWalletMgr().createIdentityFromPriKey(password, Helper.toHexString(account2.serializePrivateKey())); + dnaSdk.nativevm().dnaId().sendRegister(identity,password,account2,20000,0); + Thread.sleep(6000); + System.out.println(dnaSdk.nativevm().dnaId().sendGetDDO(identity.dnaid)); + return; + } + + + if(false){ + Identity identity3 = dnaSdk.getWalletMgr().createIdentity(password); + Attribute[] attributes = new Attribute[1]; + attributes[0] = new Attribute("key1".getBytes(),"String".getBytes(),"value1".getBytes()); + dnaSdk.nativevm().dnaId().sendRegisterWithAttrs(identity3,password,attributes,payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + dnaSdk.getWalletMgr().writeWallet(); + Thread.sleep(6000); + String ddo = dnaSdk.nativevm().dnaId().sendGetDDO(identity3.dnaid); + System.out.println(ddo); + System.exit(0); + } + if(true){ + if(dnaSdk.getWalletMgr().getWallet().getIdentities().size() < 1){ +// Identity identity = dnaSdk.getWalletMgr().createIdentity(password); + Identity identity = dnaSdk.getWalletMgr().createIdentityFromPriKey(password,privatekey0); + dnaSdk.nativevm().dnaId().sendRegister(identity,password,payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + dnaSdk.getWalletMgr().writeWallet(); + Thread.sleep(6000); + return; + } + Identity identity = dnaSdk.getWalletMgr().getWallet().getIdentities().get(0); +// String ddo = dnaSdk.nativevm().dnaId().sendGetDDO(identity.dnaid); +// System.out.println(ddo); + + Attribute[] attributes = new Attribute[1]; + attributes[0] = new Attribute("key1".getBytes(),"String".getBytes(),"value1".getBytes()); + byte[] salt = identity.controls.get(0).getSalt(); +// dnaSdk.nativevm().dnaId().sendAddAttributes(identity.dnaid,password,identity.controls.get(0).getSalt(),attributes,payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); +// dnaSdk.nativevm().dnaId().sendRemoveAttribute(identity.dnaid,password,identity.controls.get(0).getSalt(),"key1",payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + dnaSdk.nativevm().dnaId().sendAddRecovery(identity.dnaid,password,salt,account1.getAddressU160().toBase58(),payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); +// dnaSdk.nativevm().dnaId().sendAddPubKey(identity.dnaid,password,salt,Helper.toHexString(account1.serializePublicKey()),payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); +// dnaSdk.nativevm().dnaId().sendRemovePubKey(identity.dnaid,password,salt,Helper.toHexString(account1.serializePublicKey()),payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + Thread.sleep(6000); + String ddo2 = dnaSdk.nativevm().dnaId().sendGetDDO(identity.dnaid); + System.out.println(ddo2); + System.out.println(account1.getAddressU160().toBase58()); + System.exit(0); + } + Account account = dnaSdk.getWalletMgr().createAccountFromPriKey(password,privatekey0); + if(dnaSdk.getWalletMgr().getWallet().getIdentities().size() < 3){ + Identity identity = dnaSdk.getWalletMgr().createIdentity(password); + Transaction tx = dnaSdk.nativevm().dnaId().makeRegister(identity.dnaid,identity.controls.get(0).publicKey,payer.address,dnaSdk.DEFAULT_GAS_LIMIT,0); + dnaSdk.signTx(tx,identity.dnaid,password,new byte[]{}); + dnaSdk.addSign(tx,payerAcct); + dnaSdk.getConnect().sendRawTransaction(tx); + + Identity identity2 = dnaSdk.getWalletMgr().createIdentity(password); + dnaSdk.nativevm().dnaId().sendRegister(identity2,password,payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + + Identity identity3 = dnaSdk.getWalletMgr().createIdentity(password); + Attribute[] attributes = new Attribute[1]; + attributes[0] = new Attribute("key1".getBytes(),"String".getBytes(),"value1".getBytes()); + dnaSdk.nativevm().dnaId().sendRegisterWithAttrs(identity3,password,attributes,payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + dnaSdk.getWalletMgr().writeWallet(); + Thread.sleep(6000); + + } + List dids = dnaSdk.getWalletMgr().getWallet().getIdentities(); + System.out.println("dids.get(0).dnaid:" + dids.get(0).dnaid); +// System.out.println("dids.get(1).dnaid:" + dids.get(1).dnaid); +// System.out.println("dids.get(2).dnaid:" + dids.get(2).dnaid); + String ddo1 = dnaSdk.nativevm().dnaId().sendGetDDO(dids.get(0).dnaid); +// String publicKeys = dnaSdk.nativevm().dnaId().sendGetPublicKeys(dids.get(0).dnaid); +// String ddo2 = dnaSdk.nativevm().dnaId().sendGetDDO(dids.get(1).dnaid); +// String ddo3 = dnaSdk.nativevm().dnaId().sendGetDDO(dids.get(2).dnaid); + + System.out.println("ddo1:" + ddo1); +// System.out.println("ddo2:" + ddo2); +// System.out.println("ddo3:" + ddo3); + + IdentityInfo info2 = dnaSdk.getWalletMgr().getIdentityInfo(dids.get(1).dnaid,password,new byte[]{}); + IdentityInfo info3 = dnaSdk.getWalletMgr().getIdentityInfo(dids.get(2).dnaid,password,new byte[]{}); + + com.github.DNAProject.account.Account acct = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey0),SignatureScheme.SHA256WITHECDSA); + com.github.DNAProject.account.Account acct2 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey1),SignatureScheme.SHA256WITHECDSA); + Address multiAddr = Address.addressFromMultiPubKeys(2,acct.serializePublicKey(),acct2.serializePublicKey()); + + if(false){ + Account account2 = dnaSdk.getWalletMgr().createAccountFromPriKey(password, privatekey1); +// dnaSdk.nativevm().dnaId().sendChangeRecovery(dids.get(0).dnaid,account2.address,account.address,password,dnaSdk.DEFAULT_GAS_LIMIT,0); + String txhash2 = dnaSdk.nativevm().dnaId().sendAddRecovery(dids.get(0).dnaid,password,new byte[]{},multiAddr.toBase58(),payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + Thread.sleep(6000); + Object obj = dnaSdk.getConnect().getSmartCodeEvent(txhash2); + System.out.println(obj); + System.out.println(dnaSdk.nativevm().dnaId().sendGetDDO(dids.get(0).dnaid)); + } + + if(false){ + dnaSdk.nativevm().dnaId().sendAddPubKey(dids.get(0).dnaid,password,new byte[]{},info3.pubkey,payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + dnaSdk.nativevm().dnaId().sendRemovePubKey(dids.get(0).dnaid,account.address,password,new byte[]{},info2.pubkey,payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + dnaSdk.nativevm().dnaId().sendAddPubKey(dids.get(0).dnaid,account.address,password,new byte[]{},info2.pubkey,payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + Transaction tx = dnaSdk.nativevm().dnaId().makeAddPubKey(dids.get(0).dnaid,multiAddr.toBase58(),null,info2.pubkey,payer.address,dnaSdk.DEFAULT_GAS_LIMIT,0); + // dnaSdk.signTx(tx,new com.github.DNAProject.account.Account[][]{{acct,acct2}}); + // dnaSdk.addSign(tx,payerAcc.address,password); + // dnaSdk.getConnect().sendRawTransaction(tx.toHexString()); + } + + + if(false){ + String ddo4 = dnaSdk.nativevm().dnaId().sendGetDDO(dids.get(0).dnaid); + System.out.println("ddo4:" + ddo4); + System.exit(0); + System.out.println("ddo1:" + ddo1); + System.out.println("publicKeysState:" + dnaSdk.nativevm().dnaId().sendGetKeyState(dids.get(0).dnaid,1)); + System.out.println("attributes:" + dnaSdk.nativevm().dnaId().sendGetAttributes(dids.get(0).dnaid)); + } + + + } catch (Exception e) { + e.printStackTrace(); + } + + } + + + public static DnaSdk getDnaSdk() throws Exception { + String ip = "http://127.0.0.1"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRestful()); + + wm.openWalletFile("DnaIdDemo.json"); + return wm; + } +} diff --git a/src/main/java/example/dnaid/merkleProofDemo.java b/src/main/java/example/dnaid/merkleProofDemo.java new file mode 100644 index 0000000..ad58af1 --- /dev/null +++ b/src/main/java/example/dnaid/merkleProofDemo.java @@ -0,0 +1,65 @@ +package example.dnaid; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.common.UInt256; +import com.github.DNAProject.merkle.MerkleVerifier; + +public class merkleProofDemo { + public static void main(String[] args) { + + try { + DnaSdk dnaSdk = getDnaSdk(); + //System.out.println(dnaSdk.getConnectMgr().getMerkleProof("")); + + if(false) { + UInt256 txroot = UInt256.parse("731be6e82cfe0382bdf04e891fdab2fd1a3cd1b97628ef8498c85789f8c798ba"); + UInt256 curBlkRoot = UInt256.parse("34aad54259addee02df4636b3d6b57cbe3398725847f05f94ea35e8356ab46b3"); + UInt256[] targetHashes = new UInt256[]{ + UInt256.parse("b4295f52004d01be2a459b297aaa3ddc397560dddc13a917b047d8daa6bf5b2b"), + UInt256.parse("6b8e9b09ac23b532f9391f57047cc226eaafcf7531fba63714ba2aa7f0ffc291"), + UInt256.parse("863c0210cedf57a9f999f36d34b86760054234aab72eba67433ee51f6504e63a"), + + UInt256.parse("47025ef9977449b90ea58ddf820852a04a35f0827c691365a97122141e201305"), + UInt256.parse("712a75cd6759c69e704353a8b3735274dcdc9026fdce7dc3f1320123c49d6938"), + UInt256.parse("d6a3f1cb1270c5ef4e721aabc45d4894315b268875ca850653164e31e4fe64e2"), + + UInt256.parse("cb93a80f22bda0563e317b96332f989b0cc6764b84a41f7e22eb6025d3c63e94") + }; + int blockHeight = 3970; + int curBlockHeight = 3971; + boolean b = MerkleVerifier.VerifyLeafHashInclusion(txroot, blockHeight, targetHashes, curBlkRoot, curBlockHeight+1); + + System.out.println(b); + System.exit(0); + } + String txhash = "76763a5f9fc6b68d54463933e51c4b4dbce6732146294525c09b167637f2facf"; + Object proof = dnaSdk.nativevm().dnaId().getMerkleProof(txhash); + System.out.println(proof); + System.out.println(dnaSdk.getConnect().getMerkleProof(txhash)); + System.out.println(dnaSdk.nativevm().dnaId().verifyMerkleProof(JSON.toJSONString(proof))); + System.exit(0); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static DnaSdk getDnaSdk() throws Exception { + + String ip = "http://127.0.0.1"; +// String ip = "http://54.222.182.88; +// String ip = "http://101.132.193.149"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRestful()); + + wm.openWalletFile("ClaimDemo.json"); + + return wm; + } +} diff --git a/src/main/java/example/gas/ExchangeDemo.java b/src/main/java/example/gas/ExchangeDemo.java new file mode 100644 index 0000000..bf4d536 --- /dev/null +++ b/src/main/java/example/gas/ExchangeDemo.java @@ -0,0 +1,430 @@ +package example.gas; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONField; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.asset.State; +import com.github.DNAProject.core.transaction.Transaction; + +import java.math.BigInteger; +import java.util.*; + +class UserAcct{ + String id; + String address; + String withdrawAddr; + byte[] privkey; + BigInteger gasBalance; +} + +class Balance{ + @JSONField(name="gas") + String gas; + + + public String getGas() { + return gas; + } + + public void setGas(String gas) { + this.gas = gas; + } +} + + +class States{ + @JSONField(name="States") + Object[] states; + + @JSONField(name="ContractAddress") + String contractAddress; + + public Object[] getStates() { + return states; + } + + public void setStates(Object[] states) { + this.states = states; + } + + public String getContractAddress() { + return contractAddress; + } + + public void setContractAddress(String contractAddress) { + this.contractAddress = contractAddress; + } + +} + +class Event{ + @JSONField(name="GasConsumed") + int gasConsumed; + + + @JSONField(name="TxHash") + String txHash; + + @JSONField(name="State") + int state; + + @JSONField(name="Notify") + States[] notify; + + public int getGasConsumed() { + return gasConsumed; + } + + public void setGasConsumed(int gasConsumed) { + this.gasConsumed = gasConsumed; + } + + + public String getTxHash() { + return txHash; + } + + public void setTxHash(String txHash) { + this.txHash = txHash; + } + + public int getState() { + return state; + } + + public void setState(int state) { + this.state = state; + } + + public States[] getNotify() { + return notify; + } + + public void setNotify(States[] notify) { + this.notify = notify; + } +} + + + +public class ExchangeDemo { + + //init account should have some onts + public static final String INIT_ACCT_ADDR = "Ad4pjz2bqep4RhQrUAzMuZJkBC3qJ1tZuT"; + public static final String INIT_ACCT_SALT = "OkX96EG0OaCNUFD3hdc50Q=="; + + public static final String FEE_PROVIDER = "AS3SCXw8GKTEeXpdwVw7EcC4rqSebFYpfb"; + public static final String FEE_PROVIDER_SALT = "KvKkxNOGm4q4bLkD8TS2PA=="; + + //for test all account's pwd is the same + public static final String PWD = "123456"; + + //for generate a multi-sig address + public static final String MUTI_SIG_ACCT_SEED1_ADDR = "AK98G45DhmPXg4TFPG1KjftvkEaHbU8SHM"; + public static final String MUTI_SIG_ACCT_SEED1_SALT = "rD4ewxv4qHH8FbUkUv6ePQ=="; + + public static final String MUTI_SIG_ACCT_SEED2_ADDR = "ALerVnMj3eNk9xe8BnQJtoWvwGmY3x4KMi"; + public static final String MUTI_SIG_ACCT_SEED2_SALT = "1K8a7joYQ+iwj3/+wGICrw=="; + + public static final String MUTI_SIG_ACCT_SEED3_ADDR = "AKmowTi8NcAMjZrg7ZNtSQUtnEgdaC65wG"; + public static final String MUTI_SIG_ACCT_SEED3_SALT = "b9oBYBIPvZMw66q1ky+JDQ=="; + + //withdraw address for test user + public static final String WITHDRAW_ADDRESS = "AZbcPX7HyJTWjqogZhnr2qDTh6NNksGSE6"; + + + public static String GAS_NATIVE_ADDRESS = ""; + + public static void main(String[] args) { + try{ + //simulate a database using hashmap + HashMap database = new HashMap(); + + DnaSdk dnaSdk = getDnaSdk(); + GAS_NATIVE_ADDRESS = Helper.reverse(dnaSdk.nativevm().gas().getContractAddress()); + + printlog("++++ starting simulate exchange process ...========"); + printlog("++++ 1. create a random account for user ===="); + String id1 = "id1"; + Account acct1 = new Account(dnaSdk.defaultSignScheme); + String pubkey = acct1.getAddressU160().toBase58(); + byte[] privkey = acct1.serializePrivateKey(); + printlog("++++ public key is " + acct1.getAddressU160().toBase58()); + + UserAcct usr =getNewUserAcct(id1,pubkey,privkey,BigInteger.valueOf(0),BigInteger.valueOf(0)); + usr.withdrawAddr = WITHDRAW_ADDRESS; + database.put(acct1.getAddressU160().toBase58(),usr); + //all transfer fee is provide from this account + Account feeAct = dnaSdk.getWalletMgr().getAccount(FEE_PROVIDER,PWD,Base64.getDecoder().decode(FEE_PROVIDER_SALT)); + + //create a multi-sig account as a main account + Account mutiSeedAct1 = dnaSdk.getWalletMgr().getAccount(MUTI_SIG_ACCT_SEED1_ADDR,PWD,Base64.getDecoder().decode(MUTI_SIG_ACCT_SEED1_SALT)); + Account mutiSeedAct2 = dnaSdk.getWalletMgr().getAccount(MUTI_SIG_ACCT_SEED2_ADDR,PWD,Base64.getDecoder().decode(MUTI_SIG_ACCT_SEED2_SALT)); + Account mutiSeedAct3 = dnaSdk.getWalletMgr().getAccount(MUTI_SIG_ACCT_SEED3_ADDR,PWD,Base64.getDecoder().decode(MUTI_SIG_ACCT_SEED3_SALT)); + + Address mainAccountAddr = Address.addressFromMultiPubKeys(3,mutiSeedAct1.serializePublicKey(),mutiSeedAct2.serializePublicKey(),mutiSeedAct3.serializePublicKey()); + printlog("++++ Main Account Address is :" + mainAccountAddr.toBase58()); + + + //monitor the charge and withdraw thread + Thread t = new Thread(new Runnable() { + + long lastblocknum = 0 ; + + @Override + public void run() { + while(true){ + try{ + //get latest blocknum: + //TODO fix lost block + int height = dnaSdk.getConnect().getBlockHeight(); + if (height > lastblocknum){ + printlog("====== new block sync :" + height); + + Object event = dnaSdk.getConnect().getSmartCodeEvent(height); + if(event == null){ + lastblocknum = height; + Thread.sleep(1000); + continue; + } + printlog("====== event is " + event.toString()); + + List events = JSON.parseArray(event.toString(), Event.class); + if(events == null){ + lastblocknum = height; + Thread.sleep(1000); + continue; + } + if (events.size()> 0){ + for(Event ev:events){ + printlog("===== State:" + ev.getState()); + printlog("===== TxHash:" + ev.getTxHash()); + printlog("===== GasConsumed:" + ev.getGasConsumed()); + + for(States state:ev.notify){ + + printlog("===== Notify - ContractAddress:" + state.getContractAddress()); + printlog("===== Notify - States[0]:" + state.getStates()[0]); + printlog("===== Notify - States[1]:" + state.getStates()[1]); + printlog("===== Notify - States[2]:" + state.getStates()[2]); + printlog("===== Notify - States[3]:" + state.getStates()[3]); + + if (ev.getState() == 1){ //exec succeed + Set keys = database.keySet(); + // + if ("transfer".equals(state.getStates()[0]) && keys.contains(state.getStates()[2])){ + BigInteger amount = new BigInteger(state.getStates()[3].toString()); + if (GAS_NATIVE_ADDRESS.equals(state.getContractAddress())){ + printlog("===== charge GAS :"+state.getStates()[2] +" ,amount:"+amount); + database.get(state.getStates()[2]).gasBalance = amount.add(database.get(state.getStates()[2]).gasBalance); + } + } + + //withdraw case + if("transfer".equals(state.getStates()[0]) && mainAccountAddr.toBase58().equals(state.getStates()[1])){ + + for(UserAcct ua: database.values()){ + if (ua.withdrawAddr.equals((state.getStates()[2]))){ + BigInteger amount = new BigInteger(state.getStates()[3].toString()); + if (GAS_NATIVE_ADDRESS.equals(state.getContractAddress())){ + printlog("===== widtdraw "+ amount +" gas to " + ua.withdrawAddr + " confirmed!"); + } + + } + } + + } + + } + + } + + } + } + + lastblocknum = height; + + + } + Thread.sleep(1000); + + }catch(Exception e){ + printlog("exception 1:"+ e.getMessage()); + } + } + } + }); + + //monitor the collect + Thread t2 = new Thread(new Runnable() { + @Override + public void run() { + try{ + while (true){ + + Set keys = database.keySet(); + + List gasAccts = new ArrayList() ; + List gasStates = new ArrayList(); + + + for(String key:keys){ + Object balance = dnaSdk.getConnect().getBalance(key); + printlog("----- balance of " + key + " : " + balance); + Balance b = JSON.parseObject(balance.toString(),Balance.class); + BigInteger gasbalance = new BigInteger(b.gas); + + + if (gasbalance.compareTo(new BigInteger("0")) > 0){ + //transfer gas to main wallet + UserAcct ua = database.get(key); + Account acct = new Account(ua.privkey,dnaSdk.defaultSignScheme); + gasAccts.add(acct); + State st = new State(Address.addressFromPubKey(acct.serializePublicKey()),mainAccountAddr,ua.gasBalance.longValue()); + gasStates.add(st); + } + } + + //construct gas transfer tx + if(gasStates.size() > 0) { + printlog("----- Will collect gas to main wallet"); + Transaction gasTx = dnaSdk.nativevm().gas().makeTransfer(gasStates.toArray(new State[gasStates.size()]), FEE_PROVIDER, 30000, 0); + for (Account act : gasAccts) { + dnaSdk.addSign(gasTx, act); + } + //add fee provider account sig + dnaSdk.addSign(gasTx, feeAct); + dnaSdk.getConnect().sendRawTransaction(gasTx.toHexString()); + } + + Thread.sleep(10000); + } + }catch (Exception e){ + e.printStackTrace(); + printlog("exception 2:"+e.getMessage()); + } + + } + }); + + t.start(); + t2.start(); + + Thread.sleep(2000); + printlog("++++ 2. charge some gas to acct1 from init account"); + Account initAccount = dnaSdk.getWalletMgr().getAccount(INIT_ACCT_ADDR,PWD,Base64.getDecoder().decode(INIT_ACCT_SALT)); + State st = new State(initAccount.getAddressU160(),acct1.getAddressU160(),1000L); + Transaction tx = dnaSdk.nativevm().gas().makeTransfer(new State[]{st}, FEE_PROVIDER, 30000, 0); + dnaSdk.addSign(tx,initAccount); + dnaSdk.addSign(tx, feeAct); + + dnaSdk.getConnect().sendRawTransaction(tx.toHexString()); + // test is the tx in txpool + String txhash = tx.hash().toHexString(); + printlog("++++ txhash :"+txhash); + Object event = dnaSdk.getConnect().getMemPoolTxState(txhash); + printlog(event.toString()); + + + printlog("++++ 3. charge some gas to acct1 from init account"); + st = new State(initAccount.getAddressU160(),acct1.getAddressU160(),1200L); + tx = dnaSdk.nativevm().gas().makeTransfer(new State[]{st}, FEE_PROVIDER, 30000, 0); + dnaSdk.addSign(tx,initAccount); + dnaSdk.addSign(tx, feeAct); + dnaSdk.getConnect().sendRawTransaction(tx.toHexString()); + + Thread.sleep(15000); + + //simulate a withdraw + //todo must add check the user balance of database + printlog("++++ withdraw 500 onts to " + usr.withdrawAddr ); + //reduce the withdraw amount first + BigInteger wdAmount = new BigInteger("500"); + + + //simulate a withdraw + printlog("++++ withdraw 500 gas to " + usr.withdrawAddr ); + wdAmount = new BigInteger("500"); + //reduce the withdraw amount first + if(usr.gasBalance.compareTo(wdAmount) > 0) { + database.get(usr.address).gasBalance = database.get(usr.address).gasBalance.subtract(wdAmount); + printlog("++++ " + usr.address + " gas balance : " + database.get(usr.address).gasBalance); + + State wdSt = new State(mainAccountAddr, Address.decodeBase58(usr.withdrawAddr), 500); + Transaction wdTx = dnaSdk.nativevm().gas().makeTransfer(new State[]{wdSt}, FEE_PROVIDER, 30000, 0); + dnaSdk.addMultiSign(wdTx, 3, new byte[][]{mutiSeedAct1.serializePublicKey(),mutiSeedAct2.serializePublicKey(),mutiSeedAct3.serializePublicKey()},mutiSeedAct1); + dnaSdk.addMultiSign(wdTx, 3, new byte[][]{mutiSeedAct1.serializePublicKey(),mutiSeedAct2.serializePublicKey(),mutiSeedAct3.serializePublicKey()},mutiSeedAct2); + dnaSdk.addMultiSign(wdTx, 3, new byte[][]{mutiSeedAct1.serializePublicKey(),mutiSeedAct2.serializePublicKey(),mutiSeedAct3.serializePublicKey()},mutiSeedAct3); + dnaSdk.addSign(wdTx, feeAct); + dnaSdk.getConnect().sendRawTransaction(wdTx.toHexString()); + } + + + + //claim gas + Object balance = dnaSdk.getConnect().getBalance(mainAccountAddr.toBase58()); + printlog("++++ before claime gas ,balance of "+ mainAccountAddr.toBase58() +" is " + balance); + String uGasAmt = dnaSdk.nativevm().gas().unboundGas(mainAccountAddr.toBase58()); + printlog("++++ unclaimed gas is " + uGasAmt); + if(new BigInteger(uGasAmt).compareTo(new BigInteger("0")) > 0) { + tx = dnaSdk.nativevm().gas().makeWithdrawGas(mainAccountAddr.toBase58(), mainAccountAddr.toBase58(), new BigInteger(uGasAmt).longValue(), FEE_PROVIDER, 30000, 0); + dnaSdk.addMultiSign(tx, 3, new byte[][]{mutiSeedAct1.serializePublicKey(),mutiSeedAct2.serializePublicKey(),mutiSeedAct3.serializePublicKey()},mutiSeedAct1); + dnaSdk.addMultiSign(tx, 3, new byte[][]{mutiSeedAct1.serializePublicKey(),mutiSeedAct2.serializePublicKey(),mutiSeedAct3.serializePublicKey()},mutiSeedAct2); + dnaSdk.addMultiSign(tx, 3, new byte[][]{mutiSeedAct1.serializePublicKey(),mutiSeedAct2.serializePublicKey(),mutiSeedAct3.serializePublicKey()},mutiSeedAct3); + dnaSdk.addSign(tx, feeAct); + dnaSdk.getConnect().sendRawTransaction(tx.toHexString()); + balance = dnaSdk.getConnect().getBalance(mainAccountAddr.toBase58()); + + Thread.sleep(10000); + printlog("++++ after claime gas ,balance of " + mainAccountAddr.toBase58() + " is " + balance); + //distribute gas to users in database + } + + t.join(); + t2.join(); + }catch (Exception e){ + e.printStackTrace(); + printlog("exception 3:" + e.getMessage()); + } + + + } + + + + + public static DnaSdk getDnaSdk() throws Exception { + + String ip = "http://127.0.0.1"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRestful()); + + String walletfile = "wallet.dat"; + wm.openWalletFile(walletfile); + + return wm; + } + + public static void printlog(String msg){ + System.out.println(msg); + } + + public static UserAcct getNewUserAcct(String id ,String pubkey,byte[] privkey,BigInteger ont,BigInteger gas){ + UserAcct acct = new UserAcct(); + acct.id = id; + acct.privkey = privkey; + acct.address = pubkey; + acct.gasBalance = gas; + + return acct; + } +} diff --git a/src/main/java/example/gas/GasDemo.java b/src/main/java/example/gas/GasDemo.java new file mode 100644 index 0000000..72b2176 --- /dev/null +++ b/src/main/java/example/gas/GasDemo.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package example.gas; + +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.crypto.SignatureScheme; + + +/** + * + */ +public class GasDemo { + public static String privatekey1 = "49855b16636e70f100cc5f4f42bc20a6535d7414fb8845e7310f8dd065a97221"; + public static String privatekey2 = "1094e90dd7c4fdfd849c14798d725ac351ae0d924b29a279a9ffa77d5737bd96"; + public static String privatekey3 = "bc254cf8d3910bc615ba6bf09d4553846533ce4403bc24f58660ae150a6d64cf"; + public static String privatekey4 = "06bda156eda61222693cc6f8488557550735c329bc7ca91bd2994c894cd3cbc8"; + public static String privatekey5 = "f07d5a2be17bde8632ec08083af8c760b41b5e8e0b5de3703683c3bdcfb91549"; + public static String privatekey6 = "0bc8c1f75a028672cd42c221bf81709dfc7abbbaf0d87cb6fdeaf9a20492c194"; + public static void main(String[] args) { + + try { + DnaSdk dnaSdk = getDnaSdk(); + String privatekey0 = "c19f16785b8f3543bbaf5e1dbb5d398dfa6c85aaad54fc9d71203ce83e505c07"; + privatekey0 = "523c5fcf74823831756f0bcb3634234f10b3beb1c05595058534577752ad2d9f"; + com.github.DNAProject.account.Account payerAcct = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey0),dnaSdk.defaultSignScheme); + com.github.DNAProject.account.Account acct0 = payerAcct; + com.github.DNAProject.account.Account acct1 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey1), dnaSdk.defaultSignScheme); + com.github.DNAProject.account.Account acct2 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey2), dnaSdk.defaultSignScheme); + com.github.DNAProject.account.Account acct3 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey3), dnaSdk.defaultSignScheme); + com.github.DNAProject.account.Account acct4 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey4), dnaSdk.defaultSignScheme); + com.github.DNAProject.account.Account acct5 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey5), dnaSdk.defaultSignScheme); + com.github.DNAProject.account.Account acct6 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey6), dnaSdk.defaultSignScheme); + System.out.println("acct0:" + acct0.getAddressU160().toBase58()); + System.out.println("acct1:" + acct1.getAddressU160().toBase58()); + System.out.println("acct2:" + acct2.getAddressU160().toBase58()); + + + if(true){//sendTransferFromMultiSignAddr + com.github.DNAProject.account.Account acct00 = new com.github.DNAProject.account.Account(Helper.hexToBytes("dcb22fdeb1cd57c4ad82c8dc21dd6792d4b1e90b5aa06d6698c03eacddabeb1f"),SignatureScheme.SM3WITHSM2); + com.github.DNAProject.account.Account acct01 = new com.github.DNAProject.account.Account(Helper.hexToBytes("f07d5a2be17bde8632ec08083af8c760b41b5e8e0b5de3703683c3bdcfb91549"),SignatureScheme.SM3WITHSM2); + com.github.DNAProject.account.Account acct02 = new com.github.DNAProject.account.Account(Helper.hexToBytes("49855b16636e70f100cc5f4f42bc20a6535d7414fb8845e7310f8dd065a97221"),SignatureScheme.SM3WITHSM2); + com.github.DNAProject.account.Account acct03 = new com.github.DNAProject.account.Account(Helper.hexToBytes("06bda156eda61222693cc6f8488557550735c329bc7ca91bd2994c894cd3cbc8"),SignatureScheme.SM3WITHSM2); + com.github.DNAProject.account.Account acct04 = new com.github.DNAProject.account.Account(Helper.hexToBytes("0638dff2f03964883471e1dac3df9e7738f21fd2452aef4846c11a53be6feb0e"),dnaSdk.defaultSignScheme); + com.github.DNAProject.account.Account acct05 = new com.github.DNAProject.account.Account(Helper.hexToBytes("46027c9786e24ecc1b4d7b406dfe90ec30b2c2fa6ad2f7963df251200e7f003d"),dnaSdk.defaultSignScheme); + com.github.DNAProject.account.Account acct06 = new com.github.DNAProject.account.Account(Helper.hexToBytes("523c5fcf74823831756f0bcb3634234f10b3beb1c05595058534577752ad2d9f"),dnaSdk.defaultSignScheme); + com.github.DNAProject.account.Account acct07 = new com.github.DNAProject.account.Account(Helper.hexToBytes("1094e90dd7c4fdfd849c14798d725ac351ae0d924b29a279a9ffa77d5737bd96"),dnaSdk.defaultSignScheme); + +// System.out.println("##"+Helper.toHexString(acct00.serializePublicKey())); +// System.out.println(Helper.toHexString(acct11.serializePublicKey())); +// System.out.println(Helper.toHexString(acct22.serializePublicKey())); +// System.out.println(Helper.toHexString(acct33.serializePublicKey())); + int M = 5; + com.github.DNAProject.account.Account[] accounts = new com.github.DNAProject.account.Account[]{acct00,acct01,acct02,acct03,acct04,acct05,acct06,acct07}; + byte[][] pks = new byte[accounts.length][]; + for(int i=0;i dids = sdk.getWalletMgr().getWallet().getIdentities(); + Identity identity = dids.get(0); + + + Identity adminDnaid = sdk.getWalletMgr().createIdentityFromPriKey(password,adminPrivateKey); +// Identity adminDnaid = sdk.getWalletMgr().getWallet().getIdentity(Common.diddna+adminDnaIdAcct.getAddressU160().toBase58()); + Account adminAccount = new Account(Helper.hexToBytes(adminPrivateKey),SignatureScheme.SHA256WITHECDSA); + Account adminAccount2 = new Account(Helper.hexToBytes(adminPrivateKey2),SignatureScheme.SHA256WITHECDSA); + System.out.println("account:" + sdk.getConnect().getBalance(account.getAddressU160().toBase58())); + System.out.println("account:" + account.getAddressU160().toBase58()); + System.out.println("account1:" + sdk.getConnect().getBalance(account1.getAddressU160().toBase58())); + + if(false){ + String contractAddr = "0000000000000000000000000000000000000007"; +// Identity adminDnaid = sdk.getWalletMgr().getWallet().getIdentity("did:dna:AazEvfQPcQ2GEFFPLF1ZLwQ7K5jDn81hve"); +// String txhash = sdk.nativevm().auth().assignFuncsToRole(adminDnaid.dnaid,password,adminDnaid.controls.get(0).getSalt(),1,contractAddr,"role",new String[]{"registerCandidate"},payerAcct,sdk.DEFAULT_GAS_LIMIT,0); + String txhash = sdk.nativevm().auth().assignDnaIdsToRole(adminDnaid.dnaid,password,adminDnaid.controls.get(0).getSalt(),1,contractAddr,"role",new String[]{identity.dnaid},payerAcct,sdk.DEFAULT_GAS_LIMIT,0); + Thread.sleep(6000); + Object obj = sdk.getConnect().getSmartCodeEvent(txhash); + System.out.println(obj); + + Object obj2 = sdk.nativevm().auth().verifyToken(identity.dnaid,password,identity.controls.get(0).getSalt(),1,contractAddr,"registerCandidate"); + System.out.println(obj2); + + } + if(false){ + sdk.nativevm().gas().sendTransfer(account1,Address.parse("0000000000000000000000000000000000000007").toBase58(),10000000000L,account1,20000,0); + Thread.sleep(6000); + + } + System.out.println("governance balance:" + sdk.getConnect().getBalance(Address.parse("0000000000000000000000000000000000000007").toBase58())); + if(true){ + String res = sdk.nativevm().governance().getSplitFeeAddress(account1.getAddressU160().toBase58()); + System.out.println("SplitFeeAddress:" + res); + } + if(false){ + sdk.getWalletMgr().importAccount("blDuHRtsfOGo9A79rxnJFo2iOMckxdFDfYe2n6a9X+jdMCRkNUfs4+C4vgOfCOQ5",password,account.getAddressU160().toBase58(),Base64.getDecoder().decode("0hAaO6CT+peDil9s5eoHyw==")); + + String txhash = sdk.nativevm().governance().registerCandidate(account1,"02a98c15099d599b55c87834fd41bf9ad55408050b32bdc6ea88d6358717e19525",10000,identity.dnaid,password,identity.controls.get(0).getSalt(),1,payerAcct,sdk.DEFAULT_GAS_LIMIT,0); +// String txhash = sdk.nativevm().governance().unRegisterCandidate(account,Helper.toHexString(account8.serializePublicKey()),payerAcct,sdk.DEFAULT_GAS_LIMIT,0); + Thread.sleep(6000); + Object obj = sdk.getConnect().getSmartCodeEvent(txhash); + System.out.println(obj); + + } + if(false){ + String txhash = sdk.nativevm().governance().withdrawFee(account1,account1,20000,0); +// String txhash = sdk.nativevm().governance().unAuthorizeForPeer(account1,new String[]{"02a98c15099d599b55c87834fd41bf9ad55408050b32bdc6ea88d6358717e19525"},new long[]{20000},account1,20000,0); +// String txhash = sdk.nativevm().governance().authorizeForPeer(account1,new String[]{"02a98c15099d599b55c87834fd41bf9ad55408050b32bdc6ea88d6358717e19525"},new long[]{2000000},account1,20000,0); +// String txhash = sdk.nativevm().governance().changeMaxAuthorization(account1,"02a98c15099d599b55c87834fd41bf9ad55408050b32bdc6ea88d6358717e19525",20000,payerAcct,sdk.DEFAULT_GAS_LIMIT,0); +// String txhash = sdk.nativevm().governance().setPeerCost(account1,"02a98c15099d599b55c87834fd41bf9ad55408050b32bdc6ea88d6358717e19525",90,payerAcct,sdk.DEFAULT_GAS_LIMIT,0); +// String txhash = sdk.nativevm().governance().unRegisterCandidate(account,Helper.toHexString(account8.serializePublicKey()),payerAcct,sdk.DEFAULT_GAS_LIMIT,0); + Thread.sleep(6000); + Object obj = sdk.getConnect().getSmartCodeEvent(txhash); + System.out.println(obj); + } + + if(false){ +// sdk.nativevm().governance().approveCandidate(multiAddress,5,new Account[]{account1,account2,account3,account4,account5},new byte[][]{account6.serializePublicKey(),account7s.serializePublicKey()}, +// "02a98c15099d599b55c87834fd41bf9ad55408050b32bdc6ea88d6358717e19525",account,sdk.DEFAULT_GAS_LIMIT,0); +// + String txhash = sdk.nativevm().governance().commitDpos(multiAddress,5,new Account[]{account1,account2,account3,account4,account5},new byte[][]{account6.serializePublicKey(),account7s.serializePublicKey()}, + account,sdk.DEFAULT_GAS_LIMIT,0); + +// sdk.nativevm().governance().rejectCandidate(multiAddress,5,new Account[]{account1,account2,account3,account4,account5},new byte[][]{account6.serializePublicKey(),account7s.serializePublicKey()}, +// "0205bc592aa9121428c4144fcd669ece1fa73fee440616c75624967f83fb881050",account,sdk.DEFAULT_GAS_LIMIT,0); + Thread.sleep(6000); +// System.out.println("txevent:" + sdk.getConnect().getSmartCodeEvent(txhash)); + } + if(false){ +// Identity adminDnaid = sdk.getWalletMgr().getWallet().getIdentity("did:dna:AazEvfQPcQ2GEFFPLF1ZLwQ7K5jDn81hve"); +// String txhash = sdk.nativevm().governance().approveCandidate(adminAccount2,Helper.toHexString(account8.serializePublicKey()),payerAcct,sdk.DEFAULT_GAS_LIMIT,0); +// String txhash = sdk.nativevm().governance().rejectCandidate(adminAccount2,Helper.toHexString(account8.serializePublicKey()),payerAcct,sdk.DEFAULT_GAS_LIMIT,0); +// String txhash = sdk.nativevm().governance().voteForPeer(account,new String[]{Helper.toHexString(account8.serializePublicKey())},new long[]{100},payerAcct,sdk.DEFAULT_GAS_LIMIT,0); +//String txhash = sdk.nativevm().governance().unVoteForPeer(account,new String[]{Helper.toHexString(account8.serializePublicKey())},new long[]{300},payerAcct,sdk.DEFAULT_GAS_LIMIT,0); +// String txhash = sdk.nativevm().governance().quitNode(account,Helper.toHexString(account8.serializePublicKey()),payerAcct,sdk.DEFAULT_GAS_LIMIT,0); + String txhash = sdk.nativevm().governance().withdraw(account,new String[]{"03e1e09221c9f513df76273f3cec0d033ee6056b159300d7b1072fc7020eadccbb"},new long[]{9999},payerAcct,sdk.DEFAULT_GAS_LIMIT,0); +// String txhash = sdk.nativevm().governance().commitDpos(adminAccount2,payerAcct,sdk.DEFAULT_GAS_LIMIT,0); + Thread.sleep(6000); + System.out.println(sdk.getConnect().getSmartCodeEvent(txhash)); +// System.out.println("account9" +sdk.getConnect().getBalance( account9.getAddressU160().toBase58())); + } + if(true) { + System.out.println("account:" + sdk.getConnect().getBalance(account.getAddressU160().toBase58())); + String res = sdk.nativevm().governance().getPeerInfoAll(); + JSONObject jsr = JSONObject.parseObject(res); +// System.out.println(Helper.toHexString(account7.serializePublicKey())); + String voteInfo= sdk.nativevm().governance().getAuthorizeInfo("02a98c15099d599b55c87834fd41bf9ad55408050b32bdc6ea88d6358717e19525",account.getAddressU160()); + if(voteInfo != null) { + System.out.println("voteInfo:" + voteInfo); + } + + String aa = sdk.nativevm().governance().getPeerAttributes("02a98c15099d599b55c87834fd41bf9ad55408050b32bdc6ea88d6358717e19525"); + System.out.println("PeerAttributes:" + aa); + +// System.out.println("peerInfo:" + jsr.getString(Helper.toHexString(account9.serializePublicKey()))); + System.out.println("peerInfo2:" + sdk.nativevm().governance().getPeerInfo("02a98c15099d599b55c87834fd41bf9ad55408050b32bdc6ea88d6358717e19525")); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static Account getAccount(String enpri,String password,String address,String salt) throws Exception { + String privateKey = Account.getGcmDecodedPrivateKey(enpri,password,address,Base64.getDecoder().decode(salt),16384,SignatureScheme.SHA256WITHECDSA); + Account account = new Account(Helper.hexToBytes(privateKey),SignatureScheme.SHA256WITHECDSA); +// System.out.println(Helper.toHexString(account.serializePublicKey())); + return account; + } + + + + public static DnaSdk getDnaSdk() throws Exception { +// String ip = "http://127.0.0.1"; + String ip= "http://139.219.128.220"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRpc()); + wm.openWalletFile("GovernanceDemo.json"); + return wm; + } +} diff --git a/src/main/java/example/governance/GovernanceDemo2.java b/src/main/java/example/governance/GovernanceDemo2.java new file mode 100644 index 0000000..e56b230 --- /dev/null +++ b/src/main/java/example/governance/GovernanceDemo2.java @@ -0,0 +1,204 @@ +package example.governance; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.common.NotifyEventInfo; +import com.github.DNAProject.core.governance.*; +import com.github.DNAProject.crypto.SignatureScheme; + +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; +import java.util.Map; + +public class GovernanceDemo2 { + + public static void main(String[] args) throws Exception { + String privateKey = Account.getGcmDecodedPrivateKey("8p2q0vLRqyfKmFHhnjUYVWOm12kPm78JWqzkTOi9rrFMBz624KjhHQJpyPmiSSOa","111111","AHX1wzvdw9Yipk7E9MuLY4GGX4Ym9tHeDe",Base64.getDecoder().decode("KbiCUr53CZUfKG1M3Gojjw=="),16384,SignatureScheme.SHA256WITHECDSA); + Account account = new Account(Helper.hexToBytes(privateKey), SignatureScheme.SHA256WITHECDSA); + //梦航 + Account account1 = getAccount("wR9S/JYwMDfCPWFGEy5DEvWfU14k9suZuL4+woGtfhZJf5+KyL9VJqMi/wGTOd1i","passwordtest","AZqk4i7Zhfhc1CRUtZYKrLw4YTSq4Y9khN","ZaIL8DxNaQ91fkMHAdiBjQ=="); + Account account2 = getAccount("PCj/a4zUgYnOBNZUVEaXBK61Sq4due8w2RUzrumO3Bm0hZ/3v4mlDiXYYvmmBZUk","passwordtest","ARpjnrnHEjXhg4aw7vY6xsY6CfQ1XEWzWC","wlz1h439j0GwsWhGBByMxg=="); + Account account3 = getAccount("4U6qYhRUxGYTcvDvBKKCu2C1xUyd0A+pHXsK1YVY1Hbxd8TcbyvmfOcqx7N+f+BH","passwordtest","AQs2BmzzFVk7pQPfTQQi9CTEz43ejSyBnt","AFDFoZAlLGJdB4yVQqYVhw=="); + Account account4 = getAccount("i6n+FTACzRF5y0oeo6Wm3Zbv68bfjmyRyNfKB5IArK76RCG8b/JgRqnHgMtHixFx","passwordtest","AKBSRLbFNvUrWEGtKxNTpe2ZdkepQjYKfM","FkTZ6czRPAqHnSpEqVEWwA=="); + Account account5 = getAccount("IoEbJXMPlxNLrAsDYKGD4I6oFYgJl1j603c8oHQl+82yET+ibKgJdZjgdw39pr2K","passwordtest","AduX7odaWGipkdvzBwyaTgsumRbRzhhiwe","lc7ofKCBkNUmjTLrZYmStA=="); + Account account6 = getAccount("6hynBJVTAhmMJt9bIYSDoz+GL5EFaUGhn3Pd6HsF+RQ1tFyZoFRhT+JNMGAb+B6a","passwordtest","ANFfWhk3A5iFXQrVBHKrerjDDapYmLo5Bi","DTmbW9wzGA8pi4Dcj3/Cpg=="); + Account account7 = getAccount("EyXxszzKh09jszQXMIFJTmbujnojOzYzPU4cC0wOpuegDgVcRFllATQ81zD0Rp8s","passwordtest","AK3YRcRvKrASQ6nTfW48Z4iMZ2sDTDRiMC","jbwUF7JxgsiJq5QAy5dfug=="); + Address multiAddress = Address.addressFromMultiPubKeys(5,account1.serializePublicKey(),account2.serializePublicKey(),account3.serializePublicKey(),account4.serializePublicKey(),account5.serializePublicKey(),account6.serializePublicKey(),account7.serializePublicKey()); + Account[] accounts = new Account[]{account1,account2,account3,account4,account5,account6,account7}; + Account[] accounts1 = new Account[]{account1,account2,account3,account4,account5}; + byte[][] pks = new byte[accounts.length][]; + for(int i=0;i list = new ArrayList<>(); + list.add("hahaha"); + info.setStates(list); + System.out.println(info); + System.out.println(info.toJson()); + return; + } + + + + if(false){ + sdk.setRpc("http://139.219.128.220:20336"); +// System.out.println(multiAddress.toBase58()); +// System.out.println(sdk.getConnect().getBalance(multiAddress.toBase58())); + System.out.println(sdk.getConnect().getSideChainData("123456")); + return; + } + + + if(false){ + String txhash = sdk.nativevm().governance().commitDpos(multiAddress,5,new Account[]{account1,account2,account3,account4,account5},new byte[][]{account6.serializePublicKey(),account7.serializePublicKey()}, + account1,sdk.DEFAULT_GAS_LIMIT,0); + + Thread.sleep(6000); + System.out.println(sdk.getConnect().getSmartCodeEvent(txhash)); + return; + } + if(false){ + GovernanceView view = sdk.nativevm().governance().getGovernanceView(); + System.out.println(JSON.toJSONString(view)); + } + if(false){ +// success + GlobalParam1 param1 = sdk.nativevm().governance().getGlobalParam1(); + GlobalParam2 param2 = sdk.nativevm().governance().getGlobalParam2(); + System.out.println(JSON.toJSONString(param1)); + System.out.println(JSON.toJSONString(param2)); + System.out.println(Long.MAX_VALUE); + param1.candidateFee = (long)1000*1000000000; + String txhash = sdk.nativevm().governance().updateGlobalParam1(accounts1,pks,5,param1,account,20000,0); + Thread.sleep(6000); + System.out.println(sdk.getConnect().getSmartCodeEvent(txhash)); + GlobalParam1 param11 = sdk.nativevm().governance().getGlobalParam1(); + GlobalParam2 param22 = sdk.nativevm().governance().getGlobalParam2(); + System.out.println(JSON.toJSONString(param11)); + System.out.println(JSON.toJSONString(param22)); + return; + } + if(false){ +// success + GlobalParam2 param2 = sdk.nativevm().governance().getGlobalParam2(); + if(param2 == null){ + param2 = new GlobalParam2(1000,1,Helper.hexToBytes("00"),Helper.hexToBytes("00"), + Helper.hexToBytes("00"),Helper.hexToBytes("00"),Helper.hexToBytes("00"),Helper.hexToBytes("00")); + } + System.out.println(JSON.toJSONString(param2)); + String txhash = sdk.nativevm().governance().updateGlobalParam2(accounts1,pks,5,param2,account,20000,0); + Thread.sleep(6000); + System.out.println(sdk.getConnect().getSmartCodeEvent(txhash)); + GlobalParam2 param22 = sdk.nativevm().governance().getGlobalParam2(); + System.out.println(JSON.toJSONString(param22)); + } + + if(false){ +// success + InputPeerPoolMapParam param= sdk.nativevm().governance().getInputPeerPoolMapParam("123456"); + System.out.println(JSON.toJSONString(param)); + return; + } + + if(false){ +// success + SplitCurve curve = sdk.nativevm().governance().getSplitCurve(); + System.out.println(JSON.toJSONString(curve)); + curve.Yi[0] = 0; + String txhash = sdk.nativevm().governance().updateSplitCurve(accounts, pks,5,curve,account,20000,0); + System.out.println(txhash); + Thread.sleep(6000); + System.out.println(sdk.getConnect().getSmartCodeEvent(txhash)); + SplitCurve curve2 = sdk.nativevm().governance().getSplitCurve(); + System.out.println(JSON.toJSONString(curve2)); + return; + } + if(false){ + System.out.println(sdk.nativevm().governance().getPeerInfoAll()); + return; + } + + if(false){ + Map m = sdk.nativevm().governance().getPeerPoolMap(); + System.out.println(m); + } + if(false){ + Configuration c = sdk.nativevm().governance().getConfiguration(); + System.out.println(c); + } + if(false){ + GlobalParam param = sdk.nativevm().governance().getGlobalParam(); + System.out.println(param); + } + if(false){ + SplitCurve curve = sdk.nativevm().governance().getSplitCurve(); + System.out.println(curve); + } + if(false){ + GovernanceView view = sdk.nativevm().governance().getGovernanceView(); + System.out.println(view); + return; + } + if(false){ + InputPeerPoolMapParam param = sdk.nativevm().governance().getInputPeerPoolMapParam("123456"); + System.out.println(param); + } + if(true){ + Configuration c = sdk.nativevm().governance().getConfiguration(); + System.out.println(JSON.toJSONString(c)); + return; + + } + if(true){ + sdk.setRpc("http://139.219.128.220:20336"); + Configuration c = new Configuration(8,3,8,128,10000,10000,10,10000); + String txhash = sdk.nativevm().governance().updateConfig(accounts1,pks,5,c,account1,20000,0); + System.out.println(txhash); + Thread.sleep(6000); + System.out.println(sdk.getConnect().getSmartCodeEvent(txhash)); + return; + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static Account getAccount(String enpri,String password,String address,String salt) throws Exception { + String privateKey = Account.getGcmDecodedPrivateKey(enpri,password,address,Base64.getDecoder().decode(salt),16384,SignatureScheme.SHA256WITHECDSA); + Account account = new Account(Helper.hexToBytes(privateKey),SignatureScheme.SHA256WITHECDSA); +// System.out.println(Helper.toHexString(account.serializePublicKey())); + return account; + } + + + public static DnaSdk getDnaSdk() throws Exception { + String ip = "http://127.0.0.1"; +// String ip = "http://139.219.128.60"; +// String ip = "http://139.219.129.55"; +// String ip = "http://101.132.193.149"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRpc()); + wm.openWalletFile("GovernanceDemo.json"); + return wm; + } +} diff --git a/src/main/java/example/oep/Oep4Demo.java b/src/main/java/example/oep/Oep4Demo.java new file mode 100644 index 0000000..6c784a3 --- /dev/null +++ b/src/main/java/example/oep/Oep4Demo.java @@ -0,0 +1,192 @@ +package example.oep; + +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.asset.State; +import com.github.DNAProject.crypto.SignatureScheme; + +import java.math.BigInteger; +import java.util.Base64; + +public class Oep4Demo { + public static String privatekey0 = "523c5fcf74823831756f0bcb3634234f10b3beb1c05595058534577752ad2d9f"; + public static String privatekey1 = "49855b16636e70f100cc5f4f42bc20a6535d7414fb8845e7310f8dd065a97221"; + public static String privatekey2 = "1094e90dd7c4fdfd849c14798d725ac351ae0d924b29a279a9ffa77d5737bd96"; + public static String privatekey3 = "bc254cf8d3910bc615ba6bf09d4553846533ce4403bc24f58660ae150a6d64cf"; + public static String privatekey4 = "06bda156eda61222693cc6f8488557550735c329bc7ca91bd2994c894cd3cbc8"; + public static String privatekey5 = "f07d5a2be17bde8632ec08083af8c760b41b5e8e0b5de3703683c3bdcfb91549"; + + public static void main(String[] args) { + try { + DnaSdk dnaSdk = getDnaSdk(); + if(false){ + System.out.println(BigInteger.ZERO.toString()); + return; + } + String privateKey = Account.getGcmDecodedPrivateKey("8p2q0vLRqyfKmFHhnjUYVWOm12kPm78JWqzkTOi9rrFMBz624KjhHQJpyPmiSSOa","111111","AHX1wzvdw9Yipk7E9MuLY4GGX4Ym9tHeDe",Base64.getDecoder().decode("KbiCUr53CZUfKG1M3Gojjw=="),16384,SignatureScheme.SHA256WITHECDSA); +// Account account = sdk.getWalletMgr().getAccount("AQf4Mzu1YJrhz9f3aRkkwSm9n3qhXGSh4p", "xinhao"); + System.out.println(privateKey); + Account account = new Account(Helper.hexToBytes(privateKey),SignatureScheme.SHA256WITHECDSA); + Account acct1 = new Account(Helper.hexToBytes(privatekey1), dnaSdk.defaultSignScheme); + Account acct2 = new Account(Helper.hexToBytes(privatekey2), dnaSdk.defaultSignScheme); + Account acct3 = new Account(Helper.hexToBytes(privatekey3), dnaSdk.defaultSignScheme); + Account acct4 = new Account(Helper.hexToBytes(privatekey4), dnaSdk.defaultSignScheme); + Account acct5 = new Account(Helper.hexToBytes(privatekey5), dnaSdk.defaultSignScheme); + + Account acct = new Account(Helper.hexToBytes(privatekey0), dnaSdk.defaultSignScheme); + System.out.println("recv:"+acct.getAddressU160().toBase58()); + System.out.println("send:"+account.getAddressU160().toBase58()); +// System.out.println(Helper.toHexString(acct1.getAddressU160().toArray())); +// +// showBalance(dnaSdk,new Account[]{acct1,acct2,acct3}); +// System.out.println("------------------------------------------------------"); +//System.exit(0); + + if(false){ + System.out.println(acct.getAddressU160().toBase58()); + return; + } + + if(false) { +// long gasLimit = dnaSdk.neovm().oep4().sendInitPreExec(acct,acct,30000,0); +// System.out.println(gasLimit); + String result = dnaSdk.neovm().oep4().sendInit(acct,account,20000,500); + System.out.println(result); + Thread.sleep(6000); + System.out.println(dnaSdk.getConnect().getSmartCodeEvent(result)); + System.exit(0); + } + if(true){ +// System.out.println(Helper.toHexString(account.getAddressU160().toArray())); + System.out.println(dnaSdk.neovm().oep4().queryDecimals()); + System.out.println(dnaSdk.neovm().oep4().queryName()); + System.out.println(dnaSdk.neovm().oep4().querySymbol()); + System.out.println(dnaSdk.neovm().oep4().queryTotalSupply()); + System.out.println(acct.getAddressU160().toBase58()+": "+dnaSdk.neovm().oep4().queryBalanceOf(acct.getAddressU160().toBase58())); + System.out.println(account.getAddressU160().toBase58()+": "+dnaSdk.neovm().oep4().queryBalanceOf(account.getAddressU160().toBase58())); + //return; + } + + if(false){ //transfer amount is long + //showBalance(dnaSdk,new Account[]{account,acct}); + String txhash = dnaSdk.neovm().oep4().sendTransfer(account, acct.getAddressU160().toBase58(),1000,account,20000,500); + //Thread.sleep(6000); + //showBalance(dnaSdk,new Account[]{account,acct}); + return; + } + if(false){ //transfer amount is BigInteger + //showBalance(dnaSdk,new Account[]{account,acct}); + Object txhash = dnaSdk.neovm().oep4().sendTransfer(acct, account.getAddressU160().toBase58(),new BigInteger("9999999999999999999999999"),acct,20000,500,false); + //Object txhash = dnaSdk.neovm().oep4().sendTransfer(account, acct.getAddressU160().toBase58(),new BigInteger("10000000000000000000000000"),acct,20000,500,false); + System.out.println(txhash); + //Thread.sleep(6000); + //showBalance(dnaSdk,new Account[]{account,acct}); + return; + } + if(false){ + showBalance(dnaSdk,new Account[]{account,acct, acct1}); + Account[] accounts = new Account[]{account,acct}; + State state = new State(account.getAddressU160(),acct.getAddressU160(),10); + State state2 = new State(account.getAddressU160(),acct1.getAddressU160(),10); + String txhash = dnaSdk.neovm().oep4().sendTransferMulti(accounts, new State[]{state,state2},account,20000,500); + Thread.sleep(6000); + showBalance(dnaSdk,new Account[]{account,acct,acct1}); + return; + } + if(false){ + System.out.println(dnaSdk.neovm().oep4().queryAllowance(account.getAddressU160().toBase58(),acct1.getAddressU160().toBase58())); + + String txhash = dnaSdk.neovm().oep4().sendApprove(account,acct1.getAddressU160().toBase58(),1000,account,20000,500); + Thread.sleep(6000); + System.out.println(dnaSdk.getConnect().getSmartCodeEvent(txhash)); + System.out.println(dnaSdk.neovm().oep4().queryAllowance(account.getAddressU160().toBase58(),acct1.getAddressU160().toBase58())); + return; + } + if(true){ + System.out.println(dnaSdk.neovm().oep4().queryAllowance(account.getAddressU160().toBase58(),acct1.getAddressU160().toBase58())); + + String txhash = dnaSdk.neovm().oep4().sendTransferFrom(acct1,account.getAddressU160().toBase58(),acct1.getAddressU160().toBase58(),1000,account,20000,500); + Thread.sleep(6000); + System.out.println(dnaSdk.getConnect().getSmartCodeEvent(txhash)); + System.out.println(dnaSdk.neovm().oep4().queryAllowance(account.getAddressU160().toBase58(),acct1.getAddressU160().toBase58())); + return; + } + + + String multiAddr = Address.addressFromMultiPubKeys(2,acct.serializePublicKey(),acct2.serializePublicKey()).toBase58(); + System.out.println("multiAddr:"+multiAddr); + if(false) { + dnaSdk.neovm().oep4().sendTransfer(acct1, acct2.getAddressU160().toBase58(), 1000000000L, acct, 20000, 0); + Thread.sleep(6000); + showBalance(dnaSdk,new Account[]{acct1,acct2,acct3}); + + System.exit(0); + } + if(false){ + dnaSdk.neovm().oep4().sendApprove(acct1, acct2.getAddressU160().toBase58(), 1000000000L, acct, 20000, 0); + Thread.sleep(6000); + showBalance(dnaSdk,new Account[]{acct1,acct2,acct3}); + System.exit(0); + } + if(true){ + dnaSdk.neovm().oep4().queryAllowance(acct1.getAddressU160().toBase58(), acct2.getAddressU160().toBase58()); + Thread.sleep(6000); + showBalance(dnaSdk,new Account[]{acct1,acct2,acct3}); + } + if(false){ + dnaSdk.neovm().oep4().sendTransferFrom(acct1, acct2.getAddressU160().toBase58(),acct1.getAddressU160().toBase58(), 1000000000L, acct, 20000, 0); + Thread.sleep(6000); + showBalance(dnaSdk,new Account[]{acct1,acct2,acct3}); + System.exit(0); + } + + if(false){ + Account[] accounts = new Account[]{acct1,acct2}; + State[] states = new State[]{new State(acct1.getAddressU160(),acct3.getAddressU160(),100),new State(acct2.getAddressU160(),acct4.getAddressU160(),200)}; + String txhash = dnaSdk.neovm().oep4().sendTransferMulti(accounts,states,acct1,20000,0); + return; + } + +// String balance = dnaSdk.neovm().oep4().queryBalanceOf(acct.getAddressU160().toBase58()); +// System.out.println(new BigInteger(Helper.reverse(Helper.hexToBytes(balance))).longValue()); +// balance = dnaSdk.neovm().oep4().queryBalanceOf(multiAddr); +// System.out.println(new BigInteger(Helper.reverse(Helper.hexToBytes(balance))).longValue()); +// System.exit(0); + + if(false) { + String name = dnaSdk.neovm().oep4().queryName(); + System.out.println(new String(Helper.hexToBytes(name))); + String symbol = dnaSdk.neovm().oep4().querySymbol(); + System.out.println(new String(Helper.hexToBytes(symbol))); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void showBalance(DnaSdk dnaSdk, Account[] accounts) throws Exception { + for (int i=0;i nodes = Arrays.asList(ip1, ip2, ip3, ip4); + static String curIp = ip1; + + public static void main(String[] args) { + try { + DnaSdk dnaSdk = Oep4MultiTheadDemo.getDnaSdk(); + for (int i = 0; i < 1; i++) { + startThread(dnaSdk, "Thread 1", "55e02438c938f6f4eb15a9cb315b26d0169b7fd7"); + startThread(dnaSdk, "Thread 2", "547d89289f75648cbda8c1c8ccf4e83ebd01240a"); + startThread(dnaSdk, "Thread 3", "25277b421a58cfc2ef5836767e54eb7abdd31afd"); + startThread(dnaSdk, "Thread 4", "9f612aff420d11dc781be892545346607d13fd8f"); + startThread(dnaSdk, "Thread 5", "e32a9cfcb91737e27246493d8a067d438d1f650e"); + } + while (true) { + Thread.sleep(1000); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void startThread(DnaSdk dnaSdk, String threadName, String contractAddress) { + + Thread thread = new Thread() { + @Override + public void run() { + String tmpIp = ""; + for (int i = 0; i < 10000; i++) { + try { + tmpIp = curIp; // this is important + Oep4 oep4 = new Oep4(dnaSdk); + oep4.setContractAddress(contractAddress); + String tokenname = oep4.queryName(); + String total = oep4.queryTotalSupply(); + System.out.println(threadName + ": " + tokenname + " " + total); + Thread.sleep(10); + } catch (RestfulException e) { + System.err.println(e.getMessage()); + switchNode(dnaSdk,tmpIp); + } catch (Exception e1) { + e1.printStackTrace(); + } + } + + } + }; + thread.start(); + } + + public static void switchNode(DnaSdk dnaSdk, String reqIp) { + try { + if(!reqIp.equals(curIp)){ + return; + } + for (int i = 0; i < nodes.size(); i++) { + String ip = nodes.get(i); + if (i == nodes.size() - 1) { + curIp = nodes.get(0); + break; + } else if (ip.equals(curIp)) { + curIp = nodes.get(i + 1); + break; + } + } + String restUrl = curIp + ":" + "20334"; + dnaSdk.setRestful(restUrl); + dnaSdk.setDefaultConnect(dnaSdk.getRestful()); + } catch (SDKException e) { + e.printStackTrace(); + } + } + + public static DnaSdk getDnaSdk() throws Exception { + String restUrl = curIp + ":" + "20334"; + String rpcUrl = curIp + ":" + "20336"; + String wsUrl = curIp + ":" + "20335"; + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRestful()); + wm.openWalletFile("AccountDemo.json"); + return wm; + } +} diff --git a/src/main/java/example/oep/Oep5Demo.java b/src/main/java/example/oep/Oep5Demo.java new file mode 100644 index 0000000..c2320e6 --- /dev/null +++ b/src/main/java/example/oep/Oep5Demo.java @@ -0,0 +1,125 @@ +package example.oep; + +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.smartcontract.neovm.oep5.Oep5Param; + +public class Oep5Demo { + public static void main(String[] args) { + try { + DnaSdk sdk = getDnaSdk(); + Account account = sdk.getWalletMgr().getAccount("AQf4Mzu1YJrhz9f3aRkkwSm9n3qhXGSh4p", "xinhao"); + Account account1 = sdk.getWalletMgr().getAccount("ARR5ywDEx3ybXkMGmZPFYu9hiC8J4xvNdc", "xinhao"); + Account account2 = sdk.getWalletMgr().getAccount("AacHGsQVbTtbvSWkqZfvdKePLS6K659dgp", "xinhao"); + if (false){ +// success + System.out.println(sdk.getConnect().getContract("c112e68684f23af1181ed6457f7640d161b8e0dc")); + String txhash = sdk.neovm().oep5().sendInit(account, account,281803, 0); + return; + } + if (false){ +// success + String name = sdk.neovm().oep5().queryName(); + System.out.println("name: " + name); + String totalsupply = sdk.neovm().oep5().queryTotalSupply(); + System.out.println("symbol: " + sdk.neovm().oep5().querySymbol()); + System.out.println("totalsupply: " + totalsupply); + + String balance = sdk.neovm().oep5().queryBalanceOf(account.getAddressU160().toBase58()); + System.out.println("balance: " + balance); + + return; + } + if(false){ +//success + System.out.println("tokenId:" + sdk.neovm().oep5().queryTokenIDByIndex(1)); + return; + } + if (false){ +//success + String tokenId2 = sdk.neovm().oep5().queryTokenIDByIndex(2); + String tokenId3 = sdk.neovm().oep5().queryTokenIDByIndex(3); + String res = sdk.neovm().oep5().ownerOf(Helper.hexToBytes(tokenId2)); + System.out.println("owner2: " + new Address(Helper.hexToBytes(res)).toBase58()); + String res3 = sdk.neovm().oep5().ownerOf(Helper.hexToBytes(tokenId3)); + System.out.println("owner3: " + new Address(Helper.hexToBytes(res3)).toBase58()); + return; + } + + if (false){ +// success + byte[] tokenId = Helper.hexToBytes("468c0424abd5fb0ba5f0cbbe64a538a80e1e8d45e5735e41ad38059eb8031b76"); + Oep5Param param = new Oep5Param(account1.getAddressU160().toArray(), tokenId); + String txhash = sdk.neovm().oep5().transfer(account,param,account,20000,0); + System.out.println("txhash: " + txhash); + Thread.sleep(6000); + String res = sdk.neovm().oep5().ownerOf(Helper.hexToBytes("468c0424abd5fb0ba5f0cbbe64a538a80e1e8d45e5735e41ad38059eb8031b76")); + System.out.println("owner: " + new Address(Helper.hexToBytes(res)).toBase58()); + return; + } + if (false){ +// success + String tokenId2 = sdk.neovm().oep5().queryTokenIDByIndex(2); + String tokenId3 = sdk.neovm().oep5().queryTokenIDByIndex(3); +// Account[] accounts = new Account[]{account}; +// Oep5Param param = new Oep5Param(account1.getAddressU160().toArray(), Helper.hexToBytes(tokenId2)); +// Oep5Param param2 = new Oep5Param(account1.getAddressU160().toArray(), Helper.hexToBytes(tokenId3)); +// String res = sdk.neovm().oep5().transferMulti(accounts,new Oep5Param[]{param,param2}, account, 27195, 0); +// System.out.println("res: " + res); +// Thread.sleep(3000); +// System.out.println(sdk.getConnect().getSmartCodeEvent(res)); + + + String res2 = sdk.neovm().oep5().ownerOf(Helper.hexToBytes(tokenId2)); + System.out.println("owner2: " + new Address(Helper.hexToBytes(res2)).toBase58()); + String res3 = sdk.neovm().oep5().ownerOf(Helper.hexToBytes(tokenId3)); + System.out.println("owner3: " + new Address(Helper.hexToBytes(res3)).toBase58()); + return; + } + if (false){ + String tokenId1 = sdk.neovm().oep5().queryTokenIDByIndex(1); +// Oep5Param param = new Oep5Param(account1.getAddressU160().toArray(), Helper.hexToBytes(tokenId1)); +// String res = sdk.neovm().oep5().approve(account,param, account, 20000, 0); +// System.out.println("res: " + res); +// Thread.sleep(6000); +// System.out.println(sdk.getConnect().getSmartCodeEvent(res)); + System.out.println(new Address(Helper.hexToBytes(sdk.neovm().oep5().getApproved(tokenId1))).toBase58()); + return; + } + if (true){ + String tokenId1 = sdk.neovm().oep5().queryTokenIDByIndex(1); + String res0 = sdk.neovm().oep5().ownerOf(Helper.hexToBytes(tokenId1)); + System.out.println("owner1: " + new Address(Helper.hexToBytes(res0)).toBase58()); + + Oep5Param param = new Oep5Param(account1.getAddressU160().toArray(), Helper.hexToBytes(tokenId1)); + String res = sdk.neovm().oep5().takeOwnership(account1,param, account1, 20000, 0); + System.out.println("res: " + res); + Thread.sleep(6000); + System.out.println(sdk.getConnect().getSmartCodeEvent(res)); + String res1 = sdk.neovm().oep5().ownerOf(Helper.hexToBytes(tokenId1)); + System.out.println("owner1: " + new Address(Helper.hexToBytes(res1)).toBase58()); + return; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static DnaSdk getDnaSdk() throws Exception { + String ip = "http://127.0.0.1"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRestful()); + + wm.neovm().oep5().setContractAddress("6d16074febe9a2db0099570916bcb412787265ea"); + wm.openWalletFile("oep5.dat"); + return wm; + } +} \ No newline at end of file diff --git a/src/main/java/example/oep/Oep8Demo.java b/src/main/java/example/oep/Oep8Demo.java new file mode 100644 index 0000000..2cc194e --- /dev/null +++ b/src/main/java/example/oep/Oep8Demo.java @@ -0,0 +1,206 @@ +package example.oep; + +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.crypto.SignatureScheme; +import com.github.DNAProject.smartcontract.neovm.oep8.Oep8State; +import com.github.DNAProject.smartcontract.neovm.oep8.TransferFrom; + +import java.util.Base64; + +public class Oep8Demo { + public static void main(String[] args) { + try { + DnaSdk sdk = getDnaSdk(); + String privateKey = Account.getGcmDecodedPrivateKey("8p2q0vLRqyfKmFHhnjUYVWOm12kPm78JWqzkTOi9rrFMBz624KjhHQJpyPmiSSOa","111111","AHX1wzvdw9Yipk7E9MuLY4GGX4Ym9tHeDe",Base64.getDecoder().decode("KbiCUr53CZUfKG1M3Gojjw=="),16384,SignatureScheme.SHA256WITHECDSA); +// Account account = sdk.getWalletMgr().getAccount("AQf4Mzu1YJrhz9f3aRkkwSm9n3qhXGSh4p", "xinhao"); + Account account1 = sdk.getWalletMgr().getAccount("ARR5ywDEx3ybXkMGmZPFYu9hiC8J4xvNdc", "xinhao"); + Account account2 = sdk.getWalletMgr().getAccount("AacHGsQVbTtbvSWkqZfvdKePLS6K659dgp", "xinhao"); + Account account = new Account(Helper.hexToBytes(privateKey),SignatureScheme.SHA256WITHECDSA); + if (false){ + System.out.println(privateKey); + String txhash = sdk.neovm().oep8().sendInit(account1, account,200000, 500); + System.out.println(txhash); + Thread.sleep(6000); + System.out.println(sdk.getConnect().getSmartCodeEvent(txhash)); + return; + } + byte[] tokenId1 = Helper.hexToBytes("01"); + byte[] tokenId2 = Helper.hexToBytes("02"); + byte[] tokenId3 = Helper.hexToBytes("03"); + byte[] tokenId4 = Helper.hexToBytes("04"); + byte[] tokenId5 = Helper.hexToBytes("05"); + byte[] tokenId6 = Helper.hexToBytes("06"); + byte[] tokenId7 = Helper.hexToBytes("07"); + byte[] tokenId8 = Helper.hexToBytes("08"); + if (true){ + String name = sdk.neovm().oep8().queryName(tokenId1); + System.out.println("name: " + name); + System.out.println(sdk.neovm().oep8().queryName(tokenId2)); + System.out.println(sdk.neovm().oep8().queryName(tokenId3)); + System.out.println(sdk.neovm().oep8().queryName(tokenId4)); + System.out.println(sdk.neovm().oep8().queryName(tokenId5)); + System.out.println(sdk.neovm().oep8().queryName(tokenId6)); + System.out.println(sdk.neovm().oep8().queryName(tokenId7)); + System.out.println(sdk.neovm().oep8().queryName(tokenId8)); + return; + } + if(true){ + System.out.println("totalsupply: " + sdk.neovm().oep8().queryTotalSupply(tokenId1)); + System.out.println("totalsupply: " + sdk.neovm().oep8().queryTotalSupply(tokenId2)); + System.out.println("totalsupply: " + sdk.neovm().oep8().queryTotalSupply(tokenId3)); + System.out.println("totalsupply: " + sdk.neovm().oep8().queryTotalSupply(tokenId4)); + System.out.println("totalsupply: " + sdk.neovm().oep8().queryTotalSupply(tokenId5)); + System.out.println("totalsupply: " + sdk.neovm().oep8().queryTotalSupply(tokenId6)); + System.out.println("totalsupply: " + sdk.neovm().oep8().queryTotalSupply(tokenId7)); + System.out.println("totalsupply: " + sdk.neovm().oep8().queryTotalSupply(tokenId8)); + System.out.println("symbol: " + sdk.neovm().oep8().querySymbol(tokenId1)); + System.out.println("symbol: " + sdk.neovm().oep8().querySymbol(tokenId2)); + System.out.println("symbol: " + sdk.neovm().oep8().querySymbol(tokenId3)); + System.out.println("symbol: " + sdk.neovm().oep8().querySymbol(tokenId4)); + System.out.println("symbol: " + sdk.neovm().oep8().querySymbol(tokenId5)); + System.out.println("symbol: " + sdk.neovm().oep8().querySymbol(tokenId6)); + System.out.println("symbol: " + sdk.neovm().oep8().querySymbol(tokenId7)); + System.out.println("symbol: " + sdk.neovm().oep8().querySymbol(tokenId8)); + return; + } + if(false){ + System.out.println("balance: " + sdk.neovm().oep8().queryBalanceOf(account1.getAddressU160().toBase58(), tokenId1)); + System.out.println("balance: " + sdk.neovm().oep8().queryBalanceOf(account1.getAddressU160().toBase58(), tokenId2)); + System.out.println("balance: " + sdk.neovm().oep8().queryBalanceOf(account1.getAddressU160().toBase58(), tokenId3)); + System.out.println("balance: " + sdk.neovm().oep8().queryBalanceOf(account1.getAddressU160().toBase58(), tokenId4)); + System.out.println("balance: " + sdk.neovm().oep8().queryBalanceOf(account1.getAddressU160().toBase58(), tokenId5)); + System.out.println("balance: " + sdk.neovm().oep8().queryBalanceOf(account1.getAddressU160().toBase58(), tokenId6)); + System.out.println("balance: " + sdk.neovm().oep8().queryBalanceOf(account1.getAddressU160().toBase58(), tokenId7)); + System.out.println("balance: " + sdk.neovm().oep8().queryBalanceOf(account1.getAddressU160().toBase58(), tokenId8)); + + return; + } + if(false){ + System.out.println(sdk.neovm().oep8().balancesOf(account1.getAddressU160().toBase58())); + System.out.println(sdk.neovm().oep8().totalBalanceOf(account1.getAddressU160().toBase58())); + return; + } + if(false){ + System.out.println(sdk.neovm().oep8().queryTotalSupply(tokenId1)); + return; + } + if(false){ + System.out.println(sdk.neovm().oep8().queryTotalSupply(tokenId1)); + String txhash = sdk.neovm().oep8().mint(account1,tokenId1,1, account, 20000, 500); + Thread.sleep(6000); + System.out.println(sdk.getConnect().getSmartCodeEvent(txhash)); + System.out.println(sdk.neovm().oep8().queryTotalSupply(tokenId1)); + return; + } + if(false){ + String txhash = sdk.neovm().oep8().sendCompound(account1,2, account, 71442, 500); + Thread.sleep(6000); + System.out.println(sdk.getConnect().getSmartCodeEvent(txhash)); + System.out.println(sdk.neovm().oep8().queryTotalSupply(tokenId1)); + System.out.println(sdk.neovm().oep8().queryTotalSupply(tokenId8)); + return; + } + if(false){ + System.out.println(sdk.neovm().oep8().balancesOf(account.getAddressU160().toBase58())); + System.out.println(sdk.neovm().oep8().totalBalanceOf(account.getAddressU160().toBase58())); + return; + } + if (false){ + System.out.println("balance: " + sdk.neovm().oep8().queryBalanceOf(account1.getAddressU160().toBase58(), tokenId1)); + System.out.println("balance: " + sdk.neovm().oep8().queryBalanceOf(account2.getAddressU160().toBase58(), tokenId1)); + String txhash = sdk.neovm().oep8().sendTransfer(account1,account2.getAddressU160().toBase58(),tokenId1,10,account,20000,500); + System.out.println("txhash: " + txhash); + Thread.sleep(6000); + System.out.println("balance: " + sdk.neovm().oep8().queryBalanceOf(account1.getAddressU160().toBase58(), tokenId1)); + System.out.println("balance: " + sdk.neovm().oep8().queryBalanceOf(account2.getAddressU160().toBase58(), tokenId1)); + return; + } + + if (false){ + System.out.println("res: " + sdk.neovm().oep8().queryAllowance(account1.getAddressU160().toBase58(),account2.getAddressU160().toBase58(), tokenId1)); + return; + } + if (false){ + String res = sdk.neovm().oep8().sendApprove(account1,account2.getAddressU160().toBase58(), tokenId1, 10000, account, 20000, 500); + System.out.println("res: " + res); + Thread.sleep(3000); + System.out.println(sdk.getConnect().getSmartCodeEvent(res)); + return; + } + if (false){ + System.out.println("balance: " + sdk.neovm().oep8().queryBalanceOf(account1.getAddressU160().toBase58(), tokenId1)); + System.out.println("balance: " + sdk.neovm().oep8().queryBalanceOf(account2.getAddressU160().toBase58(), tokenId1)); + String res = sdk.neovm().oep8().sendTransferFrom(account2,account1.getAddressU160().toBase58(),account2.getAddressU160().toBase58(), tokenId1, 1000, account, 20000, 500); + System.out.println("res: " + res); + Thread.sleep(6000); + System.out.println(sdk.getConnect().getSmartCodeEvent(res)); + System.out.println("balance: " + sdk.neovm().oep8().queryBalanceOf(account1.getAddressU160().toBase58(), tokenId1)); + System.out.println("balance: " + sdk.neovm().oep8().queryBalanceOf(account2.getAddressU160().toBase58(), tokenId1)); + return; + } + if (false){ + System.out.println("balance: " + sdk.neovm().oep8().queryBalanceOf(account1.getAddressU160().toBase58(), tokenId1)); + System.out.println("balance: " + sdk.neovm().oep8().queryBalanceOf(account2.getAddressU160().toBase58(), tokenId1)); + System.out.println("balance: " + sdk.neovm().oep8().queryBalanceOf(account.getAddressU160().toBase58(), tokenId1)); + Account[] accounts = new Account[]{account1, account2}; + Oep8State state = new Oep8State(account1.getAddressU160().toArray(), account.getAddressU160().toArray(), tokenId1, 1); + Oep8State state2 = new Oep8State(account2.getAddressU160().toArray(), account.getAddressU160().toArray(), tokenId1, 1); + String res = sdk.neovm().oep8().sendTransferMulti(accounts,new Oep8State[]{state,state2}, account, 20000, 500); + System.out.println("res: " + res); + Thread.sleep(6000); + System.out.println(sdk.getConnect().getSmartCodeEvent(res)); + System.out.println("balance: " + sdk.neovm().oep8().queryBalanceOf(account1.getAddressU160().toBase58(), tokenId1)); + System.out.println("balance: " + sdk.neovm().oep8().queryBalanceOf(account2.getAddressU160().toBase58(), tokenId1)); + System.out.println("balance: " + sdk.neovm().oep8().queryBalanceOf(account.getAddressU160().toBase58(), tokenId1)); + return; + } + if (false){ + System.out.println("res: " + sdk.neovm().oep8().queryAllowance(account1.getAddressU160().toBase58(),account.getAddressU160().toBase58(), tokenId1)); + System.out.println("res: " + sdk.neovm().oep8().queryAllowance(account1.getAddressU160().toBase58(),account.getAddressU160().toBase58(), tokenId1)); + Account[] accounts = new Account[]{account1, account2}; + Oep8State state = new Oep8State(account1.getAddressU160().toArray(), account.getAddressU160().toArray(), tokenId1, 1); + Oep8State state2 = new Oep8State(account2.getAddressU160().toArray(), account.getAddressU160().toArray(), tokenId1, 1); + String res = sdk.neovm().oep8().sendApproveMulti(accounts,new Oep8State[]{state, state2}, account, 20000, 500); + System.out.println("res: " + res); + Thread.sleep(6000); + System.out.println(sdk.getConnect().getSmartCodeEvent(res)); + System.out.println("res: " + sdk.neovm().oep8().queryAllowance(account1.getAddressU160().toBase58(),account.getAddressU160().toBase58(), tokenId1)); + System.out.println("res: " + sdk.neovm().oep8().queryAllowance(account1.getAddressU160().toBase58(),account.getAddressU160().toBase58(), tokenId1)); + return; + } + if (true){ + System.out.println("res: " + sdk.neovm().oep8().queryAllowance(account1.getAddressU160().toBase58(),account.getAddressU160().toBase58(), tokenId1)); + System.out.println("res: " + sdk.neovm().oep8().queryAllowance(account1.getAddressU160().toBase58(),account.getAddressU160().toBase58(), tokenId1)); + Account[] accounts = new Account[]{account}; + TransferFrom state = new TransferFrom(account.getAddressU160().toArray(),account1.getAddressU160().toArray(), account.getAddressU160().toArray(), tokenId1, 1); + TransferFrom state2 = new TransferFrom(account.getAddressU160().toArray(),account2.getAddressU160().toArray(), account.getAddressU160().toArray(), tokenId1, 1); + String res = sdk.neovm().oep8().sendTransferFromMulti(accounts,new TransferFrom[]{state, state2}, account, 27740, 500); + System.out.println("res: " + res); + Thread.sleep(6000); + System.out.println(sdk.getConnect().getSmartCodeEvent(res)); + System.out.println("res: " + sdk.neovm().oep8().queryAllowance(account1.getAddressU160().toBase58(),account.getAddressU160().toBase58(), tokenId1)); + System.out.println("res: " + sdk.neovm().oep8().queryAllowance(account1.getAddressU160().toBase58(),account.getAddressU160().toBase58(), tokenId1)); + return; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static DnaSdk getDnaSdk() throws Exception { + String ip = "http://127.0.0.1"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRestful()); + wm.neovm().oep8().setContractAddress("24643d7411223bcd0dd4d8b358e1e563af311408"); + wm.openWalletFile("oep8.dat"); + return wm; + } +} diff --git a/src/main/java/example/signature/MutiSignDemo.java b/src/main/java/example/signature/MutiSignDemo.java new file mode 100644 index 0000000..4f05fea --- /dev/null +++ b/src/main/java/example/signature/MutiSignDemo.java @@ -0,0 +1,92 @@ +package example.signature; + +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.transaction.Transaction; + +/** + * + * + */ +public class MutiSignDemo { + public static String privatekey1 = "49855b16636e70f100cc5f4f42bc20a6535d7414fb8845e7310f8dd065a97221"; + public static String privatekey2 = "1094e90dd7c4fdfd849c14798d725ac351ae0d924b29a279a9ffa77d5737bd96"; + public static String privatekey3 = "bc254cf8d3910bc615ba6bf09d4553846533ce4403bc24f58660ae150a6d64cf"; + public static String privatekey4 = "06bda156eda61222693cc6f8488557550735c329bc7ca91bd2994c894cd3cbc8"; + public static String privatekey5 = "f07d5a2be17bde8632ec08083af8c760b41b5e8e0b5de3703683c3bdcfb91549"; + public static String privatekey6 = "6c2c7eade4c5cb7c9d4d6d85bfda3da62aa358dd5b55de408d6a6947c18b9279"; + public static String privatekey7 = "24ab4d1d345be1f385c75caf2e1d22bdb58ef4b650c0308d9d69d21242ba8618"; + public static String privatekey8 = "87a209d232d6b4f3edfcf5c34434aa56871c2cb204c263f6b891b95bc5837cac"; + public static String privatekey9 = "1383ed1fe570b6673351f1a30a66b21204918ef8f673e864769fa2a653401114"; + public static void main(String[] args) { + + try { + DnaSdk dnaSdk = getDnaSdk(); + com.github.DNAProject.account.Account acct1 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey1), dnaSdk.defaultSignScheme); + com.github.DNAProject.account.Account acct2 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey2), dnaSdk.defaultSignScheme); + com.github.DNAProject.account.Account acct3 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey3), dnaSdk.defaultSignScheme); + com.github.DNAProject.account.Account acct4 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey4), dnaSdk.defaultSignScheme); + com.github.DNAProject.account.Account acct5 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey5), dnaSdk.defaultSignScheme); + + com.github.DNAProject.account.Account[] accounts = new com.github.DNAProject.account.Account[]{acct1,acct2,acct3}; + int M = 2; + byte[][] pks = new byte[accounts.length][]; + for(int i=0;i 1) { + System.out.println(i + " " + Address.addressFromMultiPubKeys(tx.sigs[i].M, tx.sigs[i].pubKeys).toBase58() + " " + tx.sigs[i].json()); + } + } + System.out.println( dnaSdk.verifyTransaction(tx)); + + System.out.println(); + // test error signature in multi sign + data = "00d10157e29d000000000000000030750000000000004756c9dd829b2142883adbe1ae4f8689a1f673e97400c66b144756c9dd829b2142883adbe1ae4f8689a1f673e96a7cc81426aff63b171726ac95969887b2478dc2bc5b96f46a7cc803a086016a7cc86c51c1087472616e736665721400000000000000000000000000000000000000010068164f6e746f6c6f67792e4e61746976652e496e766f6b650002424101ddb49f40c7d8ee3efb9a3b4104e76b9bba5d5567ba7328bc723f897298cbdef2511af83a6d5170001c3c5917e89e640b65aaa7bff82c5eb3b36083d1fb986c64232103036c12be3726eb283d078dff481175e96224f0b0c632c7a37e10eb40fe6be889ac8441011d158ef87d04a9eaad579f5317a77561bef1035db9d9dd787f1c971a383fef92e4d71cd6931516ff5084793f074222c54e982157653966ba68758806993dfc1e4101e2a2fbf0e77a88161139be7e8d15fb455503cfa26b89fa2f94ff6f6ee6495f47168c75830f4219a3b75126ae74df3315680fd8325f67537f37eb08bdf73b09f169522103036c12be3726eb283d078dff481175e96224f0b0c632c7a37e10eb40fe6be88921022dce1383ab72dc421732f772171a9ef867b5d36a82c7c4daabdb083d0e710ac62102df6f28e327352a44720f2b384e55034c1a7f54ba31785aa3a338f613a5b7cc2653ae"; + tx = Transaction.deserializeFrom(Helper.hexToBytes(data)); + for (int i = 0; i < tx.sigs.length; i++) { + if (tx.sigs[i].M == 1) { + System.out.println(i + " " + Address.addressFromPubKey(tx.sigs[i].pubKeys[0]).toBase58() + " " + tx.sigs[i].json()); + } else if (tx.sigs[i].M > 1) { + System.out.println(i + " " + Address.addressFromMultiPubKeys(tx.sigs[i].M, tx.sigs[i].pubKeys).toBase58() + " " + tx.sigs[i].json()); + } + } + System.out.println(false == dnaSdk.verifyTransaction(tx)); + } catch (Exception e) { + e.printStackTrace(); + } + + } + + public static DnaSdk getDnaSdk() throws Exception { + String ip = "http://127.0.0.1"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRestful()); + wm.openWalletFile("wallet.json"); + + return wm; + } +} diff --git a/src/main/java/example/smartcontract/DeployCodeDemo.java b/src/main/java/example/smartcontract/DeployCodeDemo.java new file mode 100644 index 0000000..5a07434 --- /dev/null +++ b/src/main/java/example/smartcontract/DeployCodeDemo.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ +package example.smartcontract; + +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.payload.DeployCode; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.crypto.SignatureScheme; + + +/** + * + */ +public class DeployCodeDemo { + public static void main(String[] args) { + try { + DnaSdk dnaSdk = getDnaSdk(); + +// InputStream is = new FileInputStream("/Users/sss/dev/test/IdContract/IdContract.avm");//IdContract +// byte[] bys = new byte[is.available()]; +// is.read(bys); +// is.close(); + //code = Helper.toHexString(bys); +// System.out.println("Code:" + Helper.toHexString(bys)); + + String password = "111111"; + String privatekey0 = "59e68b0cc387dd4e36e50c0562ff589f1d9289d32fc694b8918a3859faba6c67"; + String privatekey1 = "523c5fcf74823831756f0bcb3634234f10b3beb1c05595058534577752ad2d9f"; + Account acct0 = new Account(Helper.hexToBytes(privatekey0), dnaSdk.defaultSignScheme); + String code = ""; + code = "0114c56b05322e302e306a00527ac4681953797374656d2e53746f726167652e476574436f6e746578746a51527ac404544553546a52527ac404544553546a53527ac4586a54527ac40400e1f5056a55527ac422414e4835624872727431313158774e456e75505a6a3675393544643675374734443668204f6e746f6c6f67792e52756e74696d652e426173653538546f416464726573736a56527ac40500ac23fc066a57527ac401016a58527ac401026a59527ac401036a5a527ac40b546f74616c537570706c796a5b527ac40d5061757365436f6e74726163746a5c527ac4054f776e65726a5d527ac46c0137c56b6a00527ac46a51527ac46a52527ac46a51c304696e69747d9c7c75641500006a00c306ad05000000006e6c75666203006a51c3046e616d657d9c7c75641500006a00c3062107000000006e6c75666203006a51c30673796d626f6c7d9c7c75641500006a00c3063907000000006e6c75666203006a51c308646563696d616c737d9c7c75641500006a00c3065107000000006e6c75666203006a51c30b746f74616c537570706c797d9c7c75641500006a00c3066907000000006e6c75666203006a51c30962616c616e63654f667d9c7c756435006a52c3c0517d9e7c75640a00006c75666203006a52c300c36a54527ac46a54c3516a00c3069a07000000006e6c75666203006a51c3087472616e736665727d9c7c75644f006a52c3c0537d9e7c75640a00006c75666239006a52c300c36a55527ac46a52c351c36a56527ac46a52c352c36a57527ac46a57c36a56c36a55c3536a00c3060008000000006e6c75666203006a51c30d7472616e736665724d756c74697d9c7c756418006a52c3516a00c306160a000000006e6c75666203006a51c30c7472616e7366657246726f6d7d9c7c75645c006a52c3c0547d9e7c75640a00006c75666203006a52c300c36a58527ac46a52c351c36a55527ac46a52c352c36a56527ac46a52c353c36a57527ac46a57c36a56c36a55c36a58c3546a00c306f20b000000006e6c75666203006a51c307617070726f76657d9c7c75644f006a52c3c0537d9e7c75640a00006c75666203006a52c300c36a59527ac46a52c351c36a58527ac46a52c352c36a57527ac46a57c36a58c36a59c3536a00c306d20a000000006e6c75666203006a51c309616c6c6f77616e63657d9c7c756442006a52c3c0527d9e7c75640a00006c75666203006a52c300c36a59527ac46a52c351c36a58527ac46a58c36a59c3526a00c306b00e000000006e6c75666203006a51c3056f776e65727d9c7c75641500006a00c306fb0e000000006e6c75666203006a51c30769734f776e65727d9c7c756435006a52c3c0517d9e7c75640a00006c75666203006a52c300c36a54527ac46a54c3516a00c3062c0f000000006e6c75666203006a51c3117472616e736665724f776e6572736869707d9c7c756435006a52c3c0517d9e7c75640a00006c75666203006a52c300c36a54527ac46a54c3516a00c306770f000000006e6c75666203006a51c30570617573657d9c7c75641500006a00c306ce10000000006e6c75666203006a51c307756e70617573657d9c7c75641500006a00c3064111000000006e6c75666203006a51c3097669657750617573657d9c7c75641500006a00c306b411000000006e6c75666203006a51c30d667265657a654163636f756e747d9c7c756435006a52c3c0517d9e7c75640a00006c75666203006a52c300c36a54527ac46a54c3516a00c306a512000000006e6c75666203006a51c30f756e667265657a654163636f756e747d9c7c756435006a52c3c0517d9e7c75640a00006c75666203006a52c300c36a54527ac46a54c3516a00c3065013000000006e6c75666203006a51c31176696577467265657a654163636f756e747d9c7c756435006a52c3c0517d9e7c75640a00006c75666203006a52c300c36a54527ac46a54c3516a00c306fb13000000006e6c7566620300006c75665ac56b6a00527ac46a51527ac46203000e4f776e657220696c6c6567616c216a00c356c3c001147d9c7c75526a00c306a210000000006e756a00c356c36a00c35dc36a00c351c3681253797374656d2e53746f726167652e5075746a00c35dc36a00c351c3681253797374656d2e53746f726167652e4765746a53527ac413416c726561647920696e697469616c697a65646a00c35bc36a00c351c3681253797374656d2e53746f726167652e476574007d9c7c75526a00c306a210000000006e756a00c357c36a00c355c3956a54527ac46a54c36a00c35bc36a00c351c3681253797374656d2e53746f726167652e5075746a54c36a00c358c36a53c37e6a00c351c3681253797374656d2e53746f726167652e5075746a54c36a53c300087472616e7366657254c1681553797374656d2e52756e74696d652e4e6f746966796a53c300117472616e736665724f776e65727368697053c1681553797374656d2e52756e74696d652e4e6f74696679516c756655c56b6a00527ac46a51527ac46203006a00c352c36c756655c56b6a00527ac46a51527ac46203006a00c353c36c756655c56b6a00527ac46a51527ac46203006a00c354c36c756655c56b6a00527ac46a51527ac46203006a00c35bc36a00c351c3681253797374656d2e53746f726167652e4765746c756658c56b6a00527ac46a51527ac46a52527ac46203001461646472657373206c656e677468206572726f726a52c3c001147d9c7c75526a00c306a210000000006e756a00c358c36a52c37e6a00c351c3681253797374656d2e53746f726167652e4765746c75665ec56b6a00527ac46a51527ac46a52527ac46a53527ac46a54527ac46203001461646472657373206c656e677468206572726f726a53c3c001147d9c7c7576640e00756a52c3c001147d9c7c75526a00c306a210000000006e750f496e76616c696420696e766f6b65726a52c3681b53797374656d2e52756e74696d652e436865636b5769746e657373517d9c7c75526a00c306a210000000006e750e496e76616c696420416d6f756e746a54c3007da07c75526a00c306a210000000006e75006a00c306e511000000006e6a52c3516a00c3063514000000006e6a53c3516a00c3063514000000006e6a00c358c36a52c37e6a56527ac46a56c36a00c351c3681253797374656d2e53746f726167652e4765746a57527ac4124e6f7420656e6f7567682062616c616e63656a54c36a57c37da17c75526a00c306a210000000006e756a54c36a57c37d9c7c756425006a56c36a00c351c3681553797374656d2e53746f726167652e44656c6574656226006a57c36a54c3946a56c36a00c351c3681253797374656d2e53746f726167652e5075746a00c358c36a53c37e6a58527ac46a58c36a00c351c3681253797374656d2e53746f726167652e4765746a59527ac46a59c36a54c3936a58c36a00c351c3681253797374656d2e53746f726167652e5075746a54c36a53c36a52c3087472616e7366657254c1681553797374656d2e52756e74696d652e4e6f74696679516c75665bc56b6a00527ac46a51527ac46a52527ac4620300006a53527ac46a52c36a54527ac46a54c3c06a55527ac46a53c36a55c39f6485006a54c36a53c3c36a56527ac46a53c351936a53527ac46a56c3c0537d9e7c756423001b7472616e736665724d756c746920706172616d73206572726f722ef0620300147472616e736665724d756c7469206661696c65646a56c352c36a56c351c36a56c300c3536a00c3060008000000006e526a00c306a210000000006e756277ff516c75665cc56b6a00527ac46a51527ac46a52527ac46a53527ac46a54527ac46203001461646472657373206c656e677468206572726f726a53c3c001147d9c7c7576640e00756a52c3c001147d9c7c75526a00c306a210000000006e750f496e76616c696420696e766f6b65726a52c3681b53797374656d2e52756e74696d652e436865636b5769746e657373517d9c7c75526a00c306a210000000006e750e496e76616c696420616d6f756e746a54c3007da07c75526a00c306a210000000006e756a00c359c36a52c37e6a53c37e6a56527ac46a54c36a56c36a00c351c3681253797374656d2e53746f726167652e5075746a54c36a53c36a52c308617070726f76616c54c1681553797374656d2e52756e74696d652e4e6f74696679516c75660112c56b6a00527ac46a51527ac46a52527ac46a53527ac46a54527ac46a55527ac46203001461646472657373206c656e677468206572726f726a52c3c001147d9c7c7576641d00756a53c3c001147d9c7c7576640e00756a54c3c001147d9c7c75526a00c306a210000000006e750f496e76616c696420696e766f6b65726a52c3681b53797374656d2e52756e74696d652e436865636b5769746e657373517d9c7c75526a00c306a210000000006e75006a00c306e511000000006e6a52c3516a00c3063514000000006e6a53c3516a00c3063514000000006e6a54c3516a00c3063514000000006e6a00c358c36a53c37e6a57527ac46a57c36a00c351c3681253797374656d2e53746f726167652e4765746a58527ac40e496e76616c696420616d6f756e746a55c36a58c37da17c7576640c00756a55c3007da07c75526a00c306a210000000006e756a00c359c36a53c37e6a52c37e6a59527ac46a59c36a00c351c3681253797374656d2e53746f726167652e4765746a5a527ac46a00c358c36a54c37e6a5b527ac40e496e76616c696420616d6f756e746a55c36a5ac37da17c75526a00c306a210000000006e756a55c36a5ac37d9c7c756448006a59c36a00c351c3681553797374656d2e53746f726167652e44656c6574656a58c36a55c3946a57c36a00c351c3681253797374656d2e53746f726167652e5075746249006a5ac36a55c3946a59c36a00c351c3681253797374656d2e53746f726167652e5075746a58c36a55c3946a57c36a00c351c3681253797374656d2e53746f726167652e5075746a5bc36a00c351c3681253797374656d2e53746f726167652e4765746a5c527ac46a5cc36a55c3936a5bc36a00c351c3681253797374656d2e53746f726167652e5075746a55c36a54c36a53c3087472616e7366657254c1681553797374656d2e52756e74696d652e4e6f74696679516c756659c56b6a00527ac46a51527ac46a52527ac46a53527ac46203006a00c359c36a52c37e6a53c37e6a54527ac46a54c36a00c351c3681253797374656d2e53746f726167652e4765746c756655c56b6a00527ac46a51527ac46203006a00c35dc36a00c351c3681253797374656d2e53746f726167652e4765746c756657c56b6a00527ac46a51527ac46a52527ac46203006a00c35dc36a00c351c3681253797374656d2e53746f726167652e4765746a52c37d9c7c75640a00516c7566620700006c75666c756658c56b6a00527ac46a51527ac46a52527ac4620300006a00c3063d10000000006e1461646472657373206c656e677468206572726f726a52c3c001147d9c7c75526a00c306a210000000006e756a00c35dc36a00c351c3681253797374656d2e53746f726167652e4765746a54527ac46a52c36a00c35dc36a00c351c3681253797374656d2e53746f726167652e5075746a52c36a54c3117472616e736665724f776e65727368697053c1681553797374656d2e52756e74696d652e4e6f74696679516c756656c56b6a00527ac46a51527ac4620300094e6f74204f776e65726a00c35dc36a00c351c3681253797374656d2e53746f726167652e476574681b53797374656d2e52756e74696d652e436865636b5769746e657373526a00c306a210000000006e756c756657c56b6a00527ac46a51527ac46a52527ac46a53527ac46203006a52c391640a006a53c3f0620300516c756655c56b6a00527ac46a51527ac4620300006a00c3063d10000000006e006a00c306e511000000006e516a00c35cc36a00c351c3681253797374656d2e53746f726167652e507574510d636f6e7472616374506175736552c1681553797374656d2e52756e74696d652e4e6f74696679516c756655c56b6a00527ac46a51527ac4620300006a00c3063d10000000006e006a00c3064412000000006e006a00c35cc36a00c351c3681253797374656d2e53746f726167652e507574000d636f6e7472616374506175736552c1681553797374656d2e52756e74696d652e4e6f74696679516c756655c56b6a00527ac46a51527ac46203006a00c35cc36a00c351c3681253797374656d2e53746f726167652e4765746c756655c56b6a00527ac46a51527ac46203001b4e6f74207061757365207374617465206f6620436f6e74726163746a00c35cc36a00c351c3681253797374656d2e53746f726167652e476574007d9c7c75526a00c306a210000000006e756c756655c56b6a00527ac46a51527ac46203001d4e6f7420756e7061757365207374617465206f6620436f6e74726163746a00c35cc36a00c351c3681253797374656d2e53746f726167652e476574517d9c7c75526a00c306a210000000006e756c756658c56b6a00527ac46a51527ac46a52527ac4620300006a00c3063d10000000006e6a52c3516a00c3063514000000006e1461646472657373206c656e677468206572726f726a52c3c001147d9c7c75526a00c306a210000000006e75516a00c35ac36a52c37e6a00c351c3681253797374656d2e53746f726167652e507574516a52c30a75736572467265657a6553c1681553797374656d2e52756e74696d652e4e6f74696679516c756658c56b6a00527ac46a51527ac46a52527ac4620300006a00c3063d10000000006e6a52c3516a00c3069f14000000006e1461646472657373206c656e677468206572726f726a52c3c001147d9c7c75526a00c306a210000000006e75006a00c35ac36a52c37e6a00c351c3681253797374656d2e53746f726167652e507574006a52c30a75736572467265657a6553c1681553797374656d2e52756e74696d652e4e6f74696679516c756657c56b6a00527ac46a51527ac46a52527ac46203006a00c35ac36a52c37e6a00c351c3681253797374656d2e53746f726167652e4765746c756657c56b6a00527ac46a51527ac46a52527ac46203001d4e6f7420756e66726f7a656e207374617465206f66206163636f756e746a00c35ac36a52c37e6a00c351c3681253797374656d2e53746f726167652e476574007d9c7c75526a00c306a210000000006e756c756657c56b6a00527ac46a51527ac46a52527ac46203001b4e6f742066726f7a656e207374617465206f66206163636f756e746a00c35ac36a52c37e6a00c351c3681253797374656d2e53746f726167652e476574517d9c7c75526a00c306a210000000006e756c7566"; + + System.out.println("ContractAddress:" + Address.AddressFromVmCode(code).toHexString()); + if (true) { + System.out.println(dnaSdk.getConnect().getContractJson(Address.AddressFromVmCode(code).toHexString())); + System.exit(0); + } + System.out.println(acct0.getAddressU160().toBase58()); + dnaSdk.vm().setCodeAddress(Address.AddressFromVmCode(code).toHexString()); + Account account = new Account(Helper.hexToBytes(privatekey1),SignatureScheme.SHA256WITHECDSA); + Transaction tx = dnaSdk.vm().makeDeployCodeTransaction(code, true, "name", + "v1.0", "author", "email", "desp", account.getAddressU160().toBase58(),dnaSdk.DEFAULT_DEPLOY_GAS_LIMIT,500); + dnaSdk.signTx(tx, new Account[][]{{account}}); + String txHex = Helper.toHexString(tx.toArray()); + if(false){ + System.out.println(tx.hash().toString()); + Object result = dnaSdk.getConnect().syncSendRawTransaction(txHex); + System.out.println(result); + System.exit(0); + } + System.out.println(txHex); + Object result = dnaSdk.getConnect().sendRawTransaction(txHex); + System.out.println(result); + + System.out.println("txhash:" + tx.hash().toString()); + String txhash = tx.hash().toHexString(); + + //System.out.println(dnaSdk.getConnect().getMemPoolTxCount()); + //System.out.println(dnaSdk.getConnect().getMemPoolTxState(txhash)); + Thread.sleep(6000); + + + + + DeployCode t = (DeployCode) dnaSdk.getConnect().getTransaction(txhash); + System.out.println(t.txType.value() & 0xff); + } catch (Exception e) { + + e.printStackTrace(); + } + } + + public static DnaSdk getDnaSdk() throws Exception { + String ip = "http://127.0.0.1"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRestful()); + + wm.openWalletFile("DeployDemo.json"); + + return wm; + } +} diff --git a/src/main/java/example/smartcontract/NeoVmDemo.java b/src/main/java/example/smartcontract/NeoVmDemo.java new file mode 100644 index 0000000..b710b05 --- /dev/null +++ b/src/main/java/example/smartcontract/NeoVmDemo.java @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ +package example.smartcontract; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.smartcontract.neovm.abi.AbiFunction; +import com.github.DNAProject.smartcontract.neovm.abi.AbiInfo; +import com.github.DNAProject.smartcontract.neovm.abi.Struct; + +import java.util.HashMap; +import java.util.Map; + +/** + * + * + */ +public class NeoVmDemo { + public static String privatekey0 = "c19f16785b8f3543bbaf5e1dbb5d398dfa6c85aaad54fc9d71203ce83e505c07"; + public static String privatekey1 = "49855b16636e70f100cc5f4f42bc20a6535d7414fb8845e7310f8dd065a97221"; + public static String privatekey2 = "1094e90dd7c4fdfd849c14798d725ac351ae0d924b29a279a9ffa77d5737bd96"; + public static String abi ="{\"hash\":\"0x638119357dd210e0d7661f779526690af5e3cf8e\",\"entrypoint\":\"Main\",\"functions\":[{\"name\":\"Main\",\"parameters\":[{\"name\":\"operation\",\"type\":\"String\"},{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"Any\"},{\"name\":\"TestMap\",\"parameters\":[],\"returntype\":\"Any\"},{\"name\":\"DeserializeMap\",\"parameters\":[{\"name\":\"param\",\"type\":\"Map\"}],\"returntype\":\"Any\"},{\"name\":\"TestStruct\",\"parameters\":[],\"returntype\":\"Any\"},{\"name\":\"DeserializeStruct\",\"parameters\":[{\"name\":\"param\",\"type\":\"Struct\"}],\"returntype\":\"Any\"}],\"events\":[]}"; + public static void main(String[] args) { + try { + DnaSdk dnaSdk = getDnaSdk(); + Account acct1 = new Account(Helper.hexToBytes(privatekey1), dnaSdk.defaultSignScheme); + Account acct2 = new Account(Helper.hexToBytes(privatekey2), dnaSdk.defaultSignScheme); + Account acct = new Account(Helper.hexToBytes(privatekey0), dnaSdk.defaultSignScheme); + + System.out.println("hello:"+Helper.toHexString("hello".getBytes())); + System.out.println("world:"+Helper.toHexString("world".getBytes())); + System.out.println("key:"+Helper.toHexString("key".getBytes())); + System.out.println("claimId:"+Helper.toHexString("claimId".getBytes())); + System.out.println("claimid:"+Helper.toHexString("claimid".getBytes())); + System.out.println("name:"+Helper.toHexString("name".getBytes())); + //System.exit(0); + if(false){ + + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + String name = "TestMap"; + AbiFunction func = abiinfo.getFunction(name); + func.name = name; + System.out.println(func); + func.setParamsValue(); + + Object obj = dnaSdk.neovm().sendTransaction(Helper.reverse("638119357dd210e0d7661f779526690af5e3cf8e"),null,null,0,0,func, true); + System.out.println(obj); + + } + //82 01 00 05 68656c6c6f 00 05 776f726c64 + + if(false){ + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + String name = "DeserializeMap"; + AbiFunction func = abiinfo.getFunction(name); + func.name = name; + Map map = new HashMap<>(); +// map.put("hello","world"); + map.put("key",100); +// map.put("a","worlda"); +// map.put("b",155); +// map.put("c",100000); + System.out.println(func); + func.setParamsValue(map); + + Object obj = dnaSdk.neovm().sendTransaction(Helper.reverse("638119357dd210e0d7661f779526690af5e3cf8e"),null,null,0,0,func, true); + System.out.println(obj); + + } + + //80 02 00 0164 00 07 636c61696d6964 + if(true){ + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + String name = "TestStruct"; + AbiFunction func = abiinfo.getFunction(name); + + System.out.println(func); + func.setParamsValue(); + + Object obj = dnaSdk.neovm().sendTransaction(Helper.reverse("638119357dd210e0d7661f779526690af5e3cf8e"),null,null,0,0,func, true); + System.out.println(obj); + + } + //80 02 00 0164 00 07 636c61696d6964 + //80 02 02 0164 00 07 636c61696d6964 + if(true){ + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + String name = "DeserializeStruct"; + AbiFunction func = abiinfo.getFunction(name); + + System.out.println(func); + func.setParamsValue(new Struct().add(100,"claimid")); + + Object obj = dnaSdk.neovm().sendTransaction(Helper.reverse("638119357dd210e0d7661f779526690af5e3cf8e"),null,null,0,0,func, true); + System.out.println(obj); + + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static DnaSdk getDnaSdk() throws Exception { + String ip = "http://127.0.0.1"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRestful()); + wm.openWalletFile("neovm.json"); + + + return wm; + } +} diff --git a/src/main/java/example/smartcontract/NeoVmDemo3.java b/src/main/java/example/smartcontract/NeoVmDemo3.java new file mode 100644 index 0000000..3b13f5f --- /dev/null +++ b/src/main/java/example/smartcontract/NeoVmDemo3.java @@ -0,0 +1,733 @@ +package example.smartcontract; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.crypto.SignatureScheme; +import com.github.DNAProject.smartcontract.neovm.abi.AbiFunction; +import com.github.DNAProject.smartcontract.neovm.abi.AbiInfo; +import com.github.DNAProject.smartcontract.neovm.abi.BuildParams; + +import java.util.ArrayList; +import java.util.Base64; +import java.util.List; + +public class NeoVmDemo3 { + + + public static String privatekey0 = "c19f16785b8f3543bbaf5e1dbb5d398dfa6c85aaad54fc9d71203ce83e505c07"; + public static String privatekey1 = "49855b16636e70f100cc5f4f42bc20a6535d7414fb8845e7310f8dd065a97221"; + public static String privatekey2 = "1094e90dd7c4fdfd849c14798d725ac351ae0d924b29a279a9ffa77d5737bd96"; + public static String abi ="{\"hash\":\"0x638119357dd210e0d7661f779526690af5e3cf8e\",\"entrypoint\":\"Main\",\"functions\":[{\"name\":\"Main\",\"parameters\":[{\"name\":\"operation\",\"type\":\"String\"},{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"Any\"},{\"name\":\"TestMap\",\"parameters\":[],\"returntype\":\"Any\"},{\"name\":\"DeserializeMap\",\"parameters\":[{\"name\":\"param\",\"type\":\"Map\"}],\"returntype\":\"Any\"},{\"name\":\"TestStruct\",\"parameters\":[],\"returntype\":\"Any\"},{\"name\":\"DeserializeStruct\",\"parameters\":[{\"name\":\"param\",\"type\":\"Struct\"}],\"returntype\":\"Any\"}],\"events\":[]}"; + public static void main(String[] args) { + try { + DnaSdk dnaSdk = getDnaSdk(); + Account acct1 = new Account(Helper.hexToBytes(privatekey1), dnaSdk.defaultSignScheme); + Account acct2 = new Account(Helper.hexToBytes(privatekey2), dnaSdk.defaultSignScheme); + Account acct = new Account(Helper.hexToBytes(privatekey0), dnaSdk.defaultSignScheme); + if(true){ + String abi = "{\n" + + " \"hash\":\"0xdedc8c61d03dcc3387737fbddbe8096300be84de\",\n" + + " \"entrypoint\":\"Main\",\n" + + " \"functions\":[\n" + + " {\n" + + " \"name\":\"init\",\n" + + " \"parameters\":[\n" + + "\n" + + " ],\n" + + " \"returntype\":\"Boolean\"\n" + + " },\n" + + " {\n" + + " \"name\":\"startNewRound\",\n" + + " \"parameters\":[\n" + + "\n" + + " ],\n" + + " \"returntype\":\"Boolean\"\n" + + " },\n" + + " {\n" + + " \"name\":\"addReferral\",\n" + + " \"parameters\":[\n" + + " {\n" + + " \"name\":\"toBeReferred\",\n" + + " \"type\":\"ByteArray\"\n" + + " },\n" + + " {\n" + + " \"name\":\"referral\",\n" + + " \"type\":\"ByteArray\"\n" + + " }\n" + + " ],\n" + + " \"returntype\":\"Boolean\"\n" + + " },\n" + + " {\n" + + " \"name\":\"addMultiReferral\",\n" + + " \"parameters\":[\n" + + " {\n" + + " \"name\":\"args\",\n" + + " \"type\":\"Array\"\n" + + " }\n" + + " ],\n" + + " \"returntype\":\"Boolean\"\n" + + " },\n" + + " {\n" + + " \"name\":\"withdrawGas\",\n" + + " \"parameters\":[\n" + + "\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"name\":\"endCurrentRound\",\n" + + " \"parameters\":[\n" + + "\n" + + " ],\n" + + " \"returntype\":\"\"\n" + + " },\n" + + " {\n" + + " \"name\":\"buyPaper\",\n" + + " \"parameters\":[\n" + + " {\n" + + " \"name\":\"account\",\n" + + " \"type\":\"ByteArray\"\n" + + " },\n" + + " {\n" + + " \"name\":\"paperAmount\",\n" + + " \"type\":\"Integer\"\n" + + " }\n" + + " ],\n" + + " \"returntype\":\"\"\n" + + " },\n" + + " {\n" + + " \"name\":\"reinvest\",\n" + + " \"parameters\":[\n" + + " {\n" + + " \"name\":\"account\",\n" + + " \"type\":\"ByteArray\"\n" + + " },\n" + + " {\n" + + " \"name\":\"paperAmount\",\n" + + " \"type\":\"Integer\"\n" + + " }\n" + + " ],\n" + + " \"returntype\":\"\"\n" + + " },\n" + + " {\n" + + " \"name\":\"fillPaper\",\n" + + " \"parameters\":[\n" + + " {\n" + + " \"name\":\"account\",\n" + + " \"type\":\"ByteArray\"\n" + + " },\n" + + " {\n" + + " \"name\":\"guessNumberList\",\n" + + " \"type\":\"Array\"\n" + + " }\n" + + " ],\n" + + " \"returntype\":\"\"\n" + + " },\n" + + " {\n" + + " \"name\":\"withdraw\",\n" + + " \"parameters\":[\n" + + " {\n" + + " \"name\":\"account\",\n" + + " \"type\":\"ByteArray\"\n" + + " }\n" + + " ],\n" + + " \"returntype\":\"\"\n" + + " },\n" + + " {\n" + + " \"name\":\"updateDividendBalance\",\n" + + " \"parameters\":[\n" + + " {\n" + + " \"name\":\"account\",\n" + + " \"type\":\"ByteArray\"\n" + + " }\n" + + " ],\n" + + " \"returntype\":\"\"\n" + + " },\n" + + " {\n" + + " \"name\":\"getTotalPaper\",\n" + + " \"parameters\":[\n" + + "\n" + + " ],\n" + + " \"returntype\":\"Integer\"\n" + + " },\n" + + " {\n" + + " \"name\":\"getGasVault\",\n" + + " \"parameters\":[\n" + + "\n" + + " ],\n" + + " \"returntype\":\"Integer\"\n" + + " },\n" + + " {\n" + + " \"name\":\"getCurrentRound\",\n" + + " \"parameters\":[\n" + + "\n" + + " ],\n" + + " \"returntype\":\"Integer\"\n" + + " },\n" + + " {\n" + + " \"name\":\"getCurrentPrice\",\n" + + " \"parameters\":[\n" + + "\n" + + " ],\n" + + " \"returntype\":\"Integer\"\n" + + " },\n" + + " {\n" + + " \"name\":\"getPaperBalance\",\n" + + " \"parameters\":[\n" + + " {\n" + + " \"name\":\"account\",\n" + + " \"type\":\"ByteArray\"\n" + + " }\n" + + " ],\n" + + " \"returntype\":\"Integer\"\n" + + " },\n" + + " {\n" + + " \"name\":\"getInvestOngBalance\",\n" + + " \"parameters\":[\n" + + " {\n" + + " \"name\":\"account\",\n" + + " \"type\":\"ByteArray\"\n" + + " }\n" + + " ],\n" + + " \"returntype\":\"Integer\"\n" + + " },\n" + + " {\n" + + " \"name\":\"getReferralBalance\",\n" + + " \"parameters\":[\n" + + " {\n" + + " \"name\":\"account\",\n" + + " \"type\":\"ByteArray\"\n" + + " }\n" + + " ],\n" + + " \"returntype\":\"Integer\"\n" + + " },\n" + + " {\n" + + " \"name\":\"getDividendBalance\",\n" + + " \"parameters\":[\n" + + " {\n" + + " \"name\":\"account\",\n" + + " \"type\":\"ByteArray\"\n" + + " }\n" + + " ],\n" + + " \"returntype\":\"Integer\"\n" + + " },\n" + + " {\n" + + " \"name\":\"getAwardBalance\",\n" + + " \"parameters\":[\n" + + " {\n" + + " \"name\":\"account\",\n" + + " \"type\":\"ByteArray\"\n" + + " }\n" + + " ],\n" + + " \"returntype\":\"Integer\"\n" + + " },\n" + + " {\n" + + " \"name\":\"getWithdrawnBalance\",\n" + + " \"parameters\":[\n" + + " {\n" + + " \"name\":\"account\",\n" + + " \"type\":\"ByteArray\"\n" + + " }\n" + + " ],\n" + + " \"returntype\":\"Integer\"\n" + + " },\n" + + " {\n" + + " \"name\":\"getFilledPaperBalance\",\n" + + " \"parameters\":[\n" + + " {\n" + + " \"name\":\"account\",\n" + + " \"type\":\"ByteArray\"\n" + + " },\n" + + " {\n" + + " \"name\":\"roundNum\",\n" + + " \"type\":\"Integer\"\n" + + " }\n" + + " ],\n" + + " \"returntype\":\"Integer\"\n" + + " },\n" + + " {\n" + + " \"name\":\"getReferral\",\n" + + " \"parameters\":[\n" + + " {\n" + + " \"name\":\"account\",\n" + + " \"type\":\"ByteArray\"\n" + + " }\n" + + " ],\n" + + " \"returntype\":\"ByteArray\"\n" + + " },\n" + + " {\n" + + " \"name\":\"getAwardVault\",\n" + + " \"parameters\":[\n" + + " {\n" + + " \"name\":\"roundNum\",\n" + + " \"type\":\"Integer\"\n" + + " }\n" + + " ],\n" + + " \"returntype\":\"Integer\"\n" + + " },\n" + + " {\n" + + " \"name\":\"getNextVault\",\n" + + " \"parameters\":[\n" + + " {\n" + + " \"name\":\"roundNum\",\n" + + " \"type\":\"Integer\"\n" + + " }\n" + + " ],\n" + + " \"returntype\":\"Integer\"\n" + + " },\n" + + " {\n" + + " \"name\":\"getGameStatus\",\n" + + " \"parameters\":[\n" + + " {\n" + + " \"name\":\"roundNum\",\n" + + " \"type\":\"Integer\"\n" + + " }\n" + + " ],\n" + + " \"returntype\":\"String\"\n" + + " },\n" + + " {\n" + + " \"name\":\"getRoundSoldPaperAmount\",\n" + + " \"parameters\":[\n" + + " {\n" + + " \"name\":\"roundNum\",\n" + + " \"type\":\"Integer\"\n" + + " }\n" + + " ],\n" + + " \"returntype\":\"Integer\"\n" + + " },\n" + + " {\n" + + " \"name\":\"getFilledPaperAmount\",\n" + + " \"parameters\":[\n" + + " {\n" + + " \"name\":\"roundNum\",\n" + + " \"type\":\"Integer\"\n" + + " }\n" + + " ],\n" + + " \"returntype\":\"Integer\"\n" + + " },\n" + + " {\n" + + " \"name\":\"getFilledNumberList\",\n" + + " \"parameters\":[\n" + + " {\n" + + " \"name\":\"roundNum\",\n" + + " \"type\":\"Integer\"\n" + + " }\n" + + " ],\n" + + " \"returntype\":\"Array\"\n" + + " },\n" + + " {\n" + + " \"name\":\"getPlayersList\",\n" + + " \"parameters\":[\n" + + " {\n" + + " \"name\":\"roundNum\",\n" + + " \"type\":\"Integer\"\n" + + " },\n" + + " {\n" + + " \"name\":\"guessNumber\",\n" + + " \"type\":\"Integer\"\n" + + " }\n" + + " ],\n" + + " \"returntype\":\"Array\"\n" + + " },\n" + + " {\n" + + " \"name\":\"getLuckyNumber\",\n" + + " \"parameters\":[\n" + + "\n" + + " ],\n" + + " \"returntype\":\"Integer\"\n" + + " }\n" + + " ],\n" + + " \"events\":[\n" + + "\n" + + " ]\n" + + "}"; + AbiInfo info = JSON.parseObject(abi,AbiInfo.class); + AbiFunction function = info.getFunction("getTotalPaper"); + Object res = dnaSdk.neovm().sendTransaction(Helper.reverse("dedc8c61d03dcc3387737fbddbe8096300be84de"),acct,acct, + 20000,0,function,true); + System.out.println(res); + return; + } + + +// Account account1 = getAccount("YfOr9im4rOciy3cV7JkVo9QCfrRT4IGLa/CZKUJfL29pM6Zi1oVEM67+8MezMIro","1","AXmQDzzvpEtPkNwBEFsREzApTTDZFW6frD","RCIo60eCJAwzkTYmIfp3GA=="); +// Account account2 = getAccount("gpgMejEHzawuXG+ghLkZ8/cQsOJcs4BsFgFjSaqE7SC8zob8hqc6cDNhJI/NBkk+","1","AY5W6p4jHeZG2jjW6nS1p4KDUhcqLkU6jz","tuLGZOimilSnypT91WrenQ=="); + Account account3 = getAccount("guffI05Eafq9F0j3/eQxHWGo1VN/xpeIkXysEPeH51C2YHYCNnCWTWAdqDB7lonl","1","ALZVrZrFqoSvqyi38n7mpPoeDp7DMtZ9b6","oZPg+5YotRWStVsRMYlhfg=="); +// Account account4 = getAccount("fAknSuXzMMC0nJ2+YuTpTLs6Hl5Dc0c2zHZBd2Q7vCuv8Wt97uYz1IU0t+AtrWts","1","AMogjmLf2QohTcGST7niV75ekZfj44SKme","0BVIiUf46rb/e5dVZIwfrg=="); +// Account account5 = getAccount("IufXVQfrL3LI7g2Q7dmmsdoF7BdoI/vHIsXAxd4qkqlkGBYj3pcWHoQgdCF+iVOv","1","AZzQTkZvjy7ih9gjvwU8KYiZZyNoy6jE9p","zUtzh0B4UW0wokzL+ILdeg=="); +// Account account6 = getAccount("PYEJ1c79aR7bxdzvBlj3lUMLp0VLKQHwSe+/OS1++1qa++gBMJJmJWJXUP5ZNhUs","1","AKEqQKmxCsjWJz8LPGryXzb6nN5fkK1WDY","uJhjsfcouCGZQUdHO2TZZQ=="); +// Account account7s = getAccount("ZG/SfHRArUkopwhQS1MW+a0fvQvyN1NnwonU0oZH8y1bGqo5T+dQz3rz1qsXqFI2","1","AQNpGWz4oHHFBejtBbakeR43DHfen7cm8L","6qiU9bgK/+1T2V8l14mszg=="); + + Account account100 = new Account(Helper.hexToBytes("5864530b5589d9e25f730ff27d6e2cf99b4f70028d8aebb3b4c4050af9c08276"),SignatureScheme.SHA256WITHECDSA); + + String swapAbi = "{\"hash\":\"0x1a5c9719acc4bfc6e9ab0027c757aa0ad71a6f4d\",\"entrypoint\":\"Main\",\"functions\":[{\"name\":\"Main\",\"parameters\":[{\"name\":\"operation\",\"type\":\"String\"},{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"Any\"},{\"name\":\"Swap\",\"parameters\":[{\"name\":\"from\",\"type\":\"ByteArray\"},{\"name\":\"to\",\"type\":\"ByteArray\"},{\"name\":\"fromSymbol\",\"type\":\"String\"},{\"name\":\"toSymbol\",\"type\":\"String\"},{\"name\":\"value\",\"type\":\"Integer\"}],\"returntype\":\"Boolean\"},{\"name\":\"SetTokenBase\",\"parameters\":[{\"name\":\"symbol\",\"type\":\"String\"},{\"name\":\"value\",\"type\":\"Integer\"}],\"returntype\":\"Boolean\"},{\"name\":\"GetTokenBase\",\"parameters\":[{\"name\":\"symbol\",\"type\":\"String\"}],\"returntype\":\"Integer\"},{\"name\":\"SetFeeRate\",\"parameters\":[{\"name\":\"percentage\",\"type\":\"Integer\"}],\"returntype\":\"Boolean\"},{\"name\":\"GetFeeRate\",\"parameters\":[],\"returntype\":\"Integer\"},{\"name\":\"SetContractHash\",\"parameters\":[{\"name\":\"key\",\"type\":\"String\"},{\"name\":\"hash\",\"type\":\"ByteArray\"}],\"returntype\":\"Boolean\"},{\"name\":\"GetContractHash\",\"parameters\":[{\"name\":\"key\",\"type\":\"String\"}],\"returntype\":\"ByteArray\"}],\"events\":[]}"; + + //TODO 1. 部署老庙和有乐合约, + // TODO 2. 执行合约中的deploy方法, + // TODO 3.执行group合约中SetContractHash方法设置contracthash, + // TODO 4. 执行group中的GetContractHash验证第3步是否正确执行, + // TODO 5.执行group合约中的GroupTransfer方法 + + + boolean deployContract = false;// 部署合约 + boolean deploy = false; //执行Token合约中的deploy方法 + boolean balanceOf = true; //执行合约中的balanceOf方法, 查询账户余额 + boolean SetContractHash = false;//执行group合约中的SetContractHash方法 + boolean GetContractHash = false;//执行group合约中的GetContractHash方法, 验证SetContractHash是否执行成功 + boolean GroupTransfer = true; //执行group合约中的GroupTransfer方法, + boolean transferMulti = false; //测试多转多 + + if(false){ + System.out.println(Address.parse("d2c124dd088190f709b684e0bc676d70c41b3776").toBase58()); + System.out.println(Address.parse("a34344eb3f7ea6ee8088ad6d13f5cfacc899dd88").toBase58()); + return; + } + //部署老庙,有乐合约,全家合约,group合约等 + if(false){ + String code = "011cc56b6c766b00527ac46c766b51527ac4616c766b00c30453776170876c766b52527ac46c766b52c364a900616c766b51c3c0559c009c6c766b58527ac46c766b58c3640e00006c766b59527ac46208036c766b51c300c36c766b53527ac46c766b51c351c36c766b54527ac46c766b51c352c36c766b55527ac46c766b51c353c36c766b56527ac46c766b51c354c36c766b57527ac46c766b53c36c766b54c36c766b55c36c766b56c36c766b57c3615479517956727551727553795279557275527275659a026c766b59527ac46287026c766b00c30c536574546f6b656e42617365876c766b5a527ac46c766b5ac3645d00616c766b51c3c0529c009c6c766b5d527ac46c766b5dc3640e00006c766b59527ac46240026c766b51c300c36c766b5b527ac46c766b51c351c36c766b5c527ac46c766b5bc36c766b5cc3617c6519066c766b59527ac4620b026c766b00c30c476574546f6b656e42617365876c766b5e527ac46c766b5ec3644900616c766b51c3c0519c009c6c766b60527ac46c766b60c3640e00006c766b59527ac462c4016c766b51c300c36c766b5f527ac46c766b5fc361659a066c766b59527ac462a3016c766b00c30a53657446656552617465876c766b0111527ac46c766b0111c3644d00616c766b51c3c0519c009c6c766b0113527ac46c766b0113c3640e00006c766b59527ac4625a016c766b51c300c36c766b0112527ac46c766b0112c361658b066c766b59527ac46237016c766b00c30a47657446656552617465876c766b0114527ac46c766b0114c364120061616540076c766b59527ac46206016c766b00c30f536574436f6e747261637448617368876c766b0115527ac46c766b0115c3646300616c766b51c3c0529c009c6c766b0118527ac46c766b0118c3640e00006c766b59527ac462b8006c766b51c300c36c766b0116527ac46c766b51c351c36c766b0117527ac46c766b0116c36c766b0117c3617c650a076c766b59527ac4627f006c766b00c30f476574436f6e747261637448617368876c766b0119527ac46c766b0119c3644d00616c766b51c3c0519c009c6c766b011b527ac46c766b011bc3640e00006c766b59527ac46231006c766b51c300c36c766b011a527ac46c766b011ac3616589076c766b59527ac4620e00006c766b59527ac46203006c766b59c3616c75660115c56b6c766b00527ac46c766b51527ac46c766b52527ac46c766b53527ac46c766b54527ac4616c766b54c3009f6c766b5d527ac46c766b5dc3640e00006c766b5e527ac462ac036c766b00c3c00114907c907c9e6311006c766b51c3c001149c009c620400516c766b5f527ac46c766b5fc3640e00006c766b5e527ac46273036c766b52c36165e0066c766b55527ac46c766b53c36165d0066c766b56527ac46c766b55c3c00114907c907c9e6311006c766b56c3c001149c009c620400516c766b60527ac46c766b60c3640e00006c766b5e527ac4621a0361682d53797374656d2e457865637574696f6e456e67696e652e476574457865637574696e67536372697074486173686c766b57527ac452c57600083131313131313131c476516c766b57c3c461681553797374656d2e52756e74696d652e4e6f746966796161681953797374656d2e53746f726167652e476574436f6e746578746c766b58527ac46c766b58c36105626173655f6c766b52c37e617c681253797374656d2e53746f726167652e4765746c766b59527ac46c766b58c36105626173655f6c766b53c37e617c681253797374656d2e53746f726167652e4765746c766b5a527ac452c576000732323232323232c476516c766b59c3c461681553797374656d2e52756e74696d652e4e6f746966796152c57600083333333333333333c476516c766b5ac3c461681553797374656d2e52756e74696d652e4e6f74696679616c766b59c300907c907ca1630f006c766b5ac300a0009c620400516c766b0111527ac46c766b0111c3644c006151c576001e496e76616c696420746f6b656e20636f6e76657274696f6e20626173652ec461681553797374656d2e52756e74696d652e4e6f7469667961006c766b5e527ac46261016c766b58c30766656552617465617c681253797374656d2e53746f726167652e4765746c766b5b527ac452c57600083434343434343434c476516c766b5bc3c461681553797374656d2e52756e74696d652e4e6f74696679616c766b5bc3009f6c766b0112527ac46c766b0112c3643f006151c5760011496e76616c69642066656520726174652ec461681553797374656d2e52756e74696d652e4e6f7469667961006c766b5e527ac462b4006c766b54c36c766b5ac3956c766b59c39601646c766b5bc394950164966c766b5c527ac46c766b00c36c766b51c36c766b55c36c766b54c3615379517955727551727552795279547275527275652f04009c6c766b0113527ac46c766b0113c364050061f06c766b57c36c766b51c36c766b56c36c766b5cc361537951795572755172755279527954727552727565ee03009c6c766b0114527ac46c766b0114c364050061f0516c766b5e527ac46203006c766b5ec3616c756656c56b6c766b00527ac46c766b51527ac4616c766b51c300a16c766b53527ac46c766b53c3640f00006c766b54527ac462b0006114d2c124dd088190f709b684e0bc676d70c41b377661681b53797374656d2e52756e74696d652e436865636b5769746e657373009c6c766b55527ac46c766b55c3640f00006c766b54527ac46260006105626173655f6c766b00c37e6c766b52527ac461681953797374656d2e53746f726167652e476574436f6e746578746c766b52c36c766b51c3615272681253797374656d2e53746f726167652e50757461516c766b54527ac46203006c766b54c3616c756652c56b6c766b00527ac46161681953797374656d2e53746f726167652e476574436f6e746578746105626173655f6c766b00c37e617c681253797374656d2e53746f726167652e4765746c766b51527ac46203006c766b51c3616c756654c56b6c766b00527ac4616c766b00c300907c907c9f6310006c766b00c301649f009c620400516c766b51527ac46c766b51c3640f00006c766b52527ac4629f006114d2c124dd088190f709b684e0bc676d70c41b377661681b53797374656d2e52756e74696d652e436865636b5769746e657373009c6c766b53527ac46c766b53c3640e00006c766b52527ac4624f0061681953797374656d2e53746f726167652e476574436f6e7465787407666565526174656c766b00c3615272681253797374656d2e53746f726167652e50757461516c766b52527ac46203006c766b52c3616c756651c56b6161681953797374656d2e53746f726167652e476574436f6e746578740766656552617465617c681253797374656d2e53746f726167652e4765746c766b00527ac46203006c766b00c3616c756655c56b6c766b00527ac46c766b51527ac4616114d2c124dd088190f709b684e0bc676d70c41b377661681b53797374656d2e52756e74696d652e436865636b5769746e657373009c6c766b52527ac46c766b52c3640e00006c766b53527ac46288006c766b00c30087631a006c766b00c3826411006c766b51c3c001149c009c620400516c766b54527ac46c766b54c3640e00006c766b53527ac4624c0061681953797374656d2e53746f726167652e476574436f6e746578746c766b00c36c766b51c3615272681253797374656d2e53746f726167652e50757461516c766b53527ac46203006c766b53c3616c756652c56b6c766b00527ac46161681953797374656d2e53746f726167652e476574436f6e746578746c766b00c3617c681253797374656d2e53746f726167652e4765746c766b51527ac46203006c766b51c3616c756658c56b6c766b00527ac46c766b51527ac46c766b52527ac46c766b53527ac46153c576006c766b00c3c476516c766b51c3c476526c766b53c3c46c766b54527ac452c57600083131313131313131c476516c766b00c3c461681553797374656d2e52756e74696d652e4e6f746966796152c57600083131313131313131c476516c766b51c3c461681553797374656d2e52756e74696d652e4e6f746966796152c57600083131313131313131c476516c766b53c3c461681553797374656d2e52756e74696d652e4e6f74696679616c766b52c36c766b55527ac46c766b55c3087472616e736665726c766b54c3617c527a670000000000000000000000000000000000000000009c6c766b56527ac46c766b56c3640e00006c766b57527ac4620e00516c766b57527ac46203006c766b57c3616c7566"; + System.out.println("ContractAddress:" + Address.AddressFromVmCode(code).toHexString()); + dnaSdk.vm().setCodeAddress(Address.AddressFromVmCode(code).toHexString()); + Account account = new Account(Helper.hexToBytes("957419a5ceaf5bd40e83e0fc59e71b0d7fef68149e3ea99f79149afc441549cd"),SignatureScheme.SHA256WITHECDSA); + Transaction tx = dnaSdk.vm().makeDeployCodeTransaction(code, true, "name", + "v1.0", "author", "email", "desp", account.getAddressU160().toBase58(),20600000,0); + dnaSdk.signTx(tx, new Account[][]{{account}}); + String txHex = Helper.toHexString(tx.toArray()); + System.out.println(tx.hash().toString()); + Object result = dnaSdk.getConnect().syncSendRawTransaction(txHex); + System.out.println(result); + System.exit(0); + } + + String swapAddress = "1a5c9719acc4bfc6e9ab0027c757aa0ad71a6f4d"; + String youleAddress = "749a701ae89c0dbdab9b4b660ba84ee478004219"; + String quanjiaAddress = "f9417534cbd3b09976f75f8597fe7be3fd88456b"; + String swapAddress2 = "016c1e1357727d539df2403f5a23fc2fe43ea579"; + + //执行合约中的deploy方法 + if(false){ + Account adminAcct = new Account(Helper.hexToBytes("75de8489fcb2dcaf2ef3cd607feffde18789de7da129b5e97c81e001793cb7cf"),SignatureScheme.SHA256WITHECDSA); + Account account = new Account(Helper.hexToBytes("f9d2d30ffb22dffdf4f14ad6f1303460efc633ea8a3014f638eaa19c259bada1"),SignatureScheme.SHA256WITHECDSA); + String abi = "{\"hash\":\"0xddd75e0e5c4aadc79f0ed83cd478920a37e9116f\",\"entrypoint\":\"Main\",\"functions\":[{\"name\":\"name\",\"parameters\":[],\"returntype\":\"String\"},{\"name\":\"symbol\",\"parameters\":[],\"returntype\":\"String\"},{\"name\":\"decimals\",\"parameters\":[],\"returntype\":\"Integer\"},{\"name\":\"Main\",\"parameters\":[{\"name\":\"operation\",\"type\":\"String\"},{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"Any\"},{\"name\":\"deploy\",\"parameters\":[],\"returntype\":\"Boolean\"},{\"name\":\"totalSupply\",\"parameters\":[],\"returntype\":\"Integer\"},{\"name\":\"transfer\",\"parameters\":[{\"name\":\"from\",\"type\":\"ByteArray\"},{\"name\":\"to\",\"type\":\"ByteArray\"},{\"name\":\"value\",\"type\":\"Integer\"}],\"returntype\":\"Boolean\"},{\"name\":\"balanceOf\",\"parameters\":[{\"name\":\"address\",\"type\":\"ByteArray\"}],\"returntype\":\"Integer\"},{\"name\":\"inflation\",\"parameters\":[{\"name\":\"count\",\"type\":\"Integer\"}],\"returntype\":\"Boolean\"},{\"name\":\"recycle\",\"parameters\":[{\"name\":\"count\",\"type\":\"Integer\"}],\"returntype\":\"Boolean\"}],\"events\":[]}"; + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + String name = "deploy"; + AbiFunction func = abiinfo.getFunction(name); + boolean preExec = false; + if (preExec){ + Object obj = dnaSdk.neovm().sendTransaction(Helper.reverse(youleAddress),null,null,20000,0,func, preExec); + System.out.println(obj); + }else { + Object obj = dnaSdk.neovm().sendTransaction(Helper.reverse(quanjiaAddress),adminAcct,adminAcct,20000,0,func, preExec); + System.out.println(obj); + Thread.sleep(6000); + System.out.println(dnaSdk.getConnect().getSmartCodeEvent((String) obj)); + } + return; + } + String laomiao = Account.getGcmDecodedPrivateKey("gpgMejEHzawuXG+ghLkZ8/cQsOJcs4BsFgFjSaqE7SC8zob8hqc6cDNhJI/NBkk+","1","AY5W6p4jHeZG2jjW6nS1p4KDUhcqLkU6jz",Base64.getDecoder().decode("tuLGZOimilSnypT91WrenQ=="),16384,SignatureScheme.SHA256WITHECDSA); + Account laomiaoAcct = new Account(Helper.hexToBytes(laomiao),SignatureScheme.SHA256WITHECDSA); + String youle = Account.getGcmDecodedPrivateKey("P2CK5DPZa+cfrkq9mK/1YeNU13cfPEm3ByUYrYNwrtqk9lc+UoM91UnOddc1wxWs","xinhao","ASUwFccvYFrrWR6vsZhhNszLFNvCLA5qS6",Base64.getDecoder().decode("tlWLpyfD54jM/27IvPXAWg=="),16384,SignatureScheme.SHA256WITHECDSA); + Account youleAcct = new Account(Helper.hexToBytes(youle),SignatureScheme.SHA256WITHECDSA); + //执行合约中的balanceOf方法 + if (false){ + Account account999 = new Account(Helper.hexToBytes("2ffe190d50ebcfbc8a765a4f25422275b900c476ba1fa72ea86fbdcf14900d74"),SignatureScheme.SHA256WITHECDSA); + + String abi = "{\"hash\":\"0xddd75e0e5c4aadc79f0ed83cd478920a37e9116f\",\"entrypoint\":\"Main\",\"functions\":[{\"name\":\"name\",\"parameters\":[],\"returntype\":\"String\"},{\"name\":\"symbol\",\"parameters\":[],\"returntype\":\"String\"},{\"name\":\"decimals\",\"parameters\":[],\"returntype\":\"Integer\"},{\"name\":\"Main\",\"parameters\":[{\"name\":\"operation\",\"type\":\"String\"},{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"Any\"},{\"name\":\"deploy\",\"parameters\":[],\"returntype\":\"Boolean\"},{\"name\":\"totalSupply\",\"parameters\":[],\"returntype\":\"Integer\"},{\"name\":\"transfer\",\"parameters\":[{\"name\":\"from\",\"type\":\"ByteArray\"},{\"name\":\"to\",\"type\":\"ByteArray\"},{\"name\":\"value\",\"type\":\"Integer\"}],\"returntype\":\"Boolean\"},{\"name\":\"balanceOf\",\"parameters\":[{\"name\":\"address\",\"type\":\"ByteArray\"}],\"returntype\":\"Integer\"},{\"name\":\"inflation\",\"parameters\":[{\"name\":\"count\",\"type\":\"Integer\"}],\"returntype\":\"Boolean\"},{\"name\":\"recycle\",\"parameters\":[{\"name\":\"count\",\"type\":\"Integer\"}],\"returntype\":\"Boolean\"}],\"events\":[]}"; + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + String name = "balanceOf"; + AbiFunction func = abiinfo.getFunction(name); + func.setParamsValue(Address.parse(swapAddress2).toArray()); + boolean preExec = true; + Object obj = dnaSdk.neovm().sendTransaction(Helper.reverse(quanjiaAddress),null,null,20000,0,func, preExec); + System.out.println(obj); + return; + } + // + //GetFeeRate + if (false){ + Account account999 = new Account(Helper.hexToBytes("2ffe190d50ebcfbc8a765a4f25422275b900c476ba1fa72ea86fbdcf14900d74"),SignatureScheme.SHA256WITHECDSA); + + AbiInfo abiinfo = JSON.parseObject(swapAbi, AbiInfo.class); + String name = "GetFeeRate"; + AbiFunction func = abiinfo.getFunction(name); + boolean preExec = true; + Object obj = dnaSdk.neovm().sendTransaction(Helper.reverse(swapAddress2),null,null,20000,0,func, preExec); + System.out.println(obj); + return; + } + Account adminAcct = new Account(Helper.hexToBytes("75de8489fcb2dcaf2ef3cd607feffde18789de7da129b5e97c81e001793cb7cf"),SignatureScheme.SHA256WITHECDSA); + //SetFeeRate + if (false){ + Account account999 = new Account(Helper.hexToBytes("2ffe190d50ebcfbc8a765a4f25422275b900c476ba1fa72ea86fbdcf14900d74"),SignatureScheme.SHA256WITHECDSA); + + AbiInfo abiinfo = JSON.parseObject(swapAbi, AbiInfo.class); + String name = "SetFeeRate"; + AbiFunction func = abiinfo.getFunction(name); + func.setParamsValue(5L); + boolean preExec = false; + Object obj = dnaSdk.neovm().sendTransaction(Helper.reverse(swapAddress2),adminAcct,adminAcct,20000,0,func, preExec); + System.out.println(obj); + Thread.sleep(6000); + System.out.println(dnaSdk.getConnect().getSmartCodeEvent((String)obj)); + return; + } + //GetTokenBase + if (false){ + Account account999 = new Account(Helper.hexToBytes("2ffe190d50ebcfbc8a765a4f25422275b900c476ba1fa72ea86fbdcf14900d74"),SignatureScheme.SHA256WITHECDSA); + + AbiInfo abiinfo = JSON.parseObject(swapAbi, AbiInfo.class); + String name = "GetTokenBase"; + AbiFunction func = abiinfo.getFunction(name); + func.setParamsValue("YLT"); + boolean preExec = true; + Object obj = dnaSdk.neovm().sendTransaction(Helper.reverse(swapAddress2),null,null,20000,0,func, preExec); + System.out.println(obj); + return; + } + + //SetContractHash + if (false){ + Account account999 = new Account(Helper.hexToBytes("2ffe190d50ebcfbc8a765a4f25422275b900c476ba1fa72ea86fbdcf14900d74"),SignatureScheme.SHA256WITHECDSA); + + AbiInfo abiinfo = JSON.parseObject(swapAbi, AbiInfo.class); + String name = "SetContractHash"; + AbiFunction func = abiinfo.getFunction(name); + func.setParamsValue("YLT", Helper.reverse(Address.parse(youleAddress).toArray())); + boolean preExec = false; + Object obj = dnaSdk.neovm().sendTransaction(Helper.reverse(swapAddress2),adminAcct,adminAcct,20000,0,func, preExec); + System.out.println(obj); + Thread.sleep(6000); + System.out.println(dnaSdk.getConnect().getSmartCodeEvent((String)obj)); + return; + } + //GetContractHash + if (false){ + Account account999 = new Account(Helper.hexToBytes("2ffe190d50ebcfbc8a765a4f25422275b900c476ba1fa72ea86fbdcf14900d74"),SignatureScheme.SHA256WITHECDSA); + + AbiInfo abiinfo = JSON.parseObject(swapAbi, AbiInfo.class); + String name = "GetContractHash"; + AbiFunction func = abiinfo.getFunction(name); + func.setParamsValue("QJT"); + boolean preExec = true; + Object obj = dnaSdk.neovm().sendTransaction(Helper.reverse(swapAddress2),null,null,20000,0,func, preExec); + System.out.println(obj); + return; + } + //SetTokenBase + if (false){ + Account account999 = new Account(Helper.hexToBytes("2ffe190d50ebcfbc8a765a4f25422275b900c476ba1fa72ea86fbdcf14900d74"),SignatureScheme.SHA256WITHECDSA); + + AbiInfo abiinfo = JSON.parseObject(swapAbi, AbiInfo.class); + String name = "SetTokenBase"; + AbiFunction func = abiinfo.getFunction(name); + func.setParamsValue("QJT", 1L); + boolean preExec = false; + Object obj = dnaSdk.neovm().sendTransaction(Helper.reverse(swapAddress2),adminAcct,adminAcct,20000,0,func, preExec); + System.out.println(obj); + Thread.sleep(6000); + System.out.println(dnaSdk.getConnect().getSmartCodeEvent((String)obj)); + return; + } + if(false){ + com.github.DNAProject.sdk.wallet.Account account9999999 = dnaSdk.getWalletMgr().importAccount("8p2q0vLRqyfKmFHhnjUYVWOm12kPm78JWqzkTOi9rrFMBz624KjhHQJpyPmiSSOa","111111","AHX1wzvdw9Yipk7E9MuLY4GGX4Ym9tHeDe",Base64.getDecoder().decode("KbiCUr53CZUfKG1M3Gojjw==")); + Account account = dnaSdk.getWalletMgr().getAccount(account9999999.address, "111111", account9999999.getSalt()); + dnaSdk.nativevm().gas().sendTransfer(account,account3.getAddressU160().toBase58(),100000,account,200000,0); + System.out.println(dnaSdk.getConnect().getBalance(account9999999.address)); + System.out.println(Helper.toHexString(account.serializePrivateKey())); + System.out.println(dnaSdk.nativevm().gas().unboundGas(account.getAddressU160().toBase58())); + dnaSdk.nativevm().gas().withdrawGas(account,account.getAddressU160().toBase58(),359943000000L,account,200000,0); + return; + } + + //Swap + if (true){ + com.github.DNAProject.sdk.wallet.Account account9999999 = dnaSdk.getWalletMgr().importAccount("8p2q0vLRqyfKmFHhnjUYVWOm12kPm78JWqzkTOi9rrFMBz624KjhHQJpyPmiSSOa","111111","AHX1wzvdw9Yipk7E9MuLY4GGX4Ym9tHeDe",Base64.getDecoder().decode("KbiCUr53CZUfKG1M3Gojjw==")); + Account account = dnaSdk.getWalletMgr().getAccount(account9999999.address, "111111", account9999999.getSalt()); + + AbiInfo abiinfo = JSON.parseObject(swapAbi, AbiInfo.class); + String name = "Swap"; + AbiFunction func = abiinfo.getFunction(name); + func.setParamsValue(adminAcct.getAddressU160().toArray(),Address.decodeBase58("AWf8NiLzXSDf1JB2Ae6YUKSHke4yLHMVCm").toArray(),"YLT","QJT",10L); + boolean preExec = false; + Object obj = dnaSdk.neovm().sendTransaction(Helper.reverse(swapAddress2),adminAcct,adminAcct,20474,0,func, preExec); + System.out.println(obj); + Thread.sleep(6000); + System.out.println(dnaSdk.getConnect().getSmartCodeEvent((String)obj)); + return; + } + //youle 749a701ae89c0dbdab9b4b660ba84ee478004219 + //laomiao 2ab4d126665141f5e3273dbe4935e2b4fe207552 + + if(true){ + + Account account999 = new Account(Helper.hexToBytes("2ffe190d50ebcfbc8a765a4f25422275b900c476ba1fa72ea86fbdcf14900d74"),SignatureScheme.SHA256WITHECDSA); + + Account account = new Account(Helper.hexToBytes("f9d2d30ffb22dffdf4f14ad6f1303460efc633ea8a3014f638eaa19c259bada1"),SignatureScheme.SHA256WITHECDSA); + String abi = "{\"hash\":\"0xddd75e0e5c4aadc79f0ed83cd478920a37e9116f\",\"entrypoint\":\"Main\",\"functions\":[{\"name\":\"name\",\"parameters\":[],\"returntype\":\"String\"},{\"name\":\"symbol\",\"parameters\":[],\"returntype\":\"String\"},{\"name\":\"decimals\",\"parameters\":[],\"returntype\":\"Integer\"},{\"name\":\"Main\",\"parameters\":[{\"name\":\"operation\",\"type\":\"String\"},{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"Any\"},{\"name\":\"deploy\",\"parameters\":[],\"returntype\":\"Boolean\"},{\"name\":\"totalSupply\",\"parameters\":[],\"returntype\":\"Integer\"},{\"name\":\"transfer\",\"parameters\":[{\"name\":\"from\",\"type\":\"ByteArray\"},{\"name\":\"to\",\"type\":\"ByteArray\"},{\"name\":\"value\",\"type\":\"Integer\"}],\"returntype\":\"Boolean\"},{\"name\":\"balanceOf\",\"parameters\":[{\"name\":\"address\",\"type\":\"ByteArray\"}],\"returntype\":\"Integer\"},{\"name\":\"inflation\",\"parameters\":[{\"name\":\"count\",\"type\":\"Integer\"}],\"returntype\":\"Boolean\"},{\"name\":\"recycle\",\"parameters\":[{\"name\":\"count\",\"type\":\"Integer\"}],\"returntype\":\"Boolean\"}],\"events\":[]}"; + abi = "{\"hash\":\"0xac941e00d99a7daa1d72530f01b1a8e5899bfb78\",\"entrypoint\":\"Main\",\"functions\":[{\"name\":\"name\",\"parameters\":[],\"returntype\":\"String\"},{\"name\":\"symbol\",\"parameters\":[],\"returntype\":\"String\"},{\"name\":\"decimals\",\"parameters\":[],\"returntype\":\"Integer\"},{\"name\":\"Main\",\"parameters\":[{\"name\":\"operation\",\"type\":\"String\"},{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"Any\"},{\"name\":\"deploy\",\"parameters\":[],\"returntype\":\"Boolean\"},{\"name\":\"totalSupply\",\"parameters\":[],\"returntype\":\"Integer\"},{\"name\":\"transfer\",\"parameters\":[{\"name\":\"from\",\"type\":\"ByteArray\"},{\"name\":\"to\",\"type\":\"ByteArray\"},{\"name\":\"value\",\"type\":\"Integer\"}],\"returntype\":\"Boolean\"},{\"name\":\"balanceOf\",\"parameters\":[{\"name\":\"address\",\"type\":\"ByteArray\"}],\"returntype\":\"Integer\"},{\"name\":\"inflation\",\"parameters\":[{\"name\":\"count\",\"type\":\"Integer\"}],\"returntype\":\"Boolean\"},{\"name\":\"recycle\",\"parameters\":[{\"name\":\"count\",\"type\":\"Integer\"}],\"returntype\":\"Boolean\"},{\"name\":\"transferMulti\",\"parameters\":[{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"Boolean\"}],\"events\":[]}"; + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + String name = "transfer"; + AbiFunction func = abiinfo.getFunction(name); + func.setParamsValue(youleAcct.getAddressU160().toArray(), Address.parse(Helper.reverse("1d6f7aba5129271efa0f1e38323d7fa0b3cd11f4")).toArray(),1000L); + boolean preExec = false; + Object obj = dnaSdk.neovm().sendTransaction(Helper.reverse("df57f2c82646b96ce2ae68dba27460958b46abf7"),youleAcct,adminAcct,20000,500,func, preExec); + System.out.println(obj); + Thread.sleep(6000); + System.out.println(dnaSdk.getConnect().getSmartCodeEvent((String) obj)); + return; + } + //youle 749a701ae89c0dbdab9b4b660ba84ee478004219 + //laomiao 2ab4d126665141f5e3273dbe4935e2b4fe207552 + //执行group合约中的SetContractHash方法 + if(false){ + com.github.DNAProject.sdk.wallet.Account adminAcc = dnaSdk.getWalletMgr().importAccount("bBkseVtWdArWNc2OfVnNONt+FV+6RRgvle2ffxYNrOU3bzGzq3dG07PXkzlunfi2","xinhao","AQf4Mzu1YJrhz9f3aRkkwSm9n3qhXGSh4p",Base64.getDecoder().decode("1NF1DK9zgDyB2cAcSRfB6w==")); + //有乐管理员Account + Account youleadminAcct = dnaSdk.getWalletMgr().getAccount("AQf4Mzu1YJrhz9f3aRkkwSm9n3qhXGSh4p","xinhao"); + com.github.DNAProject.sdk.wallet.Account quanjiaadminAcc = dnaSdk.getWalletMgr().importAccount("zJ2+ScaXH04G7zHh9QatqJTx4aZS1ehJ4TQlPAJ6n4qZZfzV6iWfC0novEzNwzil","xinhao","ANTPeXCffDZCaCXxY9u2UdssB2EYpP4BMh",Base64.getDecoder().decode("nAb1JNde0mC2PDYs9knxcQ==")); + //全家管理员Account + Account quanjiaadminAcct = dnaSdk.getWalletMgr().getAccount("AQf4Mzu1YJrhz9f3aRkkwSm9n3qhXGSh4p","xinhao"); + abi = "{\"hash\":\"0x7d59e893207e729410553d055cc976c262cc9e1b\",\"entrypoint\":\"Main\",\"functions\":[{\"name\":\"YL\",\"parameters\":[{\"name\":\"method\",\"type\":\"String\"},{\"name\":\"parameter\",\"type\":\"Array\"}],\"returntype\":\"Any\"},{\"name\":\"Main\",\"parameters\":[{\"name\":\"operation\",\"type\":\"String\"},{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"Any\"},{\"name\":\"GroupTransfer\",\"parameters\":[{\"name\":\"from\",\"type\":\"ByteArray\"},{\"name\":\"to\",\"type\":\"ByteArray\"},{\"name\":\"param\",\"type\":\"Array\"}],\"returntype\":\"Boolean\"},{\"name\":\"SetContractHash\",\"parameters\":[{\"name\":\"key\",\"type\":\"String\"},{\"name\":\"hash\",\"type\":\"ByteArray\"}],\"returntype\":\"Boolean\"},{\"name\":\"GetContractHash\",\"parameters\":[{\"name\":\"key\",\"type\":\"String\"}],\"returntype\":\"ByteArray\"}],\"events\":[]}"; + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + String name = "deploy"; + name = "SetContractHash";//对应的preExec 是false + AbiFunction func = abiinfo.getFunction(name); + func.setParamsValue("laomiao",Helper.reverse(Address.parse("2ab4d126665141f5e3273dbe4935e2b4fe207552").toArray())); + + boolean preExec = false; + if (preExec){ + Object obj = dnaSdk.neovm().sendTransaction(Helper.reverse("fb2ce5bd31bfb50662d95aaef1badcb8f8b71ce1"),null,null,20000,0,func, preExec); + System.out.println(obj); + }else { + Object obj = dnaSdk.neovm().sendTransaction(Helper.reverse("44f1f4ee6940b4f162d857411842f2d533892084"),quanjiaadminAcct,quanjiaadminAcct,20000,0,func, preExec); + + } + return; + } + //youle 749a701ae89c0dbdab9b4b660ba84ee478004219 + //laomiao 2ab4d126665141f5e3273dbe4935e2b4fe207552 + //执行group合约中的GetContractHash方法 + if(false){ + com.github.DNAProject.sdk.wallet.Account adminAcc = dnaSdk.getWalletMgr().importAccount("bBkseVtWdArWNc2OfVnNONt+FV+6RRgvle2ffxYNrOU3bzGzq3dG07PXkzlunfi2","xinhao","AQf4Mzu1YJrhz9f3aRkkwSm9n3qhXGSh4p",Base64.getDecoder().decode("1NF1DK9zgDyB2cAcSRfB6w==")); + //有乐管理员Account + Account youleadminAcct = dnaSdk.getWalletMgr().getAccount("AQf4Mzu1YJrhz9f3aRkkwSm9n3qhXGSh4p","xinhao"); + com.github.DNAProject.sdk.wallet.Account quanjiaadminAcc = dnaSdk.getWalletMgr().importAccount("zJ2+ScaXH04G7zHh9QatqJTx4aZS1ehJ4TQlPAJ6n4qZZfzV6iWfC0novEzNwzil","xinhao","ANTPeXCffDZCaCXxY9u2UdssB2EYpP4BMh",Base64.getDecoder().decode("nAb1JNde0mC2PDYs9knxcQ==")); + //全家管理员Account + Account quanjiaadminAcct = dnaSdk.getWalletMgr().getAccount("AQf4Mzu1YJrhz9f3aRkkwSm9n3qhXGSh4p","xinhao"); + abi = "{\"hash\":\"0x7d59e893207e729410553d055cc976c262cc9e1b\",\"entrypoint\":\"Main\",\"functions\":[{\"name\":\"YL\",\"parameters\":[{\"name\":\"method\",\"type\":\"String\"},{\"name\":\"parameter\",\"type\":\"Array\"}],\"returntype\":\"Any\"},{\"name\":\"Main\",\"parameters\":[{\"name\":\"operation\",\"type\":\"String\"},{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"Any\"},{\"name\":\"GroupTransfer\",\"parameters\":[{\"name\":\"from\",\"type\":\"ByteArray\"},{\"name\":\"to\",\"type\":\"ByteArray\"},{\"name\":\"param\",\"type\":\"Array\"}],\"returntype\":\"Boolean\"},{\"name\":\"SetContractHash\",\"parameters\":[{\"name\":\"key\",\"type\":\"String\"},{\"name\":\"hash\",\"type\":\"ByteArray\"}],\"returntype\":\"Boolean\"},{\"name\":\"GetContractHash\",\"parameters\":[{\"name\":\"key\",\"type\":\"String\"}],\"returntype\":\"ByteArray\"}],\"events\":[]}"; + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + String name = "GetContractHash"; //对应的preExec 是true + AbiFunction func = abiinfo.getFunction(name); + func.setParamsValue("laomiao"); //根据key查询合约hash + + boolean preExec = true; + if (preExec){ + Object obj = dnaSdk.neovm().sendTransaction(Helper.reverse("d755c02caf5741b1c3352a06a41271716a1fca78"),null,null,20000,0,func, preExec); + System.out.println(obj); + }else { + Object obj = dnaSdk.neovm().sendTransaction(Helper.reverse("fb2ce5bd31bfb50662d95aaef1badcb8f8b71ce1"),quanjiaadminAcct,quanjiaadminAcct,20000,0,func, preExec); + + } + return; + } + //youle 749a701ae89c0dbdab9b4b660ba84ee478004219 + //laomiao 2ab4d126665141f5e3273dbe4935e2b4fe207552 + //如果是GroupTransfer 就用下面的方法构造参数,,执行该方法之前 需要先部署好有乐合约和老庙合约 + //groupTransfer 单独测试 + if(false){ + Account account999 = new Account(Helper.hexToBytes("75de8489fcb2dcaf2ef3cd607feffde18789de7da129b5e97c81e001793cb7cf"),SignatureScheme.SHA256WITHECDSA); + com.github.DNAProject.sdk.wallet.Account adminAcc = dnaSdk.getWalletMgr().importAccount("bBkseVtWdArWNc2OfVnNONt+FV+6RRgvle2ffxYNrOU3bzGzq3dG07PXkzlunfi2","xinhao","AQf4Mzu1YJrhz9f3aRkkwSm9n3qhXGSh4p",Base64.getDecoder().decode("1NF1DK9zgDyB2cAcSRfB6w==")); + Account youleadminAcct = dnaSdk.getWalletMgr().getAccount("AQf4Mzu1YJrhz9f3aRkkwSm9n3qhXGSh4p","xinhao"); + com.github.DNAProject.sdk.wallet.Account quanjiaadminAcc = dnaSdk.getWalletMgr().importAccount("zJ2+ScaXH04G7zHh9QatqJTx4aZS1ehJ4TQlPAJ6n4qZZfzV6iWfC0novEzNwzil","xinhao","ANTPeXCffDZCaCXxY9u2UdssB2EYpP4BMh",Base64.getDecoder().decode("nAb1JNde0mC2PDYs9knxcQ==")); + Account quanjiaadminAcct = dnaSdk.getWalletMgr().getAccount("AQf4Mzu1YJrhz9f3aRkkwSm9n3qhXGSh4p","xinhao"); + abi = "{\"hash\":\"0x7d59e893207e729410553d055cc976c262cc9e1b\",\"entrypoint\":\"Main\",\"functions\":[{\"name\":\"YL\",\"parameters\":[{\"name\":\"method\",\"type\":\"String\"},{\"name\":\"parameter\",\"type\":\"Array\"}],\"returntype\":\"Any\"},{\"name\":\"Main\",\"parameters\":[{\"name\":\"operation\",\"type\":\"String\"},{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"Any\"},{\"name\":\"GroupTransfer\",\"parameters\":[{\"name\":\"from\",\"type\":\"ByteArray\"},{\"name\":\"to\",\"type\":\"ByteArray\"},{\"name\":\"param\",\"type\":\"Array\"}],\"returntype\":\"Boolean\"},{\"name\":\"SetContractHash\",\"parameters\":[{\"name\":\"key\",\"type\":\"String\"},{\"name\":\"hash\",\"type\":\"ByteArray\"}],\"returntype\":\"Boolean\"},{\"name\":\"GetContractHash\",\"parameters\":[{\"name\":\"key\",\"type\":\"String\"}],\"returntype\":\"ByteArray\"}],\"events\":[]}"; + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + + String functionName = "GroupTransfer"; + AbiFunction func = abiinfo.getFunction(functionName); + + //构造参数 + List list = new ArrayList(); + List list2 = new ArrayList(); + list2.add("youle"); + list2.add(1); + list.add(list2); + List list3 = new ArrayList(); + list3.add("laomiao"); + list3.add(1); + list.add(list3); + + func.setParamsValue(account999.getAddressU160().toArray(),Address.decodeBase58("AacHGsQVbTtbvSWkqZfvdKePLS6K659dgp").toArray(),list); + + dnaSdk.neovm().sendTransaction(Helper.reverse("44f1f4ee6940b4f162d857411842f2d533892084"),acct,acct,20000,500,func,false); +// +// Transaction tx = dnaSdk.vm().makeInvokeCodeTransaction(Helper.reverse("44f1f4ee6940b4f162d857411842f2d533892084"),null,params,account3.getAddressU160().toBase58(),20000,0); +// dnaSdk.signTx(tx,new Account[][]{{account999}}); +// dnaSdk.addSign(tx,account3); +// System.out.println(tx.hash().toHexString()); +// dnaSdk.getConnect().sendRawTransaction(tx); +// Thread.sleep(6000); +// +// System.out.println(dnaSdk.getConnect().getSmartCodeEvent(tx.hash().toHexString())); + + } + //多转多的测试 + if(transferMulti){ + Account adminAcct2 = new Account(Helper.hexToBytes("5f2fe68215476abb9852cfa7da31ef00aa1468782d5ca809da5c4e1390b8ee45"),SignatureScheme.SHA256WITHECDSA); + Account account = new Account(Helper.hexToBytes("f00dd7f5356e8aee93a049bdccc44ce91169e07ea3bec9f4e0142e456fd39bae"),SignatureScheme.SHA256WITHECDSA); + //多转多 特殊处理 不用function + String name = "transferMulti"; + List list = new ArrayList(); + List list2 = new ArrayList(); + list2.add(account.getAddressU160().toArray()); + list2.add(acct1.getAddressU160().toArray()); + list2.add(1); + list.add(list2); + List list3 = new ArrayList(); + list3.add(adminAcct.getAddressU160().toArray()); + list3.add(acct2.getAddressU160().toArray()); + list3.add(1); + list.add(list3); + + //多转多的特殊处理, + List listF = new ArrayList(); + listF.add(name.getBytes()); + listF.add(list); + byte[] params = BuildParams.createCodeParamsScript(listF); + Transaction tx = dnaSdk.vm().makeInvokeCodeTransaction(Helper.reverse("ad0bd8c715fcec8d7b3bed0fd1c88fcc8ef43927"),null,params,account.getAddressU160().toBase58(),20000,0); + dnaSdk.signTx(tx,new Account[][]{{account}}); + dnaSdk.addSign(tx,adminAcct); + dnaSdk.getConnect().sendRawTransaction(tx); + + Thread.sleep(6000); + System.out.println(dnaSdk.getConnect().getSmartCodeEvent(tx.hash().toHexString())); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static Account getAccount(String enpri,String password,String address,String salt) throws Exception { + String privateKey = Account.getGcmDecodedPrivateKey(enpri,password,address,Base64.getDecoder().decode(salt),16384,SignatureScheme.SHA256WITHECDSA); + Account account = new Account(Helper.hexToBytes(privateKey),SignatureScheme.SHA256WITHECDSA); +// System.out.println(Helper.toHexString(account.serializePublicKey())); + return account; + } + + public static DnaSdk getDnaSdk() throws Exception { + String ip = "http://127.0.0.1"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRestful()); + wm.openWalletFile("neovm.json"); + + + return wm; + } +} diff --git a/src/main/java/example/smartcontract/PunicaInitDemo.java b/src/main/java/example/smartcontract/PunicaInitDemo.java new file mode 100644 index 0000000..bde9bfd --- /dev/null +++ b/src/main/java/example/smartcontract/PunicaInitDemo.java @@ -0,0 +1,387 @@ +package example.smartcontract; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.crypto.SignatureScheme; +import com.github.DNAProject.sdk.exception.SDKException; +import com.github.DNAProject.smartcontract.neovm.abi.BuildParams; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +// Smart contract is in : https://github.com/punica-box/punica-init-default-box/tree/master/contracts +public class PunicaInitDemo { + + private static DnaSdk dnaSdk = null; + + public static String contractCode = "013ec56b6a00527ac46a51527ac46a00c3046e616d659c640900658e076c7566616a00c30568656c6c6f9c6424006a51c3c0519e640700006c7566616a51c300c36a52527ac46a52c36551076c7566616a00c3097465737448656c6c6f9c646c006a51c3c0559e640700006c7566616a51c300c36a53527ac46a51c351c36a54527ac46a51c352c36a55527ac46a51c353c36a56527ac46a51c354c36a57527ac46a53c36a54c36a55c36a56c36a57c354795179567275517275537952795572755272756553066c7566616a00c308746573744c6973749c6424006a51c3c0519e640700006c7566616a51c300c36a58527ac46a58c365e8056c7566616a00c30e746573744c697374416e645374729c6451006a51c351c176c9681553797374656d2e52756e74696d652e4e6f74696679616a51c3c0529e640700006c7566616a51c300c36a58527ac46a51c351c36a56527ac46a58c36a56c37c6528056c7566616a00c30e746573745374727563744c6973749c6431006a51c3681553797374656d2e52756e74696d652e4e6f74696679616a51c300c36a59527ac46a59c365a7046c7566616a00c314746573745374727563744c697374416e645374729c6432006a51c3c0529e640700006c7566616a51c300c36a59527ac46a51c351c36a56527ac46a59c36a56c37c65fa036c7566616a00c307746573744d61709c6416006a51c300c36a52527ac46a52c3655b036c7566616a00c30a746573744765744d61709c6424006a51c3c0519e640700006c7566616a51c300c36a5a527ac46a5ac365b1026c7566616a00c30c746573744d6170496e4d61709c6416006a51c300c36a52527ac46a52c365c2016c7566616a00c30f746573744765744d6170496e4d61709c6424006a51c3c0519e640700006c7566616a51c300c36a5a527ac46a5ac365e3006c7566616a00c30d7472616e736665724d756c74699c6416006a51c300c36a5b527ac46a5bc3650b006c756661006c756659c56b6a00527ac4006a52527ac46a00c3c06a53527ac4616a52c36a53c39f6473006a00c36a52c3c36a51527ac46a52c351936a52527ac46a51c3c0539e6420001b7472616e736665724d756c746920706172616d73206572726f722ef0616a51c300c36a51c351c36a51c352c35272652900009c64a2ff157472616e736665724d756c7469206661696c65642ef06288ff616161516c756656c56b6a00527ac46a51527ac46a52527ac4516c756657c56b6a00527ac4681953797374656d2e53746f726167652e476574436f6e7465787461086d61705f6b6579327c681253797374656d2e53746f726167652e476574616a51527ac40f746573744765744d6170496e4d61706a51c352c176c9681553797374656d2e52756e74696d652e4e6f74696679616a51c3681a53797374656d2e52756e74696d652e446573657269616c697a65616a52527ac46a52c36a00c3c36c756659c56b6a00527ac46a00c36a51527ac46a51c3681853797374656d2e52756e74696d652e53657269616c697a65616a52527ac4076d6170496e666f6a52c352c176c9681553797374656d2e52756e74696d652e4e6f74696679616a51c3036b6579c3681853797374656d2e52756e74696d652e53657269616c697a65616a53527ac4681953797374656d2e53746f726167652e476574436f6e7465787461086d61705f6b6579326a53c35272681253797374656d2e53746f726167652e507574616a52c36c756656c56b6a00527ac4681953797374656d2e53746f726167652e476574436f6e7465787461076d61705f6b65797c681253797374656d2e53746f726167652e476574616a51527ac46a51c3681a53797374656d2e52756e74696d652e446573657269616c697a65616a52527ac46a52c36a00c3c36c756657c56b6a00527ac46a00c36a51527ac46a51c3681853797374656d2e52756e74696d652e53657269616c697a65616a52527ac4681953797374656d2e53746f726167652e476574436f6e7465787461076d61705f6b65796a52c35272681253797374656d2e53746f726167652e507574616a51c3036b6579c36c756659c56b6a00527ac46a51527ac414746573745374727563744c697374416e645374726a00c36a51c353c176c9681553797374656d2e52756e74696d652e4e6f746966796100c176c96a52527ac46a52c36a00c3c86a52c36a51c3c86a52c36c756655c56b6a00527ac40e746573745374727563744c6973746a00c352c176c9681553797374656d2e52756e74696d652e4e6f74696679616a00c36c756659c56b6a00527ac46a51527ac40e746573744c697374416e645374726a00c36a51c353c176c9681553797374656d2e52756e74696d652e4e6f746966796100c176c96a52527ac46a52c36a00c3c86a52c36a51c3c86a52c36c756655c56b6a00527ac40b746573744d73674c6973746a00c352c176c9681553797374656d2e52756e74696d652e4e6f74696679616a00c36c75665fc56b6a00527ac46a51527ac46a52527ac46a53527ac46a54527ac4097465737448656c6c6f6a00c36a51c36a52c36a53c36a54c356c176c9681553797374656d2e52756e74696d652e4e6f746966796100c176c96a55527ac46a55c36a00c3c86a55c36a51c3c86a55c36a52c3c86a55c36a53c3c86a55c36a54c3c86a55c36c756654c56b6a00527ac46a00c36c756653c56b046e616d656c7566"; + + private PunicaInitDemo(){ + } + + + public static void main(String[] args2) { + try{ + dnaSdk = getDnaSdk(); + + Account account = new Account(Helper.hexToBytes("274b0b664d9c1e993c1d62a42f78ba84c379e332aa1d050ce9c1840820acee8b"), SignatureScheme.SHA256WITHECDSA); + Account account2 = new Account(Helper.hexToBytes("67ae8a3731709d8c820c03b200b9552ec61e6634cbcaf8a6a1f9d8f9f0f608"), SignatureScheme.SHA256WITHECDSA); + + // deployment + if(false){ + System.out.println("Test Function deployContract start -------"); + System.out.println("ContractAddress:" + Address.AddressFromVmCode(contractCode).toHexString()); + + dnaSdk.vm().setCodeAddress(Address.AddressFromVmCode(contractCode).toHexString()); + Transaction tx = dnaSdk.vm().makeDeployCodeTransaction(contractCode, true, "name", + "v1.0", "author", "email", "desp", account.getAddressU160().toBase58(),30000000L,0); + dnaSdk.signTx(tx, new Account[][]{{account}}); + String txHex = Helper.toHexString(tx.toArray()); + + System.out.println(txHex); + Object result = dnaSdk.getConnect().syncSendRawTransaction(txHex); + System.out.println(result); + System.out.println(); + System.exit(0); + } + + // hello + if(true){ + System.out.println(); + System.out.println("1. Test Function hello start -------"); + List paramList = new ArrayList<>(); + paramList.add("hello".getBytes()); + + List args = new ArrayList(); + args.add("helloWorld"); + + paramList.add(args); + byte[] params = BuildParams.createCodeParamsScript(paramList); + + String result = invokeContract(params, account, 20000, 500,true); + System.out.println(result); + System.out.println("hello return is: " + new String(Helper.hexToBytes(JSON.parseObject(result).getString("Result")))); + System.out.println(); + } + + // testHello + if(true){ + System.out.println("2. Test Function testHello start -------"); + List paramList = new ArrayList<>(); + paramList.add("testHello".getBytes()); + + List args = new ArrayList(); + args.add(true); + args.add(100); + args.add("test".getBytes()); + args.add("test"); + args.add(account.getAddressU160().toArray()); + + paramList.add(args); + byte[] params = BuildParams.createCodeParamsScript(paramList); + + String result = invokeContract(params, account, 20000, 500,true); + System.out.println(result); + List resultList = JSON.parseObject(JSON.parseObject(result).getString("Result"), List.class); + System.out.println("testHello return size is: " + resultList.size()); + System.out.println(); + } + + // testList + if(true){ + System.out.println("3. Test Function testList start -------"); + List paramList = new ArrayList<>(); + paramList.add("testList".getBytes()); + + List args = new ArrayList(); + List list = new ArrayList(); + list.add(1); + list.add(2); + list.add(3); + list.add(4); + list.add(5); + args.add(list); + + paramList.add(args); + byte[] params = BuildParams.createCodeParamsScript(paramList); + + + String result = invokeContract(params, account, 20000, 500,true); + System.out.println(result); + List resultList = JSON.parseObject(JSON.parseObject(result).getString("Result"), List.class); + System.out.println("testNumList return size is: " + resultList.size()); + System.out.println("testNumList return is: " + Integer.valueOf(resultList.get(0))); + System.out.println(); + } + + // testListAndStr + if(true){ + System.out.println("4. Test Function testListAndStr start -------"); + List paramList = new ArrayList<>(); + paramList.add("testListAndStr".getBytes()); + + List args = new ArrayList(); + List list = new ArrayList(); + list.add(1); + list.add(2); + list.add(3); + list.add(4); + list.add(5); + args.add(list); + args.add("test"); + + paramList.add(args); + byte[] params = BuildParams.createCodeParamsScript(paramList); + + + String result = invokeContract(params, account, 20000, 500,true); + System.out.println(result); + List resultList = JSON.parseObject(JSON.parseObject(result).getString("Result"), List.class); + System.out.println("testListAndStr return size is: " + resultList.size()); + System.out.println("testListAndStr Str return is: " + new String(Helper.hexToBytes(resultList.get(1)))); + System.out.println(); + } + + // testStructList + if(true){ + System.out.println("7. Test Function testStructList start -------"); + List paramList = new ArrayList<>(); + paramList.add("testStructList".getBytes()); + + List args = new ArrayList(); + List list = new ArrayList(); + List structList = new ArrayList(); + List structList2 = new ArrayList(); + structList.add("hello"); + structList.add(1); + structList2.add("hello2"); + structList2.add(2); + list.add(structList); + list.add(structList2); + args.add(list); + + paramList.add(args); + byte[] params = BuildParams.createCodeParamsScript(paramList); + + String result = invokeContract(params, account, 20000, 500,true); + System.out.println(result); + List resultList = JSON.parseObject(JSON.parseObject(result).getString("Result"), List.class); + + System.out.println("testStructList return size is: " + resultList.size()); + System.out.println(); + } + + // testStructListAndStr + if(true){ + System.out.println("8. Test Function testStructListAndStr start -------"); + List paramList = new ArrayList<>(); + paramList.add("testStructListAndStr".getBytes()); + + List args = new ArrayList(); + List list = new ArrayList(); + List structList = new ArrayList(); + List structList2 = new ArrayList(); + structList.add("hello"); + structList.add(1); + structList2.add("hello2"); + structList2.add(2); + list.add(structList); + list.add(structList2); + args.add(list); + args.add("test"); + + paramList.add(args); + byte[] params = BuildParams.createCodeParamsScript(paramList); + + String result = invokeContract(params, account, 20000, 500,true); + System.out.println(result); + List resultList = JSON.parseObject(JSON.parseObject(result).getString("Result"), List.class); + System.out.println("testStructListAndStr return size is: " + resultList.size()); + System.out.println(); + } + + // testMap + if(true){ + System.out.println("9. Test Function testMap start -------"); + List paramList = new ArrayList<>(); + paramList.add("testMap".getBytes()); + + List args = new ArrayList(); + Map map = new HashMap<>(); + map.put("key0","hello2"); + map.put("key2","hello".getBytes()); + map.put("key3",Long.valueOf(100)); + List list = new ArrayList(); + list.add(100); + list.add("hello"); + list.add(true); + map.put("key",list); + map.put("key5",true); + args.add(map); + + paramList.add(args); + byte[] params = BuildParams.createCodeParamsScript(paramList); + + System.out.println(Helper.toHexString(params)); + String preResult = invokeContract(params, account, 20000, 500,true); + System.out.println(preResult); + String result = invokeContract(params, account, 20000, 500,false); + Thread.sleep(6000); + System.out.println(result); + System.out.println("testMap return is: " + result); + System.out.println(); + } + + // testGetMap + if(true){ + System.out.println("10. Test Function testGetMap start -------"); + List paramList = new ArrayList<>(); + paramList.add("testGetMap".getBytes()); + + List args = new ArrayList(); + args.add("key"); + + paramList.add(args); + byte[] params = BuildParams.createCodeParamsScript(paramList); + + String result = invokeContract(params, account, 20000, 500,true); + System.out.println(result); + System.out.println(); + } + // testMapInMap + if(true){ + System.out.println("11. Test Function testMapInMap start -------"); + List paramList = new ArrayList<>(); + paramList.add("testMapInMap".getBytes()); + + List args = new ArrayList(); + Map map = new HashMap<>(); + Map map2 = new HashMap<>(); + map2.put("key","hello2"); + map2.put("key2","hello".getBytes()); + map2.put("key3",100); + List list = new ArrayList(); + list.add(10000); + list.add("hello"); + list.add(false); + map2.put("key", list); + map2.put("key5", true); + + map.put("key",map2); + map.put("key2","test"); + map.put("key4",true); + map.put("key3", list); + args.add(map); + System.out.println(Helper.toHexString("key0".getBytes())+" "+Helper.toHexString("hello2".getBytes())); + paramList.add(args); + byte[] params = BuildParams.createCodeParamsScript(paramList); + String preResult = invokeContract(params, account, 20000, 500,true); + System.out.println(preResult); + + byte[] mBytes = Helper.hexToBytes(JSON.parseObject(preResult).getString("Result")); + Object obj = BuildParams.deserializeItem(mBytes); + System.out.println(JSON.toJSONString(obj)); + + String result = invokeContract(params, account, 20000, 500,false); + Thread.sleep(6000); + System.out.println(result); + System.out.println("testMap return is: " + result); + System.out.println(); + } + + // testGetMapInMap + if(true){ + System.out.println("12. Test Function testGetMapInMap start -------"); + List paramList = new ArrayList<>(); + paramList.add("testGetMapInMap".getBytes()); + + List args = new ArrayList(); + args.add("key"); + + paramList.add(args); + byte[] params = BuildParams.createCodeParamsScript(paramList); + + String preResult = invokeContract(params, account, 20000, 500,true); + System.out.println(preResult); + System.out.println(); + } + // transferMulti + if(false){ + System.out.println("13. Test Function transferMulti start -------"); + List paramList = new ArrayList<>(); + paramList.add("transferMulti".getBytes()); + + List args = new ArrayList(); + List state = new ArrayList(); + List state2 = new ArrayList(); + state.add(account.getAddressU160().toArray()); + state.add(account.getAddressU160().toArray()); + state.add(Long.valueOf(10)); + state2.add(account.getAddressU160().toArray()); + state2.add(account.getAddressU160().toArray()); + state2.add(Long.valueOf(10)); + args.add(state); + args.add(state2); + paramList.add(args); + byte[] params = BuildParams.createCodeParamsScript(paramList); + + String result = invokeContract(params, account, 20000, 500,true); + System.out.println(result); + System.out.println(); + } + } + catch (Exception e){ + e.printStackTrace(); + } + } + + + public static String invokeContract(byte[] params, Account payerAcct, long gaslimit, long gasprice, boolean preExec) throws Exception{ + if(payerAcct == null){ + throw new SDKException("params should not be null"); + } + if(gaslimit < 0 || gasprice< 0){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + + Transaction tx = dnaSdk.vm().makeInvokeCodeTransaction(Helper.reverse(dnaSdk.neovm().oep4().getContractAddress()),null,params,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + + dnaSdk.addSign(tx, payerAcct); +// MultiSign +// Account account = new Account(Helper.hexToBytes("274b0b664d9c1e993c1d62a42f78ba84c379e332aa1d050ce9c1840820acee8b"),SignatureScheme.SHA256WITHECDSA); +// Account account2 = new Account(Helper.hexToBytes("67ae8a3731709d8c820c03b200b9552ec61e6634cbcaf8a6a1f9d8f9f0f608"),SignatureScheme.SHA256WITHECDSA); +// dnaSdk.addMultiSign(tx,2,new byte[][]{account.serializePublicKey(),account2.serializePublicKey()},account); +// dnaSdk.addMultiSign(tx,2,new byte[][]{account.serializePublicKey(),account2.serializePublicKey()},account2); + Object result = null; + if(preExec) { + result = dnaSdk.getConnect().sendRawTransactionPreExec(tx.toHexString()); + }else { + result = dnaSdk.getConnect().sendRawTransaction(tx.toHexString()); + return tx.hash().toString(); + } + + return result.toString(); + } + + + public static DnaSdk getDnaSdk() throws Exception{ + String ip = "http://127.0.0.1";//"http://polaris1.ont.io";// + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRestful()); + wm.neovm().oep4().setContractAddress("16edbe366d1337eb510c2ff61099424c94aeef02"); //9bbdd7c62fbe673c1340763b6d96e0379226a559 57785bb2eae2ced1604a532076806fc9b433f3a7 + wm.openWalletFile("wallet.json"); + + return wm; + } +} diff --git a/src/main/java/example/smartcontract/RecordTxDemo.java b/src/main/java/example/smartcontract/RecordTxDemo.java new file mode 100644 index 0000000..b843599 --- /dev/null +++ b/src/main/java/example/smartcontract/RecordTxDemo.java @@ -0,0 +1,54 @@ +package example.smartcontract; + +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.sdk.wallet.Identity; + +public class RecordTxDemo { + + + public static void main(String[] args){ + try { + DnaSdk dnaSdk = getDnaSdk(); + + if(dnaSdk.getWalletMgr().getWallet().getIdentities().size() < 1) { + + dnaSdk.getWalletMgr().createIdentity("passwordtest"); + dnaSdk.getWalletMgr().writeWallet(); + } + + + Identity id = dnaSdk.getWalletMgr().getWallet().getIdentities().get(0); + + String hash = dnaSdk.neovm().record().sendPut(id.dnaid,"passwordtest",new byte[]{},"key","value-test",0,0); + System.out.println(hash); + Thread.sleep(6000); + String res = dnaSdk.neovm().record().sendGet(id.dnaid,"passwordtest",new byte[]{},"key"); + System.out.println("result:"+res); + + //System.out.println(dnaSdk.getConnectMgr().getSmartCodeEvent(hash)); + + } catch (Exception e) { + e.printStackTrace(); + } + + } + + + + public static DnaSdk getDnaSdk() throws Exception { + String ip = "http://127.0.0.1"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRestful()); + + wm.openWalletFile("RecordTxDemo.json"); + + wm.neovm().record().setContractAddress("80f6bff7645a84298a1a52aa3745f84dba6615cf"); + return wm; + } +} diff --git a/src/main/java/example/transaction/CreateManyTx.java b/src/main/java/example/transaction/CreateManyTx.java new file mode 100644 index 0000000..12de65e --- /dev/null +++ b/src/main/java/example/transaction/CreateManyTx.java @@ -0,0 +1,80 @@ +package example.transaction; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.common.Common; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.crypto.SignatureScheme; +import com.github.DNAProject.sdk.wallet.Identity; + +import java.io.*; + +/** + * + * + */ +public class CreateManyTx { + public static String privatekey1 = "49855b16636e70f100cc5f4f42bc20a6535d7414fb8845e7310f8dd065a97221"; + public static String filePath = "txs.txt"; + public static void main(String[] args){ + + try { + DnaSdk dnaSdk = getDnaSdk(); + com.github.DNAProject.account.Account payerAcct = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey1), SignatureScheme.SHA256WITHECDSA); + if(true) { //open file, make registry dnaid transaction, save tx to file. + File file = new File(filePath); + if (!file.exists()) { + file.createNewFile(); + } + FileOutputStream fos = new FileOutputStream(file); + for (int i = 0; i < 3; i++) { + com.github.DNAProject.account.Account account = new com.github.DNAProject.account.Account(SignatureScheme.SHA256WITHECDSA); + String dnaid = Common.diddna + account.getAddressU160().toBase58(); + Transaction tx = dnaSdk.nativevm().dnaId().makeRegister(dnaid, Helper.toHexString(account.serializePublicKey()), payerAcct.getAddressU160().toBase58(), 20000, 500); + dnaSdk.addSign(tx, account); + dnaSdk.addSign(tx, payerAcct); + System.out.println("PrivateKey:"+Helper.toHexString(account.serializePrivateKey())+",txhash:"+tx.hash().toString()); + Identity identity = dnaSdk.getWalletMgr().createIdentityFromPriKey("password",Helper.toHexString(account.serializePrivateKey())); + System.out.println(JSON.toJSONString(identity)); + + fos.write(tx.toHexString().getBytes()); + fos.write(",".getBytes()); + fos.write(tx.hash().toString().getBytes()); + fos.write("\n".getBytes()); + } + } + if(true){ //read transaction from file, send transaction to node + FileReader fr = new FileReader(filePath); + BufferedReader bf = new BufferedReader(fr); + String txHex = null; + while ((txHex=bf.readLine())!=null){ + txHex = txHex.split(",")[0]; + Object obj = dnaSdk.getConnect().sendRawTransactionPreExec(txHex);//change to sendRawTransaction + System.out.println(obj); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + + } + public static DnaSdk getDnaSdk() throws Exception { + + String ip = "http://127.0.0.1"; +// String ip = "http://54.222.182.88; +// String ip = "http://101.132.193.149"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRestful()); + + wm.openWalletFile("ClaimDemo.json"); + + return wm; + } +} diff --git a/src/main/java/example/transaction/MakeTxWithJsonDemo.java b/src/main/java/example/transaction/MakeTxWithJsonDemo.java new file mode 100644 index 0000000..8dd7729 --- /dev/null +++ b/src/main/java/example/transaction/MakeTxWithJsonDemo.java @@ -0,0 +1,123 @@ +package example.transaction; + +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.transaction.Transaction; + +import java.util.*; + +// +// +public class MakeTxWithJsonDemo { + public static void main(String[] args) { + + try { + DnaSdk dnaSdk = getDnaSdk(); + String str = "{\"action\":\"invoke\",\"params\":{\"login\":true,\"url\":\"http://127.0.0.1:80/rawtransaction/txhash\",\"message\":\"will pay 1 gas in this transaction\",\"invokeConfig\":{\"contractHash\":\"16edbe366d1337eb510c2ff61099424c94aeef02\",\"functions\":[{\"operation\":\"method name\",\"args\":[{\"name\":\"arg0-list\",\"value\":[true,100,\"Long:100000000000\",\"Address:AUr5QUfeBADq6BMY6Tp5yuMsUNGpsD7nLZ\",\"ByteArray:aabb\",\"String:hello\",[true,100],{\"key\":6}]},{\"name\":\"arg1-map\",\"value\":{\"key\":\"String:hello\",\"key1\":\"ByteArray:aabb\",\"key2\":\"Long:100000000000\",\"key3\":true,\"key4\":100,\"key5\":[100],\"key6\":{\"key\":6}}},{\"name\":\"arg2-str\",\"value\":\"String:test\"}]}],\"payer\":\"AUr5QUfeBADq6BMY6Tp5yuMsUNGpsD7nLZ\",\"gasLimit\":20000,\"gasPrice\":500,\"signature\":{\"m\":1,\"signers\":[\"AUr5QUfeBADq6BMY6Tp5yuMsUNGpsD7nLZ\"]}}}}"; + Transaction[] txs = dnaSdk.makeTransactionByJson(str); + if(true) { + str = "{\n" + + "\t\"action\": \"invoke\",\n" + + "\t\"params\": {\n" + + "\t\t\"login\": true,\n" + + "\t\t\"url\": \"http://127.0.0.1:80/rawtransaction/txhash\",\n" + + "\t\t\"message\": \"will pay 1 gas in this transaction\",\n" + + "\t\t\"invokeConfig\": {\n" + + "\t\t\t\"contractHash\": \"cd948340ffcf11d4f5494140c93885583110f3e9\",\n" + + "\t\t\t\"functions\": [{\n" + + "\t\t\t\t\"operation\": \"transferNativeAsset\",\n" + + "\t\t\t\t\"args\": [{\n" + + "\t\t\t\t\t\"name\": \"arg0\",\n" + + "\t\t\t\t\t\"value\": \"String:ont\"\n" + + "\t\t\t\t}, {\n" + + "\t\t\t\t\t\"name\": \"arg1\",\n" + + "\t\t\t\t\t\"value\": \"Address:AUr5QUfeBADq6BMY6Tp5yuMsUNGpsD7nLZ\"\n" + + "\t\t\t\t}, {\n" + + "\t\t\t\t\t\"name\": \"arg2\",\n" + + "\t\t\t\t\t\"value\": \"Address:AecaeSEBkt5GcBCxwz1F41TvdjX3dnKBkJ\"\n" + + "\t\t\t\t}, {\n" + + "\t\t\t\t\t\"name\": \"arg3\",\n" + + "\t\t\t\t\t\"value\": 10\n" + + "\n" + + "\t\t\t\t}]\n" + + "\t\t\t}],\n" + + "\t\t\t\"payer\": \"AUr5QUfeBADq6BMY6Tp5yuMsUNGpsD7nLZ\",\n" + + "\t\t\t\"gasLimit\": 20000,\n" + + "\t\t\t\"gasPrice\": 500,\n" + + "\t\t\t\"signature\": {\n" + + "\t\t\t\t\"m\": 1,\n" + + "\t\t\t\t\"signers\": [\"AUr5QUfeBADq6BMY6Tp5yuMsUNGpsD7nLZ\"]\n" + + "\t\t\t}\n" + + "\t\t}\n" + + "\t}\n" + + "}"; + //System.out.println(str); + com.github.DNAProject.account.Account acct = new com.github.DNAProject.account.Account(Helper.hexToBytes("274b0b664d9c1e993c1d62a42f78ba84c379e332aa1d050ce9c1840820acee8b"), dnaSdk.defaultSignScheme); + Transaction[] txs1 = dnaSdk.makeTransactionByJson(str); + //System.out.println(tx.json()); + dnaSdk.addSign(txs1[0], acct); + Object obj = dnaSdk.getConnect().sendRawTransactionPreExec(txs1[0].toHexString()); + System.out.println(obj); + System.exit(0); + } + + List paramList = new ArrayList<>(); + paramList.add("method name"); + + List args2 = new ArrayList(); + Map map = new HashMap<>(); + Map map2 = new HashMap<>(); + map.put("key1",Helper.hexToBytes("aabb")); + map.put("key2",100000000000L); + map.put("key3",true); + map.put("key4",100); + map.put("key","hello".getBytes()); + List list0 = new ArrayList(); + list0.add(100); + map.put("key5",list0); + map2.put("key",6); + map.put("key6",map2); + List list = new ArrayList(); + List list2 = new ArrayList(); + list.add(true); + list.add(100); + list.add(100000000000L); + list.add(Address.decodeBase58("AUr5QUfeBADq6BMY6Tp5yuMsUNGpsD7nLZ").toArray()); + list.add(Helper.hexToBytes("aabb")); + list.add("hello".getBytes()); + list2.add(true); + list2.add(100); + list.add(list2); + list.add(map2); + args2.add(list); + args2.add(map); + args2.add("test".getBytes()); + + paramList.add(args2); + System.out.println("########make by self##############"); + System.out.println(paramList); + System.exit(0); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static DnaSdk getDnaSdk() throws Exception { + + String ip = "http://127.0.0.1"; +// String ip = "http://101.132.193.149"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRpc()); + + wm.openWalletFile("wallet2.dat"); + + return wm; + } +} diff --git a/src/main/java/example/transaction/MakeTxWithoutWalletDemo.java b/src/main/java/example/transaction/MakeTxWithoutWalletDemo.java new file mode 100644 index 0000000..7f04716 --- /dev/null +++ b/src/main/java/example/transaction/MakeTxWithoutWalletDemo.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package example.transaction; + +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.asset.Contract; +import com.github.DNAProject.core.asset.State; +import com.github.DNAProject.core.asset.Transfers; +import com.github.DNAProject.core.payload.InvokeCode; +import com.github.DNAProject.core.transaction.Transaction; + +public class MakeTxWithoutWalletDemo { + public static String privatekey1 = "49855b16636e70f100cc5f4f42bc20a6535d7414fb8845e7310f8dd065a97221"; + public static String privatekey2 = "1094e90dd7c4fdfd849c14798d725ac351ae0d924b29a279a9ffa77d5737bd96"; + public static String privatekey3 = "bc254cf8d3910bc615ba6bf09d4553846533ce4403bc24f58660ae150a6d64cf"; + public static String privatekey4 = "06bda156eda61222693cc6f8488557550735c329bc7ca91bd2994c894cd3cbc8"; + public static String privatekey5 = "f07d5a2be17bde8632ec08083af8c760b41b5e8e0b5de3703683c3bdcfb91549"; + public static String privatekey6 = "6c2c7eade4c5cb7c9d4d6d85bfda3da62aa358dd5b55de408d6a6947c18b9279"; + public static String privatekey7 = "24ab4d1d345be1f385c75caf2e1d22bdb58ef4b650c0308d9d69d21242ba8618"; + public static String privatekey8 = "87a209d232d6b4f3edfcf5c34434aa56871c2cb204c263f6b891b95bc5837cac"; + public static String privatekey9 = "1383ed1fe570b6673351f1a30a66b21204918ef8f673e864769fa2a653401114"; + + public static void main(String[] args) { + try { + DnaSdk dnaSdk = getDnaSdk(); + + String privatekey0 = "523c5fcf74823831756f0bcb3634234f10b3beb1c05595058534577752ad2d9f"; + com.github.DNAProject.account.Account acct0 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey0), dnaSdk.defaultSignScheme); + System.out.println(Helper.toHexString(acct0.serializePublicKey())); + + com.github.DNAProject.account.Account acct1 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey1), dnaSdk.defaultSignScheme); + com.github.DNAProject.account.Account acct2 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey2), dnaSdk.defaultSignScheme); + com.github.DNAProject.account.Account acct3 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey3), dnaSdk.defaultSignScheme); + com.github.DNAProject.account.Account acct4 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey4), dnaSdk.defaultSignScheme); + com.github.DNAProject.account.Account acct5 = new com.github.DNAProject.account.Account(Helper.hexToBytes(privatekey5), dnaSdk.defaultSignScheme); + + + if (false) { + //transer + Address sender = acct0.getAddressU160(); + Address recvAddr = Address.addressFromMultiPubKeys(2, acct1.serializePublicKey(), acct2.serializePublicKey()); +// Address recvAddr = Address.decodeBase58("TA5SgQXTeKWyN4GNfWGoXqioEQ4eCDFMqE"); + System.out.println("sender:" + sender.toBase58()); + System.out.println("recvAddr:" + recvAddr.toBase58()); + long amount = 100000; + + Transaction tx = dnaSdk.nativevm().gas().makeTransfer(sender.toBase58(),recvAddr.toBase58(), amount,sender.toBase58(),30000,0); + + System.out.println(tx.json()); + dnaSdk.signTx(tx, new com.github.DNAProject.account.Account[][]{{acct0}}); + dnaSdk.addMultiSign(tx,2,new byte[][]{acct0.serializePublicKey(),acct1.serializePublicKey()},acct0); + dnaSdk.addMultiSign(tx,2,new byte[][]{acct0.serializePublicKey(),acct1.serializePublicKey()},acct0); + System.out.println(tx.hash().toHexString()); + + Object obj = dnaSdk.getConnect().sendRawTransactionPreExec(tx.toHexString()); + System.out.println(obj); + //dnaSdk.getConnect().sendRawTransaction(tx.toHexString()); + + } + if(false){ + Address sender = acct0.getAddressU160(); + Address recvAddr = Address.addressFromMultiPubKeys(2, acct1.serializePublicKey(), acct2.serializePublicKey()); + System.out.println("sender:" + sender.toBase58()); + System.out.println("recvAddr:" + recvAddr.toBase58()); + long amount = 100000; + Transaction tx = dnaSdk.nativevm().gas().makeTransfer(sender.toBase58(),recvAddr.toBase58(), amount,sender.toBase58(),30000,0); + dnaSdk.signTx(tx, new com.github.DNAProject.account.Account[][]{{acct0}}); + //getSmartCodeEvent per 3s, max 60s + Object object = dnaSdk.getConnect().waitResult(tx.hash().toString()); + System.out.println(object); + } + + if (false) { + //sender address From MultiPubKeys + Address multiAddr = Address.addressFromMultiPubKeys(2, acct1.serializePublicKey(), acct2.serializePublicKey()); + System.out.println("sender:" + multiAddr.toBase58()); + Address recvAddr = acct0.getAddressU160(); + System.out.println("recvAddr:" + recvAddr.toBase58()); + int amount = 8; + + Transaction tx = dnaSdk.nativevm().gas().makeTransfer(multiAddr.toBase58(),recvAddr.toBase58(), amount,multiAddr.toBase58(),30000,0); + System.out.println(tx.json()); + //dnaSdk.signTx(tx, new com.github.DNAProject.account.Account[][]{{acct1, acct2}}); + dnaSdk.addMultiSign(tx,2,new byte[][]{acct1.serializePublicKey(),acct2.serializePublicKey()},acct1); + dnaSdk.addMultiSign(tx,2,new byte[][]{acct1.serializePublicKey(),acct2.serializePublicKey()},acct2); + + System.out.println(tx.hash().toHexString()); + dnaSdk.getConnect().sendRawTransaction(tx.toHexString()); + + } + + if (false) { + //2 sender transfer to 1 reveiver + Address sender1 = acct0.getAddressU160(); + Address sender2 = Address.addressFromMultiPubKeys(2, acct1.serializePublicKey(), acct2.serializePublicKey()); + Address recvAddr = acct4.getAddressU160(); + System.out.println("sender1:" + sender1.toBase58()); + System.out.println("sender2:" + sender2.toBase58()); + System.out.println("recvAddr:" + recvAddr.toBase58()); + + int amount = 1; + int amount2 = 2; + State state1 = new State(sender1,recvAddr,amount); + State state2 = new State(sender2,recvAddr,amount2); + Transaction tx = dnaSdk.nativevm().gas().makeTransfer(new State[]{state1,state2},sender1.toBase58(),30000,0); + System.out.println(tx.json()); + dnaSdk.signTx(tx, new com.github.DNAProject.account.Account[][]{{acct0}}); + dnaSdk.addMultiSign(tx,2,new byte[][]{acct1.serializePublicKey(),acct2.serializePublicKey()},acct1); + dnaSdk.addMultiSign(tx,2,new byte[][]{acct1.serializePublicKey(),acct2.serializePublicKey()},acct2); + System.out.println(tx.hash().toHexString()); + dnaSdk.getConnect().sendRawTransaction(tx.toHexString()); + + } + if(false){ + //receiver tx from other, and add sign + Address sender = acct0.getAddressU160(); + Address recvAddr = Address.decodeBase58("TA5SgQXTeKWyN4GNfWGoXqioEQ4eCDFMqE"); + System.out.println("sender:" + sender.toBase58()); + System.out.println("recvAddr:" + recvAddr.toBase58()); + long amount = 1000; + + Transaction tx = dnaSdk.nativevm().gas().makeTransfer(sender.toBase58(),recvAddr.toBase58(), amount,sender.toBase58(),30000,0); + + //serialize tx data + String txHex = tx.toHexString(); + + //deserialize + InvokeCode txRx = (InvokeCode)Transaction.deserializeFrom(Helper.hexToBytes(txHex)); + System.out.println(Transfers.deserializeFrom(Contract.deserializeFrom(txRx.code).args).json()); + dnaSdk.addSign(txRx,acct0); + dnaSdk.addMultiSign(txRx,2,new byte[][]{acct1.serializePublicKey(),acct2.serializePublicKey()},acct1); + dnaSdk.addMultiSign(txRx,2,new byte[][]{acct1.serializePublicKey(),acct2.serializePublicKey()},acct2); + //send tx + //dnaSdk.getConnect().sendRawTransaction(tx.toHexString()); + + } + if(false){ + String sender = acct0.getAddressU160().toBase58(); + Transaction tx = dnaSdk.nativevm().gas().makeWithdrawGas(sender,sender,10,sender,30000,0); + dnaSdk.signTx(tx, new com.github.DNAProject.account.Account[][]{{acct0}}); + dnaSdk.getConnect().sendRawTransaction(tx.toHexString()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static DnaSdk getDnaSdk() throws Exception { + String ip = "http://127.0.0.1"; +// String ip = "http://54.222.182.88; +// String ip = "http://101.132.193.149"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRestful()); + return wm; + } +} diff --git a/src/main/java/example/wallet/AccountDemo.java b/src/main/java/example/wallet/AccountDemo.java new file mode 100644 index 0000000..3488fbf --- /dev/null +++ b/src/main/java/example/wallet/AccountDemo.java @@ -0,0 +1,106 @@ +package example.wallet; + +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.sdk.info.AccountInfo; +import com.github.DNAProject.sdk.wallet.Account; + +import java.util.Base64; + +public class AccountDemo { + public static void main(String[] args) { + + try { + DnaSdk dnaSdk = getDnaSdk(); + com.github.DNAProject.account.Account account = dnaSdk.getWalletMgr().getAccount("AHX1wzvdw9Yipk7E9MuLY4GGX4Ym9tHeDe","111111"); + + if(false){ + dnaSdk.nativevm().gas().withdrawGas(account,account.getAddressU160().toBase58(),53620575000000000L,account,20000,0); + Thread.sleep(6000); + System.out.println(dnaSdk.getConnect().getBalance(account.getAddressU160().toBase58())); + return; + } + + if(true){ + System.out.println(dnaSdk.getConnect().getBalance("AHX1wzvdw9Yipk7E9MuLY4GGX4Ym9tHeDe")); + + dnaSdk.nativevm().gas().sendTransfer(account,"APrfMuKrAQB5sSb5GF8tx96ickZQJjCvwG",10000,account,20000,0); + Thread.sleep(6000); + System.out.println(dnaSdk.nativevm().gas().unboundGas(account.getAddressU160().toBase58())); + + return; + } + byte[] saltt = Base64.getDecoder().decode("0X3NC1UHQGltHc4ikzgzmA=="); + String prikeyg = com.github.DNAProject.account.Account.getGcmDecodedPrivateKey("7a1ccOWFQUGl0HQmc+PSLeKMwbVZ45/YDHTH/+um4O1z/YAWuv+vsr9zusvYXWbj", "1","ANH5bHrrt111XwNEnuPZj6u95Dd6u7G4D6",saltt,16384,dnaSdk.defaultSignScheme); + com.github.DNAProject.account.Account a = new com.github.DNAProject.account.Account(Helper.hexToBytes(prikeyg),dnaSdk.defaultSignScheme); + System.out.println(Helper.toHexString(a.serializePrivateKey())); + System.out.println(a.getAddressU160().toBase58()); + //com.github.DNAProject.account.Account b = new com.github.DNAProject.account.Account(false,a.serializePublicKey()); + + //System.out.println(Helper.toHexString(b.serializePublicKey())); + System.out.println( a.exportGcmEncryptedPrikey("1",saltt,16384)); + // dnaSdk.getWalletMgr().createAccount("password"); +// dnaSdk.getWalletMgr().writeWallet(); + //dnaSdk.getWalletMgr().getAccount("AUxEWKBM7zaU8iPSdymNSaZt7Dt9yB1KU6","1", Base64.getDecoder().decode("q6FCsP3XKxaeZaj15QZRqA==")); + // dnaSdk.getWalletMgr().getAccount("AHvSop5MbUX6pnqbXnFC5t3yjqVV5DiL7w","password", Base64.getDecoder().decode("ylsxIy8xq0uh4KjjbhxVLw==")); + // dnaSdk.getWalletMgr().getAccount("ANRoMGmxSLtWyzcDcnfCVnJw3FXdNuC9Vq","passwordtest", Base64.getDecoder().decode("ACm4B8Jr1oBPu++e7YIHow==")); + System.exit(0); + if(true){ + dnaSdk.getWalletMgr().createAccount("1"); + System.exit(0); + } + + byte[] salt0 = Base64.getDecoder().decode("+AX/Aa8VXp0h74PZySZ9RA=="); + String key0 = "+TDw5opWl5HfGEWUpxblVa5BqVKF2962DoCwi1GYidwWMKvOj7mqaUVx3k/utGLx"; + System.out.println(Helper.toHexString(salt0)+" "+salt0.length); + System.out.println(Helper.toHexString(Base64.getDecoder().decode(key0))); + String prikey0 = com.github.DNAProject.account.Account.getGcmDecodedPrivateKey(key0,"1","APrfMuKrAQB5sSb5GF8tx96ickZQJjCvwG", salt0,16384,dnaSdk.defaultSignScheme); + com.github.DNAProject.account.Account acct11 = new com.github.DNAProject.account.Account(Helper.hexToBytes(prikey0), dnaSdk.defaultSignScheme); + System.out.println(acct11.getAddressU160().toBase58()); + // System.exit(0); + if (false){ + AccountInfo info0 = dnaSdk.getWalletMgr().createAccountInfo("passwordtest"); + AccountInfo info = dnaSdk.getWalletMgr().createAccountInfoFromPriKey("passwordtest","e467a2a9c9f56b012c71cf2270df42843a9d7ff181934068b4a62bcdd570e8be"); + System.out.println(info.addressBase58); + Account accountInfo = dnaSdk.getWalletMgr().importAccount("3JZLD/X45qSFjmRRvRVhcEjKgCJQDPWOsjx2dcTEj58=", "passwordtest",info.addressBase58,new byte[]{}); + + com.github.DNAProject.account.Account acct0 = dnaSdk.getWalletMgr().getAccount(info.addressBase58, "passwordtest",new byte[]{}); + } + System.out.println(); + if(true){ + + byte[] salt = salt0; +// salt = ECC.generateKey(16); + com.github.DNAProject.account.Account acct = new com.github.DNAProject.account.Account(Helper.hexToBytes("a1a38ccff49fa6476e737d66ef9f18c7507b50eb4804ed8e077744a4a2a74bb6"),dnaSdk.defaultSignScheme); + String key = acct.exportGcmEncryptedPrikey("1",salt,16384); + System.out.println(key); + System.out.println(acct.getAddressU160().toBase58()); + String prikey = com.github.DNAProject.account.Account.getGcmDecodedPrivateKey(key, "1",acct.getAddressU160().toBase58(),salt,16384,dnaSdk.defaultSignScheme); + System.out.println(prikey); + } + + System.exit(0); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static DnaSdk getDnaSdk() throws Exception { + + String ip = "http://127.0.0.1"; +// String ip = "http://54.222.182.88; +// String ip = "http://101.132.193.149"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRestful()); + + wm.openWalletFile("wallet2.dat"); + + return wm; + } +} diff --git a/src/main/java/example/wallet/QrCodeDemo.java b/src/main/java/example/wallet/QrCodeDemo.java new file mode 100644 index 0000000..229ade3 --- /dev/null +++ b/src/main/java/example/wallet/QrCodeDemo.java @@ -0,0 +1,19 @@ +package example.wallet; + +import com.github.DNAProject.common.WalletQR; + +/** + * + * + */ +public class QrCodeDemo { + public static void main(String[] args) { + String keystore = "{\"address\":\"AG9W6c7nNhaiywcyVPgW9hQKvUYQr5iLvk\",\"key\":\"+UADcReBcLq0pn/2Grmz+UJsKl3ryop8pgRVHbQVgTBfT0lho06Svh4eQLSmC93j\",\"parameters\":{\"curve\":\"secp256r1\"},\"label\":\"11111\",\"scrypt\":{\"dkLen\":64,\"n\":4096,\"p\":8,\"r\":8},\"salt\":\"IfxFV0Fer5LknIyCLP2P2w==\",\"type\":\"I\",\"algorithm\":\"ECDSA\"}"; + try { + String prikey = WalletQR.getPriKeyFromQrCode(keystore,"111111"); + System.out.println(prikey); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/example/wallet/WalletDemo.java b/src/main/java/example/wallet/WalletDemo.java new file mode 100644 index 0000000..7dccd37 --- /dev/null +++ b/src/main/java/example/wallet/WalletDemo.java @@ -0,0 +1,69 @@ +package example.wallet; + +import com.github.DNAProject.DnaSdk; + +public class WalletDemo { + public static void main(String[] args) { + try { + DnaSdk dnaSdk = getDnaSdk(); + if (dnaSdk.getWalletMgr().getWallet().getAccounts().size() > 0) { + dnaSdk.getWalletMgr().getWallet().clearAccount(); + dnaSdk.getWalletMgr().getWallet().clearIdentity(); + dnaSdk.getWalletMgr().writeWallet(); + } + dnaSdk.getWalletMgr().createAccounts(1, "passwordtest"); + dnaSdk.getWalletMgr().writeWallet(); + + System.out.println("init size: "+dnaSdk.getWalletMgr().getWallet().getAccounts().size()+" " +dnaSdk.getWalletMgr().getWalletFile().getAccounts().size()); + System.out.println(dnaSdk.getWalletMgr().getWallet().toString()); + System.out.println(dnaSdk.getWalletMgr().getWalletFile().toString()); + + System.out.println(); + dnaSdk.getWalletMgr().getWallet().removeAccount(dnaSdk.getWalletMgr().getWallet().getAccounts().get(0).address); + dnaSdk.getWalletMgr().getWallet().setVersion("2.0"); + System.out.println("removeAccount size: "+dnaSdk.getWalletMgr().getWallet().getAccounts().size()+" " +dnaSdk.getWalletMgr().getWalletFile().getAccounts().size()); + System.out.println(dnaSdk.getWalletMgr().getWallet().toString()); + System.out.println(dnaSdk.getWalletMgr().getWalletFile().toString()); + + System.out.println(); + dnaSdk.getWalletMgr().resetWallet(); + System.out.println("resetWallet size: "+dnaSdk.getWalletMgr().getWallet().getAccounts().size()+" " +dnaSdk.getWalletMgr().getWalletFile().getAccounts().size()); + System.out.println(dnaSdk.getWalletMgr().getWallet().toString()); + System.out.println(dnaSdk.getWalletMgr().getWalletFile().toString()); + + + System.out.println(); + dnaSdk.getWalletMgr().getWallet().removeAccount(dnaSdk.getWalletMgr().getWallet().getAccounts().get(0).address); + dnaSdk.getWalletMgr().getWallet().setVersion("2.0"); + System.out.println("removeAccount size: "+dnaSdk.getWalletMgr().getWallet().getAccounts().size()+" " +dnaSdk.getWalletMgr().getWalletFile().getAccounts().size()); + System.out.println(dnaSdk.getWalletMgr().getWallet().toString()); + System.out.println(dnaSdk.getWalletMgr().getWalletFile().toString()); + + //write wallet + dnaSdk.getWalletMgr().writeWallet(); + System.out.println(); + System.out.println("writeWallet size: "+dnaSdk.getWalletMgr().getWallet().getAccounts().size()+" " +dnaSdk.getWalletMgr().getWalletFile().getAccounts().size()); + System.out.println(dnaSdk.getWalletMgr().getWallet().toString()); + System.out.println(dnaSdk.getWalletMgr().getWalletFile().toString()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static DnaSdk getDnaSdk() throws Exception { + + String ip = "http://127.0.0.1"; + String restUrl = ip + ":" + "20334"; + String rpcUrl = ip + ":" + "20336"; + String wsUrl = ip + ":" + "20335"; + + DnaSdk wm = DnaSdk.getInstance(); + wm.setRpc(rpcUrl); + wm.setRestful(restUrl); + wm.setDefaultConnect(wm.getRestful()); + + wm.openWalletFile("WalletDemo.json"); + + return wm; + } +} From 701386c04b955404df8534420007b1167f738ca0 Mon Sep 17 00:00:00 2001 From: xizho10 Date: Mon, 16 Dec 2019 18:26:09 +0800 Subject: [PATCH 02/18] add unit test --- .../com/github/DNAProject/DnaSdkTest.java | 35 +++ .../DNAProject/account/AccountTest.java | 43 ++++ .../github/DNAProject/common/AddressTest.java | 63 +++++ .../github/DNAProject/common/HelperTest.java | 56 +++++ .../github/DNAProject/core/VmTypeTest.java | 21 ++ .../DNAProject/core/asset/ContractTest.java | 38 +++ .../DNAProject/core/asset/StateTest.java | 27 +++ .../DNAProject/core/block/BlockTest.java | 43 ++++ .../core/payload/DeployCodeTest.java | 36 +++ .../core/payload/InvokeCodeTest.java | 29 +++ .../core/scripts/ScriptBuilderTest.java | 40 ++++ .../core/scripts/WasmScriptBuilderTest.java | 222 ++++++++++++++++++ .../core/transaction/TransactionTest.java | 38 +++ .../DNAProject/crypto/HdPrivateKeyTest.java | 102 ++++++++ .../DNAProject/crypto/HdPublicKeyTest.java | 116 +++++++++ .../DNAProject/crypto/MnemonicTest.java | 18 ++ .../DNAProject/io/BinaryReaderTest.java | 62 +++++ .../DNAProject/io/BinaryWriterTest.java | 59 +++++ .../DNAProject/merkle/MerkleVerifierTest.java | 108 +++++++++ .../sdk/manager/ConnectMgrTest.java | 155 ++++++++++++ .../sdk/manager/GasAssetTxTest.java | 111 +++++++++ .../DNAProject/sdk/manager/WalletMgrTest.java | 122 ++++++++++ .../DNAProject/sdk/wallet/WalletTest.java | 66 ++++++ .../DNAProject/smartcontract/NeoVmTest.java | 106 +++++++++ .../DNAProject/smartcontract/VmTest.java | 26 ++ .../DNAProject/smartcontract/WasmVmTest.java | 123 ++++++++++ .../smartcontract/nativevm/AuthTest.java | 167 +++++++++++++ .../smartcontract/nativevm/GasTest.java | 78 ++++++ .../nativevm/GovernanceTest.java | 26 ++ .../nativevm/NativeDnaIdTxTest.java | 205 ++++++++++++++++ 30 files changed, 2341 insertions(+) create mode 100644 src/test/java/com/github/DNAProject/DnaSdkTest.java create mode 100644 src/test/java/com/github/DNAProject/account/AccountTest.java create mode 100644 src/test/java/com/github/DNAProject/common/AddressTest.java create mode 100644 src/test/java/com/github/DNAProject/common/HelperTest.java create mode 100644 src/test/java/com/github/DNAProject/core/VmTypeTest.java create mode 100644 src/test/java/com/github/DNAProject/core/asset/ContractTest.java create mode 100644 src/test/java/com/github/DNAProject/core/asset/StateTest.java create mode 100644 src/test/java/com/github/DNAProject/core/block/BlockTest.java create mode 100644 src/test/java/com/github/DNAProject/core/payload/DeployCodeTest.java create mode 100644 src/test/java/com/github/DNAProject/core/payload/InvokeCodeTest.java create mode 100644 src/test/java/com/github/DNAProject/core/scripts/ScriptBuilderTest.java create mode 100644 src/test/java/com/github/DNAProject/core/scripts/WasmScriptBuilderTest.java create mode 100644 src/test/java/com/github/DNAProject/core/transaction/TransactionTest.java create mode 100644 src/test/java/com/github/DNAProject/crypto/HdPrivateKeyTest.java create mode 100644 src/test/java/com/github/DNAProject/crypto/HdPublicKeyTest.java create mode 100644 src/test/java/com/github/DNAProject/crypto/MnemonicTest.java create mode 100644 src/test/java/com/github/DNAProject/io/BinaryReaderTest.java create mode 100644 src/test/java/com/github/DNAProject/io/BinaryWriterTest.java create mode 100644 src/test/java/com/github/DNAProject/merkle/MerkleVerifierTest.java create mode 100644 src/test/java/com/github/DNAProject/sdk/manager/ConnectMgrTest.java create mode 100644 src/test/java/com/github/DNAProject/sdk/manager/GasAssetTxTest.java create mode 100644 src/test/java/com/github/DNAProject/sdk/manager/WalletMgrTest.java create mode 100644 src/test/java/com/github/DNAProject/sdk/wallet/WalletTest.java create mode 100644 src/test/java/com/github/DNAProject/smartcontract/NeoVmTest.java create mode 100644 src/test/java/com/github/DNAProject/smartcontract/VmTest.java create mode 100644 src/test/java/com/github/DNAProject/smartcontract/WasmVmTest.java create mode 100644 src/test/java/com/github/DNAProject/smartcontract/nativevm/AuthTest.java create mode 100644 src/test/java/com/github/DNAProject/smartcontract/nativevm/GasTest.java create mode 100644 src/test/java/com/github/DNAProject/smartcontract/nativevm/GovernanceTest.java create mode 100644 src/test/java/com/github/DNAProject/smartcontract/nativevm/NativeDnaIdTxTest.java diff --git a/src/test/java/com/github/DNAProject/DnaSdkTest.java b/src/test/java/com/github/DNAProject/DnaSdkTest.java new file mode 100644 index 0000000..879047f --- /dev/null +++ b/src/test/java/com/github/DNAProject/DnaSdkTest.java @@ -0,0 +1,35 @@ +package com.github.DNAProject; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class DnaSdkTest { + private DnaSdk dnaSdk; +// public static String URL = "http://139.219.129.26:20334"; + public static String URL = "http://127.0.0.1:20334"; + + public static String PRIVATEKEY3 = "c19f16785b8f3543bbaf5e1dbb5d398dfa6c85aaad54fc9d71203ce83e505c07";//有钱的账号的私钥 + public static String PRIVATEKEY2 = "f1442d5e7f4e2061ff9a6884d6d05212e2aa0f6a6284f0a28ae82a29cdb3d656";//有钱的账号的私钥 + public static String PRIVATEKEY = "75de8489fcb2dcaf2ef3cd607feffde18789de7da129b5e97c81e001793cb7cf"; + + public static String PASSWORD = "111111";//有钱账号的密码 + + @Before + public void setUp() throws Exception { + dnaSdk = DnaSdk.getInstance(); + } + + @After + public void tearDown() throws Exception { + } + + @Test + public void getInstance() { + DnaSdk dnaSdk = DnaSdk.getInstance(); + assertNotNull(dnaSdk); + assertSame(dnaSdk,this.dnaSdk); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/DNAProject/account/AccountTest.java b/src/test/java/com/github/DNAProject/account/AccountTest.java new file mode 100644 index 0000000..a48b55b --- /dev/null +++ b/src/test/java/com/github/DNAProject/account/AccountTest.java @@ -0,0 +1,43 @@ +package com.github.DNAProject.account; + +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.crypto.SignatureScheme; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class AccountTest { + + + @Test + public void generateSignature() throws Exception { + Account account = new Account(SignatureScheme.SHA256WITHECDSA); + byte[] signature = account.generateSignature("hello".getBytes(),SignatureScheme.SHA256WITHECDSA,null); + boolean b = account.verifySignature("hello".getBytes(),signature); + assertTrue(b); + } + + @Test + public void serializePublicKey() throws Exception { + Account account = new Account(SignatureScheme.SHA256WITHECDSA); + byte[] publickey = account.serializePublicKey(); + assertNotNull(publickey); + } + + @Test + public void serializePrivateKey() throws Exception { + Account account = new Account(SignatureScheme.SHA256WITHECDSA); + byte[] privateKey = account.serializePrivateKey(); + assertNotNull(privateKey); + } + + @Test + public void compareTo() throws Exception { + Account account1 = new Account(SignatureScheme.SHA256WITHECDSA); + Account account2 = new Account(SignatureScheme.SHA256WITHECDSA); + int res = account1.compareTo(account2); + assertNotNull(res); + } + + +} \ No newline at end of file diff --git a/src/test/java/com/github/DNAProject/common/AddressTest.java b/src/test/java/com/github/DNAProject/common/AddressTest.java new file mode 100644 index 0000000..0e50139 --- /dev/null +++ b/src/test/java/com/github/DNAProject/common/AddressTest.java @@ -0,0 +1,63 @@ +package com.github.DNAProject.common; + +import com.github.DNAProject.account.Account; +import com.github.DNAProject.crypto.SignatureScheme; +import com.github.DNAProject.sdk.exception.SDKException; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class AddressTest { + Account account; + @Before + public void setUp() throws Exception { + account = new Account(SignatureScheme.SHA256WITHECDSA); + } + + @Test + public void compareTo() throws Exception { + Account account2 = new Account(SignatureScheme.SHA256WITHECDSA); + int res = account2.getAddressU160().compareTo(account.getAddressU160()); + assertNotNull(res); + } + + @Test + public void parse() { +// Address address = Address.parse(account.getAddressU160().toHexString()); +// assertEquals(address,account.getAddressU160()); + } + + @Test + public void addressFromPubKey() { + Address address = Address.addressFromPubKey(account.serializePublicKey()); + assertEquals(address,account.getAddressU160()); + } + + @Test + public void addressFromPubKey1() { + Address address = Address.addressFromPubKey(Helper.toHexString(account.serializePublicKey())); + assertEquals(address,account.getAddressU160()); + } + + @Test + public void addressFromMultiPubKeys() throws Exception { + Account account2 = new Account(SignatureScheme.SHA256WITHECDSA); + Address res = Address.addressFromMultiPubKeys(2,account.serializePublicKey(),account2.serializePublicKey()); + assertNotNull(res); + } + + @Test + public void toBase58() throws SDKException { + String res = account.getAddressU160().toBase58(); + Address addr = Address.decodeBase58(res); + assertEquals(addr,account.getAddressU160()); + } + + @Test + public void toScriptHash() { + Address addr = Address.toScriptHash(Helper.hexToBytes("12a67b")); + assertNotNull(addr); + } + +} \ No newline at end of file diff --git a/src/test/java/com/github/DNAProject/common/HelperTest.java b/src/test/java/com/github/DNAProject/common/HelperTest.java new file mode 100644 index 0000000..5a3655c --- /dev/null +++ b/src/test/java/com/github/DNAProject/common/HelperTest.java @@ -0,0 +1,56 @@ +package com.github.DNAProject.common; + +import org.junit.Test; + +import java.math.BigInteger; + +import static com.github.DNAProject.common.Helper.BigIntFromNeoBytes; +import static com.github.DNAProject.common.Helper.BigIntToNeoBytes; +import static org.junit.Assert.*; + +public class HelperTest { + + @Test + public void bigInt2Bytes() { + assertArrayEquals(new byte[] {-85, -86, -86, -86, -86, -86, -85, -128}, BigIntToNeoBytes(new BigInteger("-9175052165852779861"))); + + assertArrayEquals(new byte[] {85, 85, 85, 85, 85, 85, 84, 127}, BigIntToNeoBytes(new BigInteger("9175052165852779861"))); + + assertArrayEquals(new byte[] {85, 85, 85, 85, 85, 85, 84, -128}, BigIntToNeoBytes(new BigInteger("-9199634313818843819"))); + + assertArrayEquals(new byte[] {-85, -86, -86, -86, -86, -86, -85, 127}, BigIntToNeoBytes(new BigInteger("9199634313818843819"))); + + assertArrayEquals(new byte[] {16, 31, -128}, BigIntToNeoBytes(new BigInteger("-8380656"))); + + assertArrayEquals(new byte[] {-16, -32, 127}, BigIntToNeoBytes(new BigInteger("8380656"))); + + assertArrayEquals(new byte[] {16, 31, 127, -1}, BigIntToNeoBytes(new BigInteger("-8446192"))); + + assertArrayEquals(new byte[] {-16, -32, -128, 0}, BigIntToNeoBytes(new BigInteger("8446192"))); + + assertArrayEquals(new byte[0], BigIntToNeoBytes(new BigInteger("-0"))); + + assertArrayEquals(new byte[0], BigIntToNeoBytes(new BigInteger("0"))); + } + + @Test + public void bytes2BigInt() { + assertEquals(BigIntFromNeoBytes(new byte[] {-85, -86, -86, -86, -86, -86, -85, -128}), new BigInteger("-9175052165852779861")); + + assertEquals(BigIntFromNeoBytes(new byte[] {85, 85, 85, 85, 85, 85, 84, 127}), new BigInteger("9175052165852779861")); + + assertEquals(BigIntFromNeoBytes(new byte[] {85, 85, 85, 85, 85, 85, 84, -128}), new BigInteger("-9199634313818843819")); + + assertEquals(BigIntFromNeoBytes(new byte[] {-85, -86, -86, -86, -86, -86, -85, 127}), new BigInteger("9199634313818843819")); + + assertEquals(BigIntFromNeoBytes(new byte[] {16, 31, -128}), new BigInteger("-8380656")); + + assertEquals(BigIntFromNeoBytes(new byte[] {-16, -32, 127}), new BigInteger("8380656")); + + assertEquals(BigIntFromNeoBytes(new byte[] {16, 31, 127, -1}), new BigInteger("-8446192")); + + assertEquals(BigIntFromNeoBytes(new byte[] {-16, -32, -128, 0}), new BigInteger("8446192")); + + assertEquals(BigIntFromNeoBytes(new byte[0]), new BigInteger("0")); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/DNAProject/core/VmTypeTest.java b/src/test/java/com/github/DNAProject/core/VmTypeTest.java new file mode 100644 index 0000000..2005de0 --- /dev/null +++ b/src/test/java/com/github/DNAProject/core/VmTypeTest.java @@ -0,0 +1,21 @@ + +package com.github.DNAProject.core; + +import org.junit.Assert; +import org.junit.Test; + +public class VmTypeTest { + + @Test + public void valueOf() throws IllegalArgumentException { + Assert.assertEquals(VmType.NEOVM, VmType.valueOf((byte) 0x01)); + Assert.assertEquals(VmType.WASMVM, VmType.valueOf((byte) 0x03)); + } + + @Test + public void value() { + Assert.assertEquals(1, VmType.NEOVM.value()); + Assert.assertEquals(3, VmType.WASMVM.value()); + } + +} diff --git a/src/test/java/com/github/DNAProject/core/asset/ContractTest.java b/src/test/java/com/github/DNAProject/core/asset/ContractTest.java new file mode 100644 index 0000000..d95e377 --- /dev/null +++ b/src/test/java/com/github/DNAProject/core/asset/ContractTest.java @@ -0,0 +1,38 @@ +package com.github.DNAProject.core.asset; + +import com.github.DNAProject.common.Address; +import com.github.DNAProject.sdk.exception.SDKException; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; + +import static org.junit.Assert.*; + +public class ContractTest { + + Address address; + + @Before + public void setUp() throws SDKException { +// address = Address.decodeBase58("TA6nRD9DqGkE8xRJaB37bW2KQEz59ovKRH"); + } + + @Test + public void serialize() throws IOException { +// Contract contract = new Contract((byte)1,address,"test","t".getBytes()); +// ByteArrayOutputStream bs = new ByteArrayOutputStream(); +// BinaryWriter binaryWriter = new BinaryWriter(bs); +// contract.serialize(binaryWriter); +// binaryWriter.flush(); +// byte[] seril = bs.toByteArray(); +// assertNotNull(seril); +// +// Contract contract1 = new Contract((byte)1,address,"test2","t2".getBytes()); +// ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(seril); +// BinaryReader binaryReader = new BinaryReader(byteArrayInputStream); +// contract1.deserialize(binaryReader); +// assertNotNull(binaryReader); + + } +} \ No newline at end of file diff --git a/src/test/java/com/github/DNAProject/core/asset/StateTest.java b/src/test/java/com/github/DNAProject/core/asset/StateTest.java new file mode 100644 index 0000000..54e18ca --- /dev/null +++ b/src/test/java/com/github/DNAProject/core/asset/StateTest.java @@ -0,0 +1,27 @@ +package com.github.DNAProject.core.asset; + +import com.github.DNAProject.sdk.exception.SDKException; +import org.junit.Test; + +import java.io.IOException; + +import static org.junit.Assert.*; + +public class StateTest { + @Test + public void deserialize() throws SDKException, IOException { +// State state = new State(Address.decodeBase58("TRj9g9kvq8pL3L8M1F2KpsqWQHiC7u4xLP"),Address.decodeBase58("TRj9g9kvq8pL3L8M1F2KpsqWQHiC7u4xLP"),1000L); +// ByteArrayOutputStream bais = new ByteArrayOutputStream(); +// BinaryWriter bw = new BinaryWriter(bais); +// Transfers transfers = new Transfers(new State[]{state}); +// System.out.println(Helper.toHexString(transfers.toArray())); +// +// +// state.serialize(bw); +// +// State state1 = new State(); +// ByteArrayInputStream baos = new ByteArrayInputStream(bais.toByteArray()); +// BinaryReader br = new BinaryReader(baos); +// state1.deserialize(br); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/DNAProject/core/block/BlockTest.java b/src/test/java/com/github/DNAProject/core/block/BlockTest.java new file mode 100644 index 0000000..454ac54 --- /dev/null +++ b/src/test/java/com/github/DNAProject/core/block/BlockTest.java @@ -0,0 +1,43 @@ +package com.github.DNAProject.core.block; + +import com.github.DNAProject.sdk.exception.SDKException; +import org.junit.Test; + +import java.io.IOException; + +import static org.junit.Assert.*; + +public class BlockTest { + + @Test + public void deserialize() { + } + + + @Test + public void serialize() throws IOException, SDKException { +// ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); +// BinaryWriter binaryWriter = new BinaryWriter(byteArrayOutputStream); +// Block block = new Block(); +// block.version = 1; +// block.height = 1; +// block.consensusPayload = "test".getBytes(); +// block.prevBlockHash = new UInt256(Helper.hexToBytes("1d46ec977e10d297a53d77dfcb5fe5904734f2c62e156d0e893d1b7c050524a2")); +// block.blockRoot = new UInt256(Helper.hexToBytes("37614956f598e0b3c4c3105d9e94c8cf4aa0ac6adce4eff4189dd348d1f3dac2")); +// block.consensusData = 111; +// block.nextBookkeeper = Address.decodeBase58("TAERF2G54oJxN4U52CVns7kTYAMFxAFsGg"); +// block.bookkeepers = new byte[][]{"test".getBytes()}; +// block.transactionsRoot = new UInt256(Helper.hexToBytes("b5b8cb62d5c1ccea510ce1c268259fab33069c343532c804743bd4c6029dbd35")); +// block.sigData = new String[]{"123ab2"}; +// block.transactions = new Transaction[]{}; +// block.serialize(binaryWriter); +// binaryWriter.flush(); +// byte[] seril = byteArrayOutputStream.toByteArray(); +// Block block1 = new Block(); +// +// ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(seril); +// block1.deserializeUnsigned(new BinaryReader(byteArrayInputStream)); +// assertEquals(block,block1); + } + +} \ No newline at end of file diff --git a/src/test/java/com/github/DNAProject/core/payload/DeployCodeTest.java b/src/test/java/com/github/DNAProject/core/payload/DeployCodeTest.java new file mode 100644 index 0000000..ffc134f --- /dev/null +++ b/src/test/java/com/github/DNAProject/core/payload/DeployCodeTest.java @@ -0,0 +1,36 @@ +package com.github.DNAProject.core.payload; + +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import static org.junit.Assert.*; + +public class DeployCodeTest { + + @Test + public void serializeExclusiveData() throws IOException { + DeployCode deployCode = new DeployCode(); + deployCode.version = "1"; + deployCode.author = "sss"; + deployCode.name = "sss"; + deployCode.code = "test".getBytes(); + deployCode.description = "test"; + deployCode.email = "test"; + deployCode.needStorage = true; + + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + BinaryWriter binaryWriter = new BinaryWriter(byteArrayOutputStream); + deployCode.serializeExclusiveData(binaryWriter); + + byte[] selr = byteArrayOutputStream.toByteArray(); + + DeployCode deployCode1 = new DeployCode(); + deployCode1.deserializeExclusiveData(new BinaryReader(new ByteArrayInputStream(selr))); + assertEquals(deployCode.version,deployCode1.version); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/DNAProject/core/payload/InvokeCodeTest.java b/src/test/java/com/github/DNAProject/core/payload/InvokeCodeTest.java new file mode 100644 index 0000000..5ef6aea --- /dev/null +++ b/src/test/java/com/github/DNAProject/core/payload/InvokeCodeTest.java @@ -0,0 +1,29 @@ +package com.github.DNAProject.core.payload; + +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import static org.junit.Assert.*; + +public class InvokeCodeTest { + + @Test + public void serializeExclusiveData() throws IOException { + InvokeCode invokeCode = new InvokeCode(); + invokeCode.code = "test".getBytes(); + + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + BinaryWriter binaryWriter = new BinaryWriter(byteArrayOutputStream); + invokeCode.serializeExclusiveData(binaryWriter); + + assertNotNull(byteArrayOutputStream); + + InvokeCode invokeCode1 = new InvokeCode(); + invokeCode1.deserializeExclusiveData(new BinaryReader(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()))); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/DNAProject/core/scripts/ScriptBuilderTest.java b/src/test/java/com/github/DNAProject/core/scripts/ScriptBuilderTest.java new file mode 100644 index 0000000..161cbe4 --- /dev/null +++ b/src/test/java/com/github/DNAProject/core/scripts/ScriptBuilderTest.java @@ -0,0 +1,40 @@ +package com.github.DNAProject.core.scripts; + +import org.junit.Before; +import org.junit.Test; + +import java.math.BigInteger; + +import static org.junit.Assert.*; + +public class ScriptBuilderTest { + + ScriptBuilder scriptBuilder; + + @Before + public void setUp(){ + scriptBuilder = new ScriptBuilder(); + } + + @Test + public void add() { + ScriptBuilder sb = scriptBuilder.add("test".getBytes()); + assertNotNull(sb); + + } + + @Test + public void push() { + ScriptBuilder sb = scriptBuilder.emitPushBool(true); + assertNotNull(sb); + assertNotNull(scriptBuilder.emitPushByteArray("test".getBytes())); + assertNotNull(scriptBuilder.emitPushInteger(new BigInteger("11"))); + } + + + @Test + public void pushPack() { + assertNotNull(scriptBuilder.pushPack()); + + } +} \ No newline at end of file diff --git a/src/test/java/com/github/DNAProject/core/scripts/WasmScriptBuilderTest.java b/src/test/java/com/github/DNAProject/core/scripts/WasmScriptBuilderTest.java new file mode 100644 index 0000000..d60c70f --- /dev/null +++ b/src/test/java/com/github/DNAProject/core/scripts/WasmScriptBuilderTest.java @@ -0,0 +1,222 @@ +package com.github.DNAProject.core.scripts; + +import com.github.DNAProject.common.Address; +import com.github.DNAProject.sdk.exception.SDKException; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.List; + +public class WasmScriptBuilderTest { + + private WasmScriptBuilder builder; + + @Before + public void setUp() { + builder = new WasmScriptBuilder(); + } + + @Test + public void pushBool() { + List booleanList = Arrays.asList(true, false); + List targetList = Arrays.asList("01", "00"); + for (int i = 0; i < booleanList.size(); i++) { + builder.push(booleanList.get(i)); + Assert.assertEquals(targetList.get(i), builder.toHexString()); + builder.reset(); + } + } + + @Test + public void pushInt() { + List intList = Arrays.asList( + -2147483648, + -32768, + 0, + 1, + 2, + 32768, + 2147483647 + ); + List targetResult = Arrays.asList( + "00000080ffffffffffffffffffffffff", + "0080ffffffffffffffffffffffffffff", + "00000000000000000000000000000000", + "01000000000000000000000000000000", + "02000000000000000000000000000000", + "00800000000000000000000000000000", + "ffffff7f000000000000000000000000" + ); + for (int i = 0; i < intList.size(); i++) { + builder.push(intList.get(i)); + Assert.assertEquals(targetResult.get(i), builder.toHexString()); + builder.reset(); + } + } + + @Test + public void pushByteArray() { + List stringList = Arrays.asList( + "Hello, world!".getBytes(), + "DNA".getBytes(), + "!@#$%^&*()_+1234567890-=".getBytes(), + "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".getBytes() + ); + List targetResult = Arrays.asList( + "0d48656c6c6f2c20776f726c6421", + "03444e41", + "1821402324255e262a28295f2b313233343536373839302d3d", + "3e313233343536373839304142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a" + ); + for (int i = 0; i < stringList.size(); i++) { + builder.push(stringList.get(i)); + Assert.assertEquals(targetResult.get(i), builder.toHexString()); + builder.reset(); + } + } + + @Test + public void pushLong() { + List longList = Arrays.asList( + -9223372036854775808L, + -267L, + -2L, + 0L, + 1L, + 2L, + 9007199254740993L, + 9223372036854775807L + ); + List targetResult = Arrays.asList( + "0000000000000080ffffffffffffffff", + "f5feffffffffffffffffffffffffffff", + "feffffffffffffffffffffffffffffff", + "00000000000000000000000000000000", + "01000000000000000000000000000000", + "02000000000000000000000000000000", + "01000000000020000000000000000000", + "ffffffffffffff7f0000000000000000" + ); + for (int i = 0; i < longList.size(); i++) { + builder.push(longList.get(i)); + Assert.assertEquals(targetResult.get(i), builder.toHexString()); + builder.reset(); + } + } + + @Test + public void pushBigInteger() { + List bigIntegerList = Arrays.asList( + new BigInteger("2").pow(127).subtract(new BigInteger("1")), + new BigInteger("2").pow(127).negate(), + new BigInteger("267").negate(), + new BigInteger("2").negate(), + new BigInteger("0"), + new BigInteger("1"), + new BigInteger("2") + ); + List targetResult = Arrays.asList( + "ffffffffffffffffffffffffffffff7f", + "00000000000000000000000000000080", + "f5feffffffffffffffffffffffffffff", + "feffffffffffffffffffffffffffffff", + "00000000000000000000000000000000", + "01000000000000000000000000000000", + "02000000000000000000000000000000" + ); + for (int i = 0; i < bigIntegerList.size(); i++) { + builder.push(bigIntegerList.get(i)); + Assert.assertEquals(targetResult.get(i), builder.toHexString()); + builder.reset(); + } + } + + @Test + public void pushStr() { + List stringList = Arrays.asList( + "Hello, world!", + "DNA", + "!@#$%^&*()_+1234567890-=", + "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + ); + List targetResult = Arrays.asList( + "0d48656c6c6f2c20776f726c6421", + "03444e41", + "1821402324255e262a28295f2b313233343536373839302d3d", + "3e313233343536373839304142434445464748494a4b4c4d4e4f505152535455565758595a6162636465666768696a6b6c6d6e6f707172737475767778797a" + ); + for (int i = 0; i < stringList.size(); i++) { + builder.push(stringList.get(i)); + Assert.assertEquals(targetResult.get(i), builder.toHexString()); + builder.reset(); + } + } + + @Test + public void pushAddress() throws SDKException { + List
addressList = Arrays.asList( + Address.decodeBase58("AS7MjVEicEsJ4zjEfm2LoKoYoFsmapD7rT"), + Address.decodeBase58("AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK"), + Address.decodeBase58("Ad4pjz2bqep4RhQrUAzMuZJkBC3qJ1tZuT"), + Address.decodeBase58("AK98G45DhmPXg4TFPG1KjftvkEaHbU8SHM") + ); + List targetResult = Arrays.asList( + "71609b2c2f7b9447b089ad1da31586f42ca9eb10", + "0000000000000000000000000000000000000007", + "e98f4998d837fcdd44a50561f7f32140c7c6c260", + "24ed4f965d3a5a76f5d0e87633c0b76941fc8827" + ); + for (int i = 0; i < addressList.size(); i++) { + builder.push(addressList.get(i)); + Assert.assertEquals(targetResult.get(i), builder.toHexString()); + builder.reset(); + } + } + + @Test + public void pushVarUInt() { + List varUIntList = Arrays.asList( + 0L, + 1L, + 254L, + 65536L, + 65537L, + 4294967295L, + 4294967296L, + 1152921504606846975L + ); + List targetResult = Arrays.asList( + "00", + "01", + "fdfe00", + "fe00000100", + "fe01000100", + "feffffffff", + "ff0000000001000000", + "ffffffffffffffff0f", + "ffffffffffffffffff", + "ffffffffffffffffffff", + "ffffffffffffffffffffffff" + ); + for (int i = 0; i < varUIntList.size(); i++) { + builder.pushVarUInt(varUIntList.get(i)); + Assert.assertEquals(targetResult.get(i), builder.toHexString()); + builder.reset(); + } + } + + @Test + public void pushWithoutLen() { + List lengthArray = Arrays.asList(1, 2, 4, 8, 16, 32, 64, 128, 256, 1024, 2048); + lengthArray.forEach(length -> { + byte[] val = new byte[length]; + Arrays.fill(val, (byte) 0xFF); + builder.pushWithoutLen(val); + Assert.assertEquals(length * 2, builder.toHexString().length()); + builder.reset(); + }); + } +} diff --git a/src/test/java/com/github/DNAProject/core/transaction/TransactionTest.java b/src/test/java/com/github/DNAProject/core/transaction/TransactionTest.java new file mode 100644 index 0000000..4c680d0 --- /dev/null +++ b/src/test/java/com/github/DNAProject/core/transaction/TransactionTest.java @@ -0,0 +1,38 @@ +package com.github.DNAProject.core.transaction; + +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.crypto.SignatureScheme; +import com.github.DNAProject.smartcontract.Vm; +import org.junit.Before; +import org.junit.Test; + +public class TransactionTest { + + DnaSdk dnaSdk; + Vm vm; + String gasContract = "0000000000000000000000000000000000000002"; + + @Before + public void setUp(){ + dnaSdk = DnaSdk.getInstance(); + vm = new Vm(dnaSdk); + } + + @Test + public void serialize() throws Exception { + Transaction tx = vm.buildNativeParams(Address.parse(gasContract),"init","1".getBytes(),null,0,0); + Account account = new Account(Helper.hexToBytes("0bc8c1f75a028672cd42c221bf81709dfc7abbbaf0d87cb6fdeaf9a20492c194"),SignatureScheme.SHA256WITHECDSA); + dnaSdk.signTx(tx,new Account[][]{{account}}); + + String t = tx.toHexString(); + System.out.println(t); + + Transaction tx2 = Transaction.deserializeFrom(Helper.hexToBytes(t)); + System.out.println(tx2.json()); + + + } +} \ No newline at end of file diff --git a/src/test/java/com/github/DNAProject/crypto/HdPrivateKeyTest.java b/src/test/java/com/github/DNAProject/crypto/HdPrivateKeyTest.java new file mode 100644 index 0000000..13fd7ee --- /dev/null +++ b/src/test/java/com/github/DNAProject/crypto/HdPrivateKeyTest.java @@ -0,0 +1,102 @@ + +package com.github.DNAProject.crypto; + +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.crypto.bip32.HdPrivateKey; +import com.github.DNAProject.crypto.bip32.HdPublicKey; +import com.github.DNAProject.sdk.exception.SDKException; +import org.junit.Assert; +import org.junit.Test; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; + + +public class HdPrivateKeyTest { + @Test + public void TestMasterKeyFromMnemonic() throws Exception { + String code = "ritual month sign shop champion number mask leave anchor critic boring clinic"; + HdPrivateKey masterKey = HdPrivateKey.masterKeyFromMnemonic(code); + HdPublicKey masterPubKey = masterKey.getHdPublicKey(); + Assert.assertEquals("xpub661MyMwAqRbcFipovJxHFBNJ9YZDn4NdPVcf6bFnwqo5RwgGAf1yEcGVRVwNmhBRmcvzforP5aWQefsNveyCxPdJ4L6oydpm9XLZ7PLCBXd", masterPubKey.base58Encode()); + Assert.assertEquals("942a2d2546105da4ab795f89847b6bc1bff3b90180dd811a906bb73a284f1c2e", masterKey.toHexString()); + Account masterAcct = new Account(masterKey.getPrivateKey(), SignatureScheme.SHA256WITHECDSA); + Assert.assertEquals(Helper.toHexString(masterAcct.serializePrivateKey()), masterKey.toHexString()); + Assert.assertEquals(Helper.toHexString(masterAcct.serializePublicKey()), masterPubKey.toHexString()); + Assert.assertEquals("ANQ6eYZ3Age8iXxTeaAzQR1GLbshaESWgL", masterAcct.getAddressU160().toBase58()); + acctValidity(masterAcct); + } + + @Test + public void TestRootKey() throws Exception { + HdPrivateKey masterKey = HdPrivateKey.base58Decode("xprv9s21ZrQH143K3EkLpHRGt3RZbWijNben2Gh4JCrBPWG6Z9M7d7higox1aCzTm77JCa7FGoAsy8jgtMMyqqDk25DXssjbEBzqR6yr9gqNimh"); + HdPrivateKey rootPriKey = masterKey.fromPath(); + Assert.assertEquals("66ed0c7f0476d64752ec1d14beaf0693af6641ccce6401ba6f30c41048f5f9de", rootPriKey.toHexString()); + Account rootAcct = new Account(rootPriKey.getPrivateKey(), SignatureScheme.SHA256WITHECDSA); + Assert.assertEquals("AZN8hReHwhsdaowbBLcDsGHeAnjoTXAyRs", rootAcct.getAddressU160().toBase58()); + Assert.assertEquals(rootPriKey.base58Encode(), HdPrivateKey.base58Decode(rootPriKey.base58Encode()).base58Encode()); + } + + @Test + public void TestBase58() throws Exception { + ArrayList addressList = new ArrayList<>( + Arrays.asList( + "AX9gZt82urcv5fHu13QTiU3ZczYDJPBnb1", + "ALhLmVQ4xV3ZSHzcB9p2zwkqqgHuhjQ4nM", + "AGoDL81KzTEAaPxBzWDRwmgyoZNRPJEiSz", + "APSnKt2w2YAruZHmnq3TpYqTEihvrFjAAK", + "AP4nB1yct8D6si1C6T3bdevHqJiKpxrwsu", + "AG3Qq59LUCxNDcyrpSQFBtfnje7oRTPnMV", + "AX5mTNWyeXWpTb6L3y53VpgyuspRYXzgAk", + "AMLZhVzfFecX6tw2r26p8kxwFjx6gUL7X7", + "AeUjHPsbmwCwNg9QK3gFH2nwypgeqDqfox", + "APWuVP5JqsYc8aHKGAwXg9cufmHtxz62EW" + ) + ); + HdPrivateKey masterKey = HdPrivateKey.base58Decode("xprv9s21ZrQH143K3EkLpHRGt3RZbWijNben2Gh4JCrBPWG6Z9M7d7higox1aCzTm77JCa7FGoAsy8jgtMMyqqDk25DXssjbEBzqR6yr9gqNimh"); + HdPrivateKey rootKey = masterKey.fromPath(); + Assert.assertEquals("xprv9y1wY3ovCV9wWRTw8VJwkyjuaV9vbmLb8kLuaAXyzBGQReZETHBHEab9BUdE9m5iCnfHyxABpomdqa6m4RCGzaC3iBdTQ1MPHxcF3RMXFD4", rootKey.base58Encode()); + HdPrivateKey actualRootKey = HdPrivateKey.base58Decode(rootKey.base58Encode()); + Assert.assertEquals("66ed0c7f0476d64752ec1d14beaf0693af6641ccce6401ba6f30c41048f5f9de", actualRootKey.toHexString()); + for (int i = 0; i < 10; i++) { + HdPrivateKey childKey = rootKey.fromPath(String.format("0/%d", i)); + Account childAcct = new Account(childKey.getPrivateKey(), SignatureScheme.SHA256WITHECDSA); + Assert.assertEquals(addressList.get(i), childAcct.getAddressU160().toBase58()); + Assert.assertEquals(Helper.toHexString(childAcct.serializePrivateKey()), childKey.toHexString()); + acctValidity(childAcct); + } + } + + @Test + public void TestChildKey() throws SDKException { + HdPrivateKey rootPriKey = HdPrivateKey.base58Decode("xprv9y1wY3ovCV9wWRTw8VJwkyjuaV9vbmLb8kLuaAXyzBGQReZETHBHEab9BUdE9m5iCnfHyxABpomdqa6m4RCGzaC3iBdTQ1MPHxcF3RMXFD4"); + ArrayList childKeyList = new ArrayList<>( + Arrays.asList( + "130d422b03a9b8f2246e850f2680cb61666b7d7da94a8ae1e754d12f10f9d7fa", + "8b7bb7a40ef05729fba70eec6b397f69c08d68a511428917f4f8828c5975ff50", + "59afb74c850af049c46359a55cd11edeefe32bd17956d36f0f7b5302c758d23e", + "d38b59946b0a6c359ac860b9d2632edf8ea297b11679a4ab8e06d515cc18c7bc", + "d1dac074d6361b3a0f9454affd67788e2b5cd8cc1564ffd653b36133359d13a2", + "2c700989f69f557c3dab063c62dae5a3c1b295b3044279ff645963e2c3a60877", + "2b4b47e351cb8eb717bba086b6109c312c6e196d93f96f898ae888c001baab97", + "b208e4c0cb6dbf5b17acbf98526d42a1e2c9e0f653e577247dd6722c932fc6f3", + "584540f8e3a5b37d04856c0e48267f7d42be0d3aa5610dbc7433901dc7bfe30a", + "feac85feda73a5cd07ece0eb5990b953ded921952a67642f0d57fca762fa8175" + ) + ); + for (int i = 0; i < 10; i++) { + HdPrivateKey childKey = rootPriKey.fromPath(String.format("0/%d", i)); + Assert.assertEquals(childKeyList.get(i), childKey.toHexString()); + Assert.assertEquals(childKey.base58Encode(), HdPrivateKey.base58Decode(childKey.base58Encode()).base58Encode()); + } + } + + private void acctValidity(Account acct) throws Exception { + byte[] msg = "Attack!".getBytes(StandardCharsets.UTF_8); + byte[] signature = acct.generateSignature(msg, acct.getSignatureScheme(), null); + Assert.assertTrue(acct.verifySignature(msg, signature)); + } + +} diff --git a/src/test/java/com/github/DNAProject/crypto/HdPublicKeyTest.java b/src/test/java/com/github/DNAProject/crypto/HdPublicKeyTest.java new file mode 100644 index 0000000..56a7340 --- /dev/null +++ b/src/test/java/com/github/DNAProject/crypto/HdPublicKeyTest.java @@ -0,0 +1,116 @@ + +package com.github.DNAProject.crypto; + +import com.github.DNAProject.account.Account; +import com.github.DNAProject.crypto.bip32.HdPrivateKey; +import com.github.DNAProject.crypto.bip32.HdPublicKey; +import org.junit.Assert; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; + +public class HdPublicKeyTest { + @Test + public void TestBase58() throws Exception { + ArrayList childKeysFromMaterKey = new ArrayList<>( + Arrays.asList( + "xpub6B8Gwg8EyCxhfunuHCPJzQSLyU2MEv4HzSBthbzWtkLMm9PK8GZuVT1qDSJ8jkKiwXdYzgUWgXV1fvbvvqBU1wKrJMXtrkJ4MghnsKbBR5D", + "xpub6B8Gwg8EyCxhixXNFY2khGpFADQF7Sq4Gf3e5w6buzWxjXhrqN2nbjCBmnHuTTf692RQTUvWsXTEgtaJMUqnEgDz9WcJuBiAh2eubcEVotS", + "xpub6B8Gwg8EyCxho65BfKpBtT2w4aVTrrtakypNbSn2RYYSWyuoEZDxCAB2bY9pVMPX1L1QqzANqSoMaSmnLVW9RRbSDy38SRsSc5ZdX9x7VTx", + "xpub6B8Gwg8EyCxhqzA6x6YhqEA27tu2h5Wk5hTHknbEQGCnw2immnB7Mj2SY1G2Z3sSutYncgrbUb2nsguLvZfvURo8L3zhGKECciKVDgjPgju", + "xpub6B8Gwg8EyCxhsdKE1ZeizXX9dKKhRjDj4hQ1Rihu5y3z244whdm2p1YrBtBsYKJUzX5Ks5RrngQfFY5VK6P3cQWMoB96u5ytCknmrzozrAN", + "xpub6B8Gwg8EyCxhvcNvuG5y6ExgHTkV3gr9Y8NKczn6zcT5MrBWLeTMFb6YhPL2SHWvyKD3zLSSvcfycuJzpL5kL4HNH3bT4U5Fkd1WZndXcov", + "xpub6B8Gwg8EyCxhydcj9rvsRyrx9Ns1uoYedTJn8GScff2T2vzfefetgjS1dv4K3xrffSkguDwK73YtFdhxgwsMbn8gqtaqJUR8tQ64yBckngK", + "xpub6B8Gwg8EyCxhzEzosFjaCaK4T7Baxasg2mfrKovbnx2TqBJGfaaZjKiozCX2zzYBc79kgAv8UmYtnoo1dsjXGg3kME9aKyMLTeESdoJNup5", + "xpub6B8Gwg8EyCxi2PpauJ4mhjxRsf4n7HKjUY65HnXfrCJTtYJH25LjrthVdrQZXoik9cXTwdm9qLtoWLcHXB3KkMkZUJPXbWenoFkzxLZ9tuU", + "xpub6B8Gwg8EyCxi74DcH9AdErRcSDfiYnH3CCUS2Kb2CsrhtYATVugBiVYGBungGJphArg3peaDUh6hwJnxCUSbsqcqhZkKK35bMkK4WLtario" + ) + ); + HdPrivateKey masterKey = HdPrivateKey.base58Decode("xprv9s21ZrQH143K3EkLpHRGt3RZbWijNben2Gh4JCrBPWG6Z9M7d7higox1aCzTm77JCa7FGoAsy8jgtMMyqqDk25DXssjbEBzqR6yr9gqNimh"); + HdPublicKey masterPubKey = masterKey.getHdPublicKey(); + Assert.assertEquals("03908a0ce4ccc0e706e09905db4f04eb150bc42fb6cd96a7a2c8396873fa973262", masterPubKey.toHexString()); + String encodeMasterPubKey = masterPubKey.base58Encode(); + Assert.assertEquals("xpub661MyMwAqRbcFipovJxHFBNJ9YZDn4NdPVcf6bFnwqo5RwgGAf1yEcGVRVwNmhBRmcvzforP5aWQefsNveyCxPdJ4L6oydpm9XLZ7PLCBXd", encodeMasterPubKey); + HdPublicKey actualMasterPubKey = HdPublicKey.base58Decode(encodeMasterPubKey); + Assert.assertEquals(masterPubKey.toHexString(), actualMasterPubKey.toHexString()); + for (int i = 0; i < 10; i++) { + HdPublicKey childKey = masterPubKey.fromPath(String.format("0/%d", i)); + Assert.assertEquals(childKeysFromMaterKey.get(i), childKey.base58Encode()); + } + } + + @Test + public void TestChildKey() throws Exception { + ArrayList childPubKeys = new ArrayList<>( + Arrays.asList( + "03d36b121866ddb5d18cd73b4f08a0b33d4e78765353122af304c274afa46234f1", + "0294423e98e78befeec802f3bb710d23e07cde2eac693f04b0457f0088987a6c3d", + "024573478ec397c11187a80654eb61632195e10b790abcd3c7a4ebf9bb656d08a2", + "03a4d828a8d10d6af8ae575b8edd751053179b9c20966c5ae3140b524269114b94", + "02547df85c98586055f7f991ee2eb2ae12c6dcfc8f3dc47d07b6416f3118206aa2", + "03b4713e88d3015e91b827c87d8de204f6807e57e4ca4a048c4cff81643b816fd1", + "0366faf9e5c4984bed43afa2cebad2ea957bbce308a3d100e5bd7ee0a7b8a49a89", + "0374eb62dab8294566d804bd7d1e3475bc1c66e08824f1b77dd18b539ba192a6aa", + "0349d87e57ca1bd3d720625ad973d24cba51c94ca33352b462e851ebbb5f12a47d", + "02d34bdd023d4cfe9461a60222cbb6ef34f09a1ec4208d15e30800aa4c20c8be28" + ) + ); + ArrayList childPrvKeys = new ArrayList<>( + Arrays.asList( + "130d422b03a9b8f2246e850f2680cb61666b7d7da94a8ae1e754d12f10f9d7fa", + "8b7bb7a40ef05729fba70eec6b397f69c08d68a511428917f4f8828c5975ff50", + "59afb74c850af049c46359a55cd11edeefe32bd17956d36f0f7b5302c758d23e", + "d38b59946b0a6c359ac860b9d2632edf8ea297b11679a4ab8e06d515cc18c7bc", + "d1dac074d6361b3a0f9454affd67788e2b5cd8cc1564ffd653b36133359d13a2", + "2c700989f69f557c3dab063c62dae5a3c1b295b3044279ff645963e2c3a60877", + "2b4b47e351cb8eb717bba086b6109c312c6e196d93f96f898ae888c001baab97", + "b208e4c0cb6dbf5b17acbf98526d42a1e2c9e0f653e577247dd6722c932fc6f3", + "584540f8e3a5b37d04856c0e48267f7d42be0d3aa5610dbc7433901dc7bfe30a", + "feac85feda73a5cd07ece0eb5990b953ded921952a67642f0d57fca762fa8175" + ) + ); + + HdPrivateKey rootPriKey = HdPrivateKey.base58Decode("xprv9y1wY3ovCV9wWRTw8VJwkyjuaV9vbmLb8kLuaAXyzBGQReZETHBHEab9BUdE9m5iCnfHyxABpomdqa6m4RCGzaC3iBdTQ1MPHxcF3RMXFD4"); + HdPublicKey rootPubKey = rootPriKey.getHdPublicKey(); + for (int i = 0; i < 10; i++) { + HdPublicKey childPubKey = rootPubKey.fromPath(String.format("0/%d", i)); + HdPrivateKey childPrvKey = rootPriKey.fromPath(String.format("0/%d", i)); + Assert.assertEquals(childPrvKeys.get(i), childPrvKey.toHexString()); + Assert.assertEquals(childPubKeys.get(i), childPubKey.toHexString()); + Assert.assertEquals(childPubKey.base58Encode(), HdPublicKey.base58Decode(childPubKey.base58Encode()).base58Encode()); + Account acct = new Account(childPrvKey.getPrivateKey(), SignatureScheme.SHA256WITHECDSA); + Assert.assertEquals(childPubKey.getAddress().toBase58(), acct.getAddressU160().toBase58()); + Assert.assertEquals(childPrvKey.getAddress().toBase58(), acct.getAddressU160().toBase58()); + } + } + + @Test + public void TestChildAddress() throws Exception { + ArrayList childAddressList = new ArrayList<>( + Arrays.asList( + "AX9gZt82urcv5fHu13QTiU3ZczYDJPBnb1", + "ALhLmVQ4xV3ZSHzcB9p2zwkqqgHuhjQ4nM", + "AGoDL81KzTEAaPxBzWDRwmgyoZNRPJEiSz", + "APSnKt2w2YAruZHmnq3TpYqTEihvrFjAAK", + "AP4nB1yct8D6si1C6T3bdevHqJiKpxrwsu", + "AG3Qq59LUCxNDcyrpSQFBtfnje7oRTPnMV", + "AX5mTNWyeXWpTb6L3y53VpgyuspRYXzgAk", + "AMLZhVzfFecX6tw2r26p8kxwFjx6gUL7X7", + "AeUjHPsbmwCwNg9QK3gFH2nwypgeqDqfox", + "APWuVP5JqsYc8aHKGAwXg9cufmHtxz62EW" + ) + ); + + HdPrivateKey rootPriKey = HdPrivateKey.base58Decode("xprv9y1wY3ovCV9wWRTw8VJwkyjuaV9vbmLb8kLuaAXyzBGQReZETHBHEab9BUdE9m5iCnfHyxABpomdqa6m4RCGzaC3iBdTQ1MPHxcF3RMXFD4"); + HdPublicKey rootPubKey = rootPriKey.getHdPublicKey(); + for (int i = 0; i < 10; i++) { + HdPublicKey childPubKey = rootPubKey.fromPath(String.format("0/%d", i)); + HdPrivateKey childPrvKey = rootPriKey.fromPath(String.format("0/%d", i)); + Assert.assertEquals(childPubKey.getAddress().toBase58(), childAddressList.get(i)); + Account acct = new Account(childPrvKey.getPrivateKey(), SignatureScheme.SHA256WITHECDSA); + Assert.assertEquals(childPubKey.getAddress().toBase58(), acct.getAddressU160().toBase58()); + Assert.assertEquals(childPrvKey.getAddress().toBase58(), acct.getAddressU160().toBase58()); + } + } +} diff --git a/src/test/java/com/github/DNAProject/crypto/MnemonicTest.java b/src/test/java/com/github/DNAProject/crypto/MnemonicTest.java new file mode 100644 index 0000000..da527d4 --- /dev/null +++ b/src/test/java/com/github/DNAProject/crypto/MnemonicTest.java @@ -0,0 +1,18 @@ + +package com.github.DNAProject.crypto; + +import io.github.novacrypto.bip39.Words; +import org.junit.Assert; +import org.junit.Test; + +public class MnemonicTest { + @Test + public void TestMnemonic() { + Assert.assertEquals(12, MnemonicCode.generateMnemonicCodesStr().split(" ").length); + Assert.assertEquals(12, MnemonicCode.generateMnemonicCodesStr(Words.TWELVE).split(" ").length); + Assert.assertEquals(15, MnemonicCode.generateMnemonicCodesStr(Words.FIFTEEN).split(" ").length); + Assert.assertEquals(18, MnemonicCode.generateMnemonicCodesStr(Words.EIGHTEEN).split(" ").length); + Assert.assertEquals(21, MnemonicCode.generateMnemonicCodesStr(Words.TWENTY_ONE).split(" ").length); + Assert.assertEquals(24, MnemonicCode.generateMnemonicCodesStr(Words.TWENTY_FOUR).split(" ").length); + } +} diff --git a/src/test/java/com/github/DNAProject/io/BinaryReaderTest.java b/src/test/java/com/github/DNAProject/io/BinaryReaderTest.java new file mode 100644 index 0000000..400b85c --- /dev/null +++ b/src/test/java/com/github/DNAProject/io/BinaryReaderTest.java @@ -0,0 +1,62 @@ +package com.github.DNAProject.io; + +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Arrays; + +import static org.junit.Assert.*; + +public class BinaryReaderTest { + + @Test + public void readVarBytes() throws IOException { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + BinaryWriter binaryWriter = new BinaryWriter(byteArrayOutputStream); + binaryWriter.writeVarBytes("12".getBytes()); + + ByteArrayInputStream bin = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); + BinaryReader binaryReader = new BinaryReader(bin); + byte[] res = binaryReader.readVarBytes(); + assertTrue(Arrays.equals(res,"12".getBytes())); + } + + @Test + public void readVarInt() throws IOException { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + BinaryWriter binaryWriter = new BinaryWriter(byteArrayOutputStream); + binaryWriter.writeVarInt(123); + + ByteArrayInputStream bin = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); + BinaryReader binaryReader = new BinaryReader(bin); + long res = binaryReader.readVarInt(); + assertEquals(123,res); + } + + @Test + public void readBoolean() throws IOException { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + BinaryWriter binaryWriter = new BinaryWriter(byteArrayOutputStream); + binaryWriter.writeBoolean(true); + + ByteArrayInputStream bin = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); + BinaryReader binaryReader = new BinaryReader(bin); + boolean res = binaryReader.readBoolean(); + assertTrue(res); + } + + @Test + public void readByte() throws IOException { + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + BinaryWriter binaryWriter = new BinaryWriter(byteArrayOutputStream); + byte a = 'a'; + binaryWriter.writeByte(a); + + ByteArrayInputStream bin = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); + BinaryReader binaryReader = new BinaryReader(bin); + byte res = binaryReader.readByte(); + assertEquals(res,'a'); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/DNAProject/io/BinaryWriterTest.java b/src/test/java/com/github/DNAProject/io/BinaryWriterTest.java new file mode 100644 index 0000000..5614af3 --- /dev/null +++ b/src/test/java/com/github/DNAProject/io/BinaryWriterTest.java @@ -0,0 +1,59 @@ +package com.github.DNAProject.io; + +import com.github.DNAProject.sdk.exception.SDKException; +import org.junit.Test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import static org.junit.Assert.*; + +public class BinaryWriterTest { + + @Test + public void writeVarInt() throws IOException { + ByteArrayOutputStream ms = new ByteArrayOutputStream(); + BinaryWriter binaryWriter = new BinaryWriter(ms); + binaryWriter.writeVarInt((long) 2544); + binaryWriter.flush(); + assertNotNull(ms); + } + + @Test + public void write() throws IOException { + ByteArrayOutputStream ms = new ByteArrayOutputStream(); + BinaryWriter binaryWriter = new BinaryWriter(ms); + binaryWriter.write("test".getBytes()); + binaryWriter.flush(); + assertNotNull(ms); + } + + @Test + public void writeInt() throws IOException { + ByteArrayOutputStream ms = new ByteArrayOutputStream(); + BinaryWriter binaryWriter = new BinaryWriter(ms); + binaryWriter.writeInt(1); + binaryWriter.flush(); + assertNotNull(ms); + } + + @Test + public void writeSerializable() throws IOException, SDKException { +// ByteArrayOutputStream ms = new ByteArrayOutputStream(); +// BinaryWriter binaryWriter = new BinaryWriter(ms); +// Address address = Address.decodeBase58("TA6nRD9DqGkE8xRJaB37bW2KQEz59ovKRH"); +// binaryWriter.writeSerializable(address); +// binaryWriter.flush(); +// assertNotNull(ms); + } + + @Test + public void writeVarBytes() throws IOException { + ByteArrayOutputStream ms = new ByteArrayOutputStream(); + BinaryWriter binaryWriter = new BinaryWriter(ms); + binaryWriter.writeVarBytes("test".getBytes()); + binaryWriter.flush(); + assertNotNull(ms); + } + +} \ No newline at end of file diff --git a/src/test/java/com/github/DNAProject/merkle/MerkleVerifierTest.java b/src/test/java/com/github/DNAProject/merkle/MerkleVerifierTest.java new file mode 100644 index 0000000..d6d7274 --- /dev/null +++ b/src/test/java/com/github/DNAProject/merkle/MerkleVerifierTest.java @@ -0,0 +1,108 @@ +package com.github.DNAProject.merkle; + +import com.alibaba.fastjson.JSONObject; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.DnaSdkTest; +import com.github.DNAProject.common.UInt256; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.sdk.exception.SDKException; +import com.github.DNAProject.sdk.wallet.Account; +import com.github.DNAProject.sdk.wallet.Identity; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.*; + +public class MerkleVerifierTest { + DnaSdk dnaSdk; + String password = "111111"; + String walletFile = "MerkleVerifierTest.json"; + + @Before + public void setUp() throws SDKException { + String restUrl = DnaSdkTest.URL; + + dnaSdk = DnaSdk.getInstance(); + dnaSdk.setRestful(restUrl); + dnaSdk.setDefaultConnect(dnaSdk.getRestful()); + + dnaSdk.openWalletFile(walletFile); + } + + + @After + public void removeWallet(){ + File file = new File(walletFile); + if(file.exists()){ + if(file.delete()){ + System.out.println("delete wallet file success"); + } + } + } + + @Test + public void verifyLeafHashInclusion() throws Exception { + UInt256 txroot = UInt256.parse("f332c8ede11799137f28b10e40200063353dfc3233da6cea689e0637231ad1a7"); + UInt256 curBlkRoot = UInt256.parse("ba64746f650b7be0ac89fbf8defeceeb63821272d8096d83d3764b7ae9eb4a21"); + UInt256[] targetHashes = new UInt256[]{ + UInt256.parse("0000000000000000000000000000000000000000000000000000000000000000"), + UInt256.parse("e14172c8a6e193943465648e1c586a9186a3784ee7ee29db9edbf6afe04f5390"), + UInt256.parse("f440531999c547db08f516677c152215475a69dccb82176e4bca1b726261a1be"), + + UInt256.parse("ef4d3c0debb66bb15af8b82e1b9463d3039f6a95bf91c349e7df1b34ef5f7630"), + UInt256.parse("d6dd5266af7407b89d00b1a11044cd4eb30f94dabbdf440b03f9173384b16d67"), + UInt256.parse("17100c09ef2d19689c85cc7038b6654037045fc83b3951439634e5d2074998c6"), + + UInt256.parse("584aa3a421020a07710a2bc16e7865ea9ee0860692ad509515fb8caa837d27df"), + UInt256.parse("192eed54084fbe94a8c34c1274168f38ac02abe01c94f9b425e58f26fe93d598") + }; + int blockHeight = 1277; + int curBlockHeight = 1277; + boolean b = MerkleVerifier.VerifyLeafHashInclusion(txroot, blockHeight, targetHashes, curBlkRoot, curBlockHeight+1); + assertTrue(b); + } + + @Test + public void getProof() throws Exception { + Identity identity = dnaSdk.getWalletMgr().createIdentity(password); + Account payer = dnaSdk.getWalletMgr().createAccount(password); + byte[] salt = identity.controls.get(0).getSalt(); + Transaction tx = dnaSdk.nativevm().dnaId().makeRegister(identity.dnaid,identity.controls.get(0).publicKey,payer.address, dnaSdk.DEFAULT_GAS_LIMIT,0); + dnaSdk.signTx(tx,identity.dnaid,password,salt); + dnaSdk.addSign(tx,payer.address,password,payer.getSalt()); + dnaSdk.getConnect().sendRawTransaction(tx); + Thread.sleep(6000); + + String hash = tx.hash().toHexString(); + System.out.println(hash); + Map proof = new HashMap(); + Map map = new HashMap(); + int height = dnaSdk.getConnect().getBlockHeightByTxHash(hash); + map.put("Type", "MerkleProof"); + map.put("TxnHash", hash); + map.put("BlockHeight", height); + System.out.println(hash); + Map tmpProof = (Map) dnaSdk.getConnect().getMerkleProof(hash); + System.out.println(JSONObject.toJSONString(tmpProof)); + UInt256 txroot = UInt256.parse((String) tmpProof.get("TransactionsRoot")); + int blockHeight = (int) tmpProof.get("BlockHeight"); + UInt256 curBlockRoot = UInt256.parse((String) tmpProof.get("CurBlockRoot")); + int curBlockHeight = (int) tmpProof.get("CurBlockHeight"); + List hashes = (List) tmpProof.get("TargetHashes"); + UInt256[] targetHashes = new UInt256[hashes.size()]; + for (int i = 0; i < hashes.size(); i++) { + targetHashes[i] = UInt256.parse((String) hashes.get(i)); + } + map.put("MerkleRoot", curBlockRoot.toHexString()); + map.put("Nodes", MerkleVerifier.getProof(txroot, blockHeight, targetHashes, curBlockHeight + 1)); + proof.put("Proof", map); + boolean b = MerkleVerifier.Verify(txroot, MerkleVerifier.getProof(txroot, blockHeight, targetHashes, curBlockHeight + 1), curBlockRoot); + assertTrue(b); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/DNAProject/sdk/manager/ConnectMgrTest.java b/src/test/java/com/github/DNAProject/sdk/manager/ConnectMgrTest.java new file mode 100644 index 0000000..454427b --- /dev/null +++ b/src/test/java/com/github/DNAProject/sdk/manager/ConnectMgrTest.java @@ -0,0 +1,155 @@ +package com.github.DNAProject.sdk.manager; + +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.DnaSdkTest; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.block.Block; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.crypto.SignatureScheme; +import com.github.DNAProject.network.exception.ConnectorException; +import com.github.DNAProject.sdk.exception.SDKException; +import com.github.DNAProject.sdk.info.AccountInfo; +import com.github.DNAProject.sdk.wallet.Identity; +import com.github.DNAProject.smartcontract.nativevm.abi.NativeBuildParams; +import com.github.DNAProject.smartcontract.neovm.abi.BuildParams; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +public class ConnectMgrTest { + + DnaSdk ontSdk; + String codeAddress; + String blockHash; + String password = "111111"; + Identity identity; + private final String ontContract = "0000000000000000000000000000000000000001"; + + String wallet = "ConnectMgrTest.json"; + + @Before + public void setUp() throws Exception { + + ontSdk = DnaSdk.getInstance(); + String restUrl = DnaSdkTest.URL; + ontSdk.setRestful(restUrl); + ontSdk.setDefaultConnect(ontSdk.getRestful()); + ontSdk.openWalletFile(wallet); + + if(ontSdk.getWalletMgr().getWallet().getIdentities().size() < 1){ + identity = ontSdk.getWalletMgr().createIdentity(password); + }else{ + identity = ontSdk.getWalletMgr().getWallet().getIdentities().get(0); + } + } + + + @After + public void removeWallet(){ + File file = new File(wallet); + if(file.exists()){ + if(file.delete()){ + System.out.println("delete wallet file success"); + } + } + } + + @Test + public void sendRawTransaction() throws Exception { + //部署交易 + String codeHex = "5ec56b6c766b00527ac46c766b51527ac4616c766b00c306436f6d6d6974876c766b52527ac46c766b52c3645d00616c766b51c3c0529c009c6c766b55527ac46c766b55c3640e00006c766b56527ac4621e016c766b51c300c36c766b53527ac46c766b51c351c36c766b54527ac46c766b53c36c766b54c3617c65fc006c766b56527ac462e9006c766b00c3065265766f6b65876c766b57527ac46c766b57c3645d00616c766b51c3c0529c009c6c766b5a527ac46c766b5ac3640e00006c766b56527ac462a8006c766b51c300c36c766b58527ac46c766b51c351c36c766b59527ac46c766b58c36c766b59c3617c65d7016c766b56527ac46273006c766b00c309476574537461747573876c766b5b527ac46c766b5bc3644900616c766b51c3c0519c009c6c766b5d527ac46c766b5dc3640e00006c766b56527ac4622f006c766b51c300c36c766b5c527ac46c766b5cc36165b8036c766b56527ac4620e00006c766b56527ac46203006c766b56c3616c756656c56b6c766b00527ac46c766b51527ac4616168164e656f2e53746f726167652e476574436f6e746578746c766b00c3617c680f4e656f2e53746f726167652e4765746c766b52527ac46c766b52c3640e006c766b52c3c000a0620400006c766b54527ac46c766b54c364410061616c766b00c309206578697374656421617c084572726f724d736753c168124e656f2e52756e74696d652e4e6f7469667961006c766b55527ac462a0000231236c766b53527ac46c766b53c36c766b51c37e6c766b53527ac46168164e656f2e53746f726167652e476574436f6e746578746c766b00c36c766b53c3615272680f4e656f2e53746f726167652e50757461616c766b51c31320637265617465206e657720636c61696e3a206c766b00c3615272045075736854c168124e656f2e52756e74696d652e4e6f7469667961516c766b55527ac46203006c766b55c3616c756658c56b6c766b00527ac46c766b51527ac4616168164e656f2e53746f726167652e476574436f6e746578746c766b00c3617c680f4e656f2e53746f726167652e4765746c766b52527ac46168164e656f2e53746f726167652e476574436f6e746578746c766b00c3617c680f4e656f2e53746f726167652e476574756c766b52c3630e006c766b52c3c0009c620400006c766b54527ac46c766b54c364450061616c766b00c30d206e6f74206578697374656421617c084572726f724d736753c168124e656f2e52756e74696d652e4e6f7469667961006c766b55527ac4625f016c766b52c300517f01309c6c766b56527ac46c766b56c3644a0061616c766b00c312206861732062656564207265766f6b65642e617c084572726f724d736753c168124e656f2e52756e74696d652e4e6f7469667961006c766b55527ac462fe006c766b52c300517f01319c009c6c766b57527ac46c766b57c364490061616c766b00c3112076616c756520696e76616c696465642e617c084572726f724d736753c168124e656f2e52756e74696d652e4e6f7469667961006c766b55527ac4629c000230236c766b53527ac46c766b53c36c766b51c37e6c766b53527ac46168164e656f2e53746f726167652e476574436f6e746578746c766b00c36c766b53c3615272680f4e656f2e53746f726167652e50757461616c766b51c30f207265766f6b6520636c61696d3a206c766b00c3615272045075736854c168124e656f2e52756e74696d652e4e6f7469667961516c766b55527ac46203006c766b55c3616c756653c56b6c766b00527ac4616168164e656f2e53746f726167652e476574436f6e746578746c766b00c3617c680f4e656f2e53746f726167652e4765746c766b51527ac4616c766b00c309207374617475733a206c766b51c3615272045075736854c168124e656f2e52756e74696d652e4e6f74696679616c766b51c36c766b52527ac46203006c766b52c3616c7566"; + codeAddress = Address.AddressFromVmCode(codeHex).toHexString(); + Transaction tx = ontSdk.vm().makeDeployCodeTransaction(codeHex, true, "name", "1.0", "1", "1", "1",identity.dnaid,ontSdk.DEFAULT_GAS_LIMIT,0); + ontSdk.signTx(tx,identity.dnaid,password,identity.controls.get(0).getSalt()); + + String txHex = Helper.toHexString(tx.toArray()); + boolean b = ontSdk.getConnect().sendRawTransaction(txHex); + Thread.sleep(6000); + + + AccountInfo info = ontSdk.getWalletMgr().getAccountInfo(identity.dnaid, password,identity.controls.get(0).getSalt()); + List list = new ArrayList(); + list.add("Commit".getBytes()); + List tmp = new ArrayList(); + tmp.add(Helper.hexToBytes("dde1a09571bf98e04e62b1a8778b2d413747408f4594c946577965fa571de8e5")); + tmp.add(identity.dnaid.getBytes()); + list.add(tmp); + byte[] params = BuildParams.createCodeParamsScript(list); + Transaction tx2 = ontSdk.vm().makeInvokeCodeTransaction(codeAddress,null,params,identity.dnaid,ontSdk.DEFAULT_GAS_LIMIT,0); + ontSdk.signTx(tx2, identity.dnaid, password,identity.controls.get(0).getSalt()); + boolean b2 = ontSdk.getConnect().sendRawTransaction(tx2.toHexString()); + Assert.assertEquals(true,b); + + Thread.sleep(6000); + + Transaction txres = ontSdk.getConnect().getTransaction(tx2.hash().toHexString()); + Assert.assertNotNull(txres); + Object obj = ontSdk.getConnect().getTransactionJson(tx2.hash().toHexString()); + Assert.assertNotNull(obj); + + Object obj2 = ontSdk.getConnect().getSmartCodeEvent(tx2.hash().toHexString()); + Assert.assertNotNull(obj2); + + int blockheight = ontSdk.getConnect().getBlockHeightByTxHash(tx2.hash().toHexString()); + Assert.assertNotNull(blockheight); +// ontSdk.getConnectMgr().getStorage(codeAddress,) + + } + + @Test + public void sendRawTransactionPreExec() throws Exception { + Account account = new Account(Helper.hexToBytes(DnaSdkTest.PRIVATEKEY),SignatureScheme.SHA256WITHECDSA); + List list = new ArrayList(); + list.add(Address.decodeBase58(account.getAddressU160().toBase58())); + byte[] parabytes = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = ontSdk.vm().buildNativeParams(new Address(Helper.hexToBytes(ontContract)),"balanceOf",parabytes,null,0,0); + Object obj = ontSdk.getConnect().sendRawTransactionPreExec(tx.toHexString()); + Assert.assertNotEquals(null,obj); + } + + @Test + public void getBlockHeight() throws ConnectorException, IOException { + + int res = ontSdk.getConnect().getBlockHeight(); + Assert.assertTrue(res > 0); + } + + @Test + public void getBlock() throws ConnectorException, IOException,SDKException { + int blockHeight = ontSdk.getConnect().getBlockHeight(); + Block b = ontSdk.getConnect().getBlock(blockHeight); + Assert.assertNotNull(b); + + } + + @Test + public void getBlockByBlockhash() throws ConnectorException, IOException,SDKException { + int blockHeight = ontSdk.getConnect().getBlockHeight(); + Block b2 = ontSdk.getConnect().getBlock(blockHeight); + blockHash = b2.hash().toString(); + Block b = ontSdk.getConnect().getBlock(blockHash); + Assert.assertNotNull(b); + } + + @Test + public void getBalance() throws Exception { + Account account = new Account(Helper.hexToBytes(DnaSdkTest.PRIVATEKEY),SignatureScheme.SHA256WITHECDSA); + Object obj = ontSdk.getConnect().getBalance(account.getAddressU160().toBase58()); + Assert.assertNotNull(obj); + } + + @Test + public void getBlockJson() throws ConnectorException, IOException { + int blockHeight = ontSdk.getConnect().getBlockHeight(); + Object obj = ontSdk.getConnect().getBlockJson(blockHeight); + Assert.assertNotNull(obj); + } + +} \ No newline at end of file diff --git a/src/test/java/com/github/DNAProject/sdk/manager/GasAssetTxTest.java b/src/test/java/com/github/DNAProject/sdk/manager/GasAssetTxTest.java new file mode 100644 index 0000000..86b7d7e --- /dev/null +++ b/src/test/java/com/github/DNAProject/sdk/manager/GasAssetTxTest.java @@ -0,0 +1,111 @@ +package com.github.DNAProject.sdk.manager; + +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.DnaSdkTest; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.sdk.wallet.Account; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; + +import static org.junit.Assert.*; + +public class GasAssetTxTest { + + DnaSdk ontSdk; + Account info1 = null; + Account info2 = null; + Account info3 = null; + String password = "111111"; + String wallet = "OntAssetTxTest.json"; + + Account payer; + @Before + public void setUp() throws Exception { + ontSdk = DnaSdk.getInstance(); + String restUrl = DnaSdkTest.URL; + ontSdk.setRestful(restUrl); + ontSdk.setDefaultConnect(ontSdk.getRestful()); + ontSdk.openWalletFile(wallet); + info1 = ontSdk.getWalletMgr().createAccountFromPriKey(DnaSdkTest.PASSWORD, DnaSdkTest.PRIVATEKEY); + info2 = ontSdk.getWalletMgr().createAccount(password); + info3 = ontSdk.getWalletMgr().createAccount(password); + + payer = ontSdk.getWalletMgr().createAccount(password); + } + @After + public void removeWallet(){ + File file = new File(wallet); + if(file.exists()){ + if(file.delete()){ + System.out.println("delete wallet file success"); + } + } + } + @Test + public void sendTransfer() throws Exception { + com.github.DNAProject.account.Account sendAcct = ontSdk.getWalletMgr().getAccount(info1.address,password,info1.getSalt()); + com.github.DNAProject.account.Account payerAcct = ontSdk.getWalletMgr().getAccount(payer.address,password,payer.getSalt()); + String res= ontSdk.nativevm().gas().sendTransfer(sendAcct,info2.address,100L,payerAcct,ontSdk.DEFAULT_GAS_LIMIT,0); + + + Assert.assertNotNull(res); + } + + @Test + public void makeTransfer() throws Exception { + + Transaction tx = ontSdk.nativevm().gas().makeTransfer(info1.address,info2.address,100L,payer.address,ontSdk.DEFAULT_GAS_LIMIT,0); + Assert.assertNotNull(tx); + } + + @Test + public void sendApprove() throws Exception { + com.github.DNAProject.account.Account sendAcct1 = ontSdk.getWalletMgr().getAccount(info1.address,password,info1.getSalt()); + com.github.DNAProject.account.Account sendAcct2 = ontSdk.getWalletMgr().getAccount(info2.address,password,info2.getSalt()); + com.github.DNAProject.account.Account payerAcct = ontSdk.getWalletMgr().getAccount(payer.address,password,payer.getSalt()); + ontSdk.nativevm().gas().sendApprove(sendAcct1,sendAcct2.getAddressU160().toBase58(),10L,payerAcct,ontSdk.DEFAULT_GAS_LIMIT,0); + long info1balance = ontSdk.nativevm().gas().queryBalanceOf(sendAcct1.getAddressU160().toBase58()); + long info2balance = ontSdk.nativevm().gas().queryBalanceOf(sendAcct2.getAddressU160().toBase58()); + Thread.sleep(6000); + + long allo = ontSdk.nativevm().gas().queryAllowance(sendAcct1.getAddressU160().toBase58(),sendAcct2.getAddressU160().toBase58()); + Assert.assertTrue(allo == 10); + ontSdk.nativevm().gas().sendTransferFrom(sendAcct2,info1.address,sendAcct2.getAddressU160().toBase58(),10L,payerAcct,ontSdk.DEFAULT_GAS_LIMIT,0); + Thread.sleep(6000); + long info1balance2 = ontSdk.nativevm().gas().queryBalanceOf(info1.address); + long info2balance2 = ontSdk.nativevm().gas().queryBalanceOf(info2.address); + + Assert.assertTrue((info1balance - info1balance2) == 10); + Assert.assertTrue((info2balance2 - info2balance) == 10); + + + } + + @Test + public void sendOngTransferFrom() throws Exception { + String unboundOngStr = ontSdk.nativevm().gas().unboundGas(info1.address); + long unboundOng = Long.parseLong(unboundOngStr); + String res = ontSdk.nativevm().gas().withdrawGas(ontSdk.getWalletMgr().getAccount(info1.address,password,info1.getSalt()),info2.address,unboundOng/100,ontSdk.getWalletMgr().getAccount(payer.address,password,payer.getSalt()),ontSdk.DEFAULT_GAS_LIMIT,0); + Assert.assertNotNull(res); + } + + @Test + public void queryTest() throws Exception { + + long decimal = ontSdk.nativevm().gas().queryDecimals(); + long decimal2 = ontSdk.nativevm().gas().queryDecimals(); + Assert.assertNotNull(decimal); + Assert.assertNotNull(decimal2); + + String name = ontSdk.nativevm().gas().queryName(); + + String gassym = ontSdk.nativevm().gas().querySymbol(); + + long total = ontSdk.nativevm().gas().queryTotalSupply(); + + } +} \ No newline at end of file diff --git a/src/test/java/com/github/DNAProject/sdk/manager/WalletMgrTest.java b/src/test/java/com/github/DNAProject/sdk/manager/WalletMgrTest.java new file mode 100644 index 0000000..c43905a --- /dev/null +++ b/src/test/java/com/github/DNAProject/sdk/manager/WalletMgrTest.java @@ -0,0 +1,122 @@ +package com.github.DNAProject.sdk.manager; + +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.DnaSdkTest; +import com.github.DNAProject.sdk.wallet.Account; +import com.github.DNAProject.sdk.wallet.Identity; +import com.github.DNAProject.sdk.wallet.Wallet; +import com.github.DNAProject.smartcontract.nativevm.DnaId; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.util.List; + +import static org.junit.Assert.*; + +public class WalletMgrTest { + private DnaSdk dnaSdk; + private WalletMgr walletMgr; + private Wallet wallet; + private DnaId dnaIdTx; + + String password = "111111"; + byte[] salt = new byte[]{}; + Account payer; + + String walletFile = "wallet.json"; + + @Before + public void setUp() throws Exception { + dnaSdk = DnaSdk.getInstance(); + dnaSdk.setRestful(DnaSdkTest.URL); + dnaSdk.openWalletFile(walletFile); + walletMgr = dnaSdk.getWalletMgr(); + wallet = walletMgr.getWallet(); + dnaIdTx = dnaSdk.nativevm().dnaId(); + payer = dnaSdk.getWalletMgr().createAccount(password); + + } + + @After + public void removeWallet(){ + File file = new File(walletFile); + if(file.exists()){ + if(file.delete()){ + System.out.println("delete wallet file success"); + } + } + } + + @Test + public void openWallet() { + dnaSdk.openWalletFile("wallet.json"); + walletMgr = dnaSdk.getWalletMgr(); + assertNotNull(walletMgr); + } + + @Test + public void getWallet() { + } + + @Test + public void writeWallet() throws Exception { + walletMgr.writeWallet(); + File f = new File("wallet.json"); + boolean isExist = f.exists() && !f.isDirectory(); + assertTrue(isExist); + } + + @Test + public void createIdentity() throws Exception { + Identity identity = walletMgr.createIdentity(password); + com.github.DNAProject.account.Account account = walletMgr.getAccount(identity.dnaid,password,identity.controls.get(0).getSalt()); + assertNotNull(account); + assertNotNull(identity); + assertNotNull(identity.dnaid); + assertNotEquals(identity.dnaid,""); + } + + @Test + public void importIdentity() throws Exception { + List identities = wallet.getIdentities(); + identities.clear(); + walletMgr.writeWallet(); + assertEquals(identities.size(), 0); + + Identity identity = walletMgr.createIdentity(password); + com.github.DNAProject.account.Account account = walletMgr.getAccount(identity.dnaid,password,identity.controls.get(0).getSalt()); + String prikeyStr = account.exportGcmEncryptedPrikey(password,identity.controls.get(0).getSalt(),16384); + assertTrue(identities.size() == 1); + identities.clear(); + walletMgr.writeWallet(); + assertTrue(identities.size() == 0); + + String addr = identity.dnaid.substring(8); + walletMgr.importIdentity(prikeyStr,password,identity.controls.get(0).getSalt(),addr); + assertTrue(identities.size() == 1); + Identity identity1 = identities.get(0); + assertEquals(identity.dnaid,identity1.dnaid); + } + + @Test + public void importAccount() throws Exception { + List accounts = walletMgr.getWallet().getAccounts(); + accounts.clear(); + assertEquals(accounts.size(), 0); + walletMgr.writeWallet(); + Account account = walletMgr.createAccount(password); + com.github.DNAProject.account.Account accountDiff = walletMgr.getAccount(account.address,password,account.getSalt()); + String prikeyStr = accountDiff.exportGcmEncryptedPrikey(password,account.getSalt(),16384); + assertTrue(accounts.size() == 1); + accounts.clear(); + assertTrue(accounts.size() == 0); + walletMgr.writeWallet(); + + Account account1 = walletMgr.importAccount(prikeyStr,password,account.address,account.getSalt()); + assertTrue(accounts.size() == 1); + assertEquals(account.address, account1.address); + + } +} \ No newline at end of file diff --git a/src/test/java/com/github/DNAProject/sdk/wallet/WalletTest.java b/src/test/java/com/github/DNAProject/sdk/wallet/WalletTest.java new file mode 100644 index 0000000..27f71b7 --- /dev/null +++ b/src/test/java/com/github/DNAProject/sdk/wallet/WalletTest.java @@ -0,0 +1,66 @@ +package com.github.DNAProject.sdk.wallet; + +import com.github.DNAProject.DnaSdk; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; + +public class WalletTest { + + DnaSdk dnaSdk; + Identity id1; + Identity id2; + Account acct1; + Account acct2; + + String walletFile = "WalletTest.json"; + + @Before + public void setUp() throws Exception { + dnaSdk = DnaSdk.getInstance(); + dnaSdk.openWalletFile(walletFile); + + + id1 = dnaSdk.getWalletMgr().createIdentity("passwordtest"); + id2 = dnaSdk.getWalletMgr().createIdentity("passwordtest"); + + acct1 = dnaSdk.getWalletMgr().createAccount("passwordtest"); + acct2 = dnaSdk.getWalletMgr().createAccount("passwordtest"); + } + + @After + public void removeWallet(){ + File file = new File(walletFile); + if(file.exists()){ + if(file.delete()){ + System.out.println("delete wallet file success"); + } + } + } + + + @Test + public void getAccount() throws Exception { + Account acct = dnaSdk.getWalletMgr().getWallet().getAccount(acct1.address); + Assert.assertNotNull(acct); + + dnaSdk.getWalletMgr().getWallet().setDefaultIdentity(id1.dnaid); + dnaSdk.getWalletMgr().getWallet().setDefaultIdentity(1); + dnaSdk.getWalletMgr().getWallet().setDefaultAccount(acct1.address); + dnaSdk.getWalletMgr().getWallet().setDefaultAccount(1); + Identity did = dnaSdk.getWalletMgr().getWallet().getIdentity(id1.dnaid); + Assert.assertNotNull(did); + boolean b = dnaSdk.getWalletMgr().getWallet().removeIdentity(id1.dnaid); + Assert.assertTrue(b); + + boolean b2 = dnaSdk.getWalletMgr().getWallet().removeAccount(acct1.address); + Assert.assertTrue(b2); + + + } + + +} \ No newline at end of file diff --git a/src/test/java/com/github/DNAProject/smartcontract/NeoVmTest.java b/src/test/java/com/github/DNAProject/smartcontract/NeoVmTest.java new file mode 100644 index 0000000..a903aa3 --- /dev/null +++ b/src/test/java/com/github/DNAProject/smartcontract/NeoVmTest.java @@ -0,0 +1,106 @@ +package com.github.DNAProject.smartcontract; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.DnaSdkTest; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.crypto.SignatureScheme; +import com.github.DNAProject.sdk.exception.SDKException; +import com.github.DNAProject.smartcontract.neovm.abi.AbiFunction; +import com.github.DNAProject.smartcontract.neovm.abi.AbiInfo; +import com.github.DNAProject.smartcontract.neovm.abi.BuildParams; +import com.github.DNAProject.smartcontract.neovm.abi.Struct; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + + +import static org.junit.Assert.*; + +public class NeoVmTest { + + DnaSdk ontSdk; + + @Before + public void setUp() throws SDKException { + + ontSdk = DnaSdk.getInstance(); + ontSdk.setRestful(DnaSdkTest.URL); + ontSdk.setDefaultConnect(ontSdk.getRestful()); + ontSdk.openWalletFile("NeoVmTest.json"); + } + + @Test + public void sendTransaction() throws Exception { + + Account account = new Account(Helper.hexToBytes(DnaSdkTest.PRIVATEKEY),SignatureScheme.SHA256WITHECDSA); + + String codeHex = "57c56b6c766b00527ac46c766b51527ac4616c766b00c307546573744d6170876c766b52527ac46c766b52c3641200616165c7006c766b53527ac462b4006c766b00c30e446573657269616c697a654d6170876c766b54527ac46c766b54c3641900616c766b51c300c3616511026c766b53527ac4627a006c766b00c30a54657374537472756374876c766b55527ac46c766b55c3641200616165e9026c766b53527ac4624b006c766b00c311446573657269616c697a65537472756374876c766b56527ac46c766b56c3641900616c766b51c300c36165cc036c766b53527ac4620e00006c766b53527ac46203006c766b53c3616c756658c56b6161681953797374656d2e53746f726167652e476574436f6e746578746c766b00527ac4c76c766b51527ac401646c766b52527ac46c766b51c3036b65796c766b52c3c4616c766b51c361681853797374656d2e52756e74696d652e53657269616c697a656c766b53527ac46c766b00c30274786c766b53c3615272681253797374656d2e53746f726167652e507574616c766b00c3027478617c681253797374656d2e53746f726167652e4765746c766b54527ac46c766b54c361681a53797374656d2e52756e74696d652e446573657269616c697a656c766b55527ac46c766b55c36416006c766b55c3036b6579c36c766b52c39c620400006c766b56527ac46c766b56c3643c00616c766b00c306726573756c740474727565615272681253797374656d2e53746f726167652e507574616c766b53c36c766b57527ac46238006c766b00c306726573756c740566616c7365615272681253797374656d2e53746f726167652e50757461006c766b57527ac46203006c766b57c3616c756656c56b6c766b00527ac4616c766b00c361681a53797374656d2e52756e74696d652e446573657269616c697a656c766b51527ac461681953797374656d2e53746f726167652e476574436f6e746578746c766b52527ac401646c766b53527ac46c766b51c36416006c766b51c3036b6579c36c766b53c39c620400006c766b54527ac46c766b54c3643800616c766b52c306726573756c740474727565615272681253797374656d2e53746f726167652e50757461516c766b55527ac46241006c766b52c306726573756c740566616c7365615272681253797374656d2e53746f726167652e507574616c766b51c3036b6579c36c766b55527ac46203006c766b55c3616c756656c56b6161681953797374656d2e53746f726167652e476574436f6e746578746c766b00527ac46152c56c766b51527ac46c766b51c307636c61696d6964517cc46c766b51c30164007cc46c766b51c361681853797374656d2e52756e74696d652e53657269616c697a656c766b52527ac46c766b00c30274786c766b52c3615272681253797374656d2e53746f726167652e507574616c766b00c3027478617c681253797374656d2e53746f726167652e4765746c766b53527ac46c766b52c300a06c766b54527ac46c766b54c3641300616c766b52c36c766b55527ac46238006c766b00c306726573756c740566616c7365615272681253797374656d2e53746f726167652e50757461006c766b55527ac46203006c766b55c3616c756656c56b6c766b00527ac4616c766b00c361681a53797374656d2e52756e74696d652e446573657269616c697a656c766b51527ac461681953797374656d2e53746f726167652e476574436f6e746578746c766b52527ac401646c766b53527ac46c766b51c36413006c766b51c300c36c766b53c39c620400006c766b54527ac46c766b54c3643800616c766b52c306726573756c740474727565615272681253797374656d2e53746f726167652e50757461516c766b55527ac4623e006c766b52c306726573756c740566616c7365615272681253797374656d2e53746f726167652e507574616c766b51c300c36c766b55527ac46203006c766b55c3616c7566"; + String abi = "{\"hash\":\"0xd97f2d441f82f132d1904d521f93f8e51d354d7c\",\"entrypoint\":\"Main\",\"functions\":[{\"name\":\"Main\",\"parameters\":[{\"name\":\"operation\",\"type\":\"String\"},{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"Any\"},{\"name\":\"TestMap\",\"parameters\":[],\"returntype\":\"Any\"},{\"name\":\"DeserializeMap\",\"parameters\":[{\"name\":\"param\",\"type\":\"ByteArray\"}],\"returntype\":\"Any\"},{\"name\":\"TestStruct\",\"parameters\":[],\"returntype\":\"Any\"},{\"name\":\"DeserializeStruct\",\"parameters\":[{\"name\":\"param\",\"type\":\"ByteArray\"}],\"returntype\":\"Any\"}],\"events\":[]}"; + abi = "{\"hash\":\"0x3c341335540c51c03bdef0f460994f99ea4659e8\",\"entrypoint\":\"Main\",\"functions\":[{\"name\":\"Main\",\"parameters\":[{\"name\":\"operation\",\"type\":\"String\"},{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"Any\"},{\"name\":\"TestMap\",\"parameters\":[],\"returntype\":\"Any\"},{\"name\":\"DeserializeMap\",\"parameters\":[{\"name\":\"param\",\"type\":\"ByteArray\"}],\"returntype\":\"Any\"},{\"name\":\"TestStruct\",\"parameters\":[],\"returntype\":\"Any\"},{\"name\":\"DeserializeStruct\",\"parameters\":[{\"name\":\"param\",\"type\":\"ByteArray\"}],\"returntype\":\"Any\"}],\"events\":[]}"; + String codeAddress = Address.AddressFromVmCode(codeHex).toHexString(); + + if(true){ + Transaction tx = ontSdk.vm().makeDeployCodeTransaction(codeHex, true, "name", + "v1.0", "author", "email", "desp", account.getAddressU160().toBase58(),30000000,0); + ontSdk.signTx(tx, new Account[][]{{account}}); + Object result = ontSdk.getConnect().sendRawTransaction(tx.toHexString()); + Thread.sleep(6000); + Object obj = ontSdk.getConnect().getContract(codeAddress); + assertTrue(obj != null); + } + if(true){ + + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + String name = "TestMap"; + AbiFunction func = abiinfo.getFunction(name); + func.name = name; + func.setParamsValue(); + Object obj = ontSdk.neovm().sendTransaction(Helper.reverse(codeAddress),null,null,0,0,func, true); + assertTrue( ((JSONObject)obj).getString("State").equals("1")); + } + if(true){ + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + String name = "DeserializeMap"; + AbiFunction func = abiinfo.getFunction(name); + func.name = name; + Map map = new HashMap<>(); + map.put("key",100); + func.setParamsValue(BuildParams.getMapBytes(map)); + Object obj = ontSdk.neovm().sendTransaction(Helper.reverse(codeAddress),null,null,0,0,func, true); + assertTrue(((JSONObject)obj).getString("State").equals("1")); + } + + //80 02 00 0164 00 07 636c61696d6964 + if(true){ + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + String name = "TestStruct"; + AbiFunction func = abiinfo.getFunction(name); + + System.out.println(func); + func.setParamsValue(); + + Object obj = ontSdk.neovm().sendTransaction(Helper.reverse(codeAddress),null,null,0,0,func, true); + assertTrue(((JSONObject)obj).getString("State").equals("1")); + + } + //80 02 00 0164 00 07 636c61696d6964 + //80 02 02 0164 00 07 636c61696d6964 + if(true){ + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + String name = "DeserializeStruct"; + AbiFunction func = abiinfo.getFunction(name); + + System.out.println(func); + func.setParamsValue(BuildParams.getStructBytes(new Struct().add(100,"claimid"))); + Object obj = ontSdk.neovm().sendTransaction(Helper.reverse(codeAddress),null,null,0,0,func, true); + assertTrue(((JSONObject)obj).getString("State").equals("1")); + } + } +} \ No newline at end of file diff --git a/src/test/java/com/github/DNAProject/smartcontract/VmTest.java b/src/test/java/com/github/DNAProject/smartcontract/VmTest.java new file mode 100644 index 0000000..3ba8f24 --- /dev/null +++ b/src/test/java/com/github/DNAProject/smartcontract/VmTest.java @@ -0,0 +1,26 @@ +package com.github.DNAProject.smartcontract; + +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.sdk.exception.SDKException; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class VmTest { + + DnaSdk ontSdk; + Vm vm; + @Before + public void setUp(){ + ontSdk = DnaSdk.getInstance(); + vm = new Vm(ontSdk); + + } + + @Test + public void buildNativeParams() throws SDKException { +// Address addr = Address.decodeBase58("TA9MXtwAcXkUMuujJh2iNRaWoXrvzfrmZb"); +// vm.buildNativeParams(addr,"init","1".getBytes(),null,0,0); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/DNAProject/smartcontract/WasmVmTest.java b/src/test/java/com/github/DNAProject/smartcontract/WasmVmTest.java new file mode 100644 index 0000000..f139cfa --- /dev/null +++ b/src/test/java/com/github/DNAProject/smartcontract/WasmVmTest.java @@ -0,0 +1,123 @@ +package com.github.DNAProject.smartcontract; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.DnaSdkTest; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.crypto.SignatureScheme; +import com.github.DNAProject.core.payload.DeployWasmCode; +import com.github.DNAProject.core.payload.InvokeWasmCode; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class WasmVmTest { + + private DnaSdk ontSdk; + + private Account payer; + + private String oep4Contract = "c3304fc12dbc38aa5c8e308b9236552523ffae0f"; + + @Before + public void setUp() throws Exception { + ontSdk = DnaSdk.getInstance(); + ontSdk.setRestful("http://127.0.0.1:20334"); + ontSdk.setDefaultConnect(ontSdk.getRestful()); +// ontSdk.openWalletFile("NeoVmTest.json"); + payer = new Account(Helper.hexToBytes(DnaSdkTest.PRIVATEKEY), SignatureScheme.SHA256WITHECDSA); + } + + @Test + public void makeDeployCodeTx() throws Exception { + String code = "0061736d01000000014c0d60037f7f7f017f60027f7f017f6000017f60017f0060027f7f0060017f017f60037f7f7f0060000060047f7f7f7f0060027e7f017f60017f017e60057f7f7f7f7f017f60047f7f7f7f017f02550403656e76126f6e74696f5f696e7075745f6c656e677468000203656e760f6f6e74696f5f6765745f696e707574000303656e760c6f6e74696f5f72657475726e000403656e760b6f6e74696f5f70616e69630004033837030305040607050607030804040500000507070404060003030001010401040903030a0b0c040001010101010405030101010401000000040501700114140504010101500608017f01418080020b070a0106696e766f6b6500090919010041010b132e2b212c33343504371c1d1e1f1b2f2526322d0a8b393702000b7b01037f230041106b220124000240410b100622020d00410b41011007000b2001420b3702042001200236020020014100410b1008200020012903003702002001280200200128020822026a220341002900bc8002370000200041086a2002410b6a360200200341076a41002800c38002360000200141106a24000b0600200010110b040000000b7b01017f0240024002402000280204220320016b20024f0d00200120026a22022001490d01200341017422012002200120024b1b22014100480d010240024020030d002001100621020c010b200028020020032001101221020b2002450d0220002001360204200020023602000b0f0b1016000b200141011007000bd00402047f017e230041306b22002400410121010240024002400240024002400240024002400240024010002202450d002002417f4c0d012002100a2201450d02200110010b410021032000410036020820002002360204200020013602002002450d0620012d00002102200041013602080240200241837e6a220141024d0d002002ad21040c080b024002400240024020010e03000102000b200041206a20004102100b20002d00204101460d08200041286a28020041014d0d0520002802243300002104410321020c020b200041206a20004104100b20002d00204101460d07200041286a28020041034d0d0520002802243500002104410521020c010b200041206a20004108100b20002d00204101460d06200041206a41086a28020041074d0d0520002802242900002104410921020b41012103200442fd01540d064103410541092004428080808010541b200442808004541b2002460d070c060b100c000b200241011007000b41f08802100d000b41808a02100d000b41b88a02100d000b20002d002121030b200041013a0020200020033a00210c010b200041206a20002004a7100b20002d00204101470d0120002d002121030b200020033a001041808002412b200041106a41ac8002100e000b200041286a28020021022000280224210302400240410c10062201450d002000420c37021420002001360210024020024105470d00200341c78002460d02200341c780024105103a450d020b41808102100d000b410c41011007000b200041206a1005200041106a200041206a100f200028021020002802181010000b0600200010140b830101037f024002400240024020012802042203200128020822046b2002490d00200420026a22052004490d0220032005490d032001280200210320012005360208200041086a2002360200200041046a200320046a360200410021010c010b200041003a0001410121010b200020013a00000f0b200420051029000b200520031020000b05001016000b5b02017f037e230041306b220124002000290208210220002902102103200029020021042001420437031020014201370204200120043703182001200141186a36020020012003370328200120023703202001200141206a1022000b7f01017f230041c0006b220424002004200136020c2004200036020820042003360214200420023602102004412c6a41023602002004413c6a41013602002004420237021c200441c48702360218200441023602342004200441306a3602282004200441106a3602382004200441086a360230200441186a41d887021022000bb90101027f20012802002102024002402001280208220141fd01490d000240200141ffff03490d00200041fe011030200020002802084104100820002000280208220341046a360208200320002802006a20013600000c020b200041fd011030200020002802084102100820002000280208220341026a360208200320002802006a20013b00000c010b2000200110300b200020002802082001100820002000280208220320016a360208200320002802006a2002200110391a0b0900200020011002000b0600200010310b0a0020002001200210130b2301017f0240200210312203450d002003200020022001200120024b1b10391a0b20030b1b01017f0240200010312201450d0020014100200010381a0b20010b05001016000b090041988102100d000b800101027f02400240024020002802042202200028020822036b20014f0d00200320016a22012003490d02200241017422032001200320014b1b22014100480d020240024020020d002001100621020c010b200028020020022001101221020b2002450d0120002001360204200020023602000b0f0b200141011007000b1016000b830301067f230041306b2202240020012802002103024002402001280204220441037422050d00410021060c010b200341046a2107410021060340200728020020066a2106200741086a2107200541786a22050d000b0b024002400240024002400240200141146a2802000d00200621070c010b024020040d0041c48102410041001019000b024002402006410f4b0d002003280204450d010b200620066a220720064f0d010b4101210541002107200241086a21060c010b2007417f4c0d01200241086a2106024020070d0041012105410021070c010b200710062205450d020b200241003602102002200736020c200220053602082002200241086a360214200241186a41106a200141106a290200370300200241186a41086a200141086a29020037030020022001290200370318200241146a41d48102200241186a101a0d0220002006290200370200200041086a200641086a280200360200200241306a24000f0b1015000b200741011007000b41ec81024133200241186a41a08202100e000b6b01017f230041306b2203240020032002360204200320013602002003411c6a41023602002003412c6a41033602002003420237020c200341f88202360208200341033602242003200341206a360218200320033602282003200341046a360220200341086a20001022000bb90801087f230041c0006b22032400200341246a2001360200200341346a200241146a2802002204360200200341033a00382003412c6a2002280210220520044103746a36020020034280808080800437030820032000360220410021062003410036021820034100360210200320053602302003200536022802400240024002400240200228020822070d0020022802002108200228020422092004200420094b1b220a450d0141012104200020082802002008280204200128020c1100000d04200841086a210241012106034002402005280200200341086a200541046a280200110100450d00410121040c060b2006200a4f0d02200241046a210020022802002101200541086a2105200241086a210241012104200641016a2106200328022020012000280200200328022428020c110000450d000c050b0b20022802002108200228020422092002410c6a2802002205200520094b1b220a450d0041012104200020082802002008280204200128020c1100000d03200741106a2105200841086a21024101210603402003200541786a28020036020c2003200541106a2d00003a003820032005417c6a28020036020841002101410021040240024002400240200541086a2802000e0400010203000b2005410c6a2802002100410121040c020b02402005410c6a2802002207200328023422044f0d0041002104200328023020074103746a22072802044104470d0220072802002802002100410121040c020b41b88602200720041019000b4100210420032802282207200328022c460d002003200741086a3602284100210420072802044104470d0020072802002802002100410121040b2003200036021420032004360210024002400240024002400240024020052802000e0404010006040b20032802282200200328022c470d010c050b200541046a2802002200200328023422044f0d01200328023020004103746a22002802044104470d04200028020028020021040c030b2003200041086a36022820002802044104470d03200028020028020021040c020b41b88602200020041019000b200541046a28020021040b410121010b2003200436021c2003200136021802400240200541706a2802004101460d0020032802282204200328022c460d042003200441086a3602280c010b200541746a2802002204200328023422004f0d04200328023020044103746a21040b02402004280200200341086a200441046a280200110100450d00410121040c050b2006200a4f0d01200241046a210020022802002101200541246a2105200241086a210241012104200641016a2106200328022020012000280200200328022428020c110000450d000c040b0b0240200920064d0d00410121042003280220200820064103746a22052802002005280204200328022428020c1100000d030b410021040c020b41a08602100d000b41c88602200420001019000b200341c0006a240020040b02000b02000b2f01017f200028020022002002101720002000280208220320026a360208200320002802006a2001200210391a41000bcb0201027f230041106b220224002000280200210002400240024002402001418001490d002002410036020c2001418010490d0102402001418080044f0d0020022001413f71418001723a000e20022001410676413f71418001723a000d20022001410c76410f7141e001723a000c410321010c030b20022001413f71418001723a000f2002200141127641f001723a000c20022001410676413f71418001723a000e20022001410c76413f71418001723a000d410421010c020b0240200028020822032000280204470d00200041011017200028020821030b200028020020036a20013a00002000200028020841016a3602080c020b20022001413f71418001723a000d20022001410676411f7141c001723a000c410221010b20002001101720002000280208220320016a360208200320002802006a2002410c6a200110391a0b200241106a240041000b6201017f230041206b2202240020022000280200360204200241086a41106a200141106a290200370300200241086a41086a200141086a29020037030020022001290200370308200241046a41d48102200241086a101a2101200241206a240020010b6d01017f230041306b2202240020022001360204200220003602002002411c6a41023602002002412c6a41033602002002420237020c200241948502360208200241033602242002200241206a3602182002200241046a36022820022002360220200241086a41a485021022000b0b002000350200200110230b4602017f017e230041206b2202240020012902002103200241146a20012902083702002002200337020c200220003602082002418883023602042002410136020020021024000bcd0203027f017e037f230041306b22022400412721030240024020004290ce005a0d00200021040c010b412721030340200241096a20036a2205417c6a200020004290ce0080220442f0b17f7e7ca7220641ffff037141e4006e220741017441ca83026a2f00003b00002005417e6a2007419c7f6c20066a41ffff037141017441ca83026a2f00003b00002003417c6a2103200042ffc1d72f5621052004210020050d000b0b02402004a7220541e3004c0d00200241096a2003417e6a22036a2004a7220641ffff037141e4006e2205419c7f6c20066a41ffff037141017441ca83026a2f00003b00000b024002402005410a480d00200241096a2003417e6a22036a200541017441ca83026a2f00003b00000c010b200241096a2003417f6a22036a200541306a3a00000b200141ac88024100200241096a20036a412720036b10272103200241306a240020030bbe0201027f230041e0006b220124000240024002400240200028020822020d00200141003602300c010b20012002360200200141dc006a41013602002001420137024c200141a48802360248200141053602242001200141206a36025820012001360220200141306a200141c8006a101820012802300d010b20014100360208200142013703000c010b200141086a200141306a41086a280200360200200120012903303703000b200041146a28020021022001200029020c3703102001200236021c200141306a41146a4103360200200141c8006a41146a4103360200200141d4006a410636020020014203370234200141ac88023602302001410736024c2001200141c8006a36024020012001411c6a3602582001200141106a36025020012001360248200141206a200141306a1018200128022020012802281036000b02000b0c00428fa2e88daad0abe05a0bc50501067f20002802002205410171220620046a21070240024020054104710d00410021010c010b4100210802402002450d00200221092001210a03402008200a2d000041c00171418001466a2108200a41016a210a2009417f6a22090d000b0b200720026a20086b21070b412b418080c40020061b21080240024020002802084101460d004101210a200020082001200210280d012000280218200320042000411c6a28020028020c1100000f0b02402000410c6a280200220920074b0d004101210a200020082001200210280d012000280218200320042000411c6a28020028020c1100000f0b0240024020054108710d00200920076b21094100210a024002400240410120002d0030220720074103461b0e0402000100020b2009210a410021090c010b2009410176210a200941016a41017621090b200a41016a210a0340200a417f6a220a450d0220002802182000280204200028021c280210110100450d000b41010f0b4101210a200041013a003020004130360204200020082001200210280d01200920076b21084100210a024002400240410120002d0030220920094103461b0e0402000100020b2008210a410021080c010b2008410176210a200841016a41017621080b200a41016a210a02400340200a417f6a220a450d0120002802182000280204200028021c280210110100450d000b41010f0b200028020421094101210a200028021820032004200028021c28020c1100000d01200841016a2108200028021c210220002802182100034002402008417f6a22080d0041000f0b4101210a200020092002280210110100450d000c020b0b200028020421074101210a200020082001200210280d00200028021820032004200028021c28020c1100000d00200941016a2108200028021c210920002802182100034002402008417f6a22080d0041000f0b4101210a200020072009280210110100450d000b0b200a0b5401017f024002402001418080c400460d0041012104200028021820012000411c6a2802002802101101000d010b024020020d0041000f0b2000280218200220032000411c6a28020028020c11000021040b20040b6d01017f230041306b2202240020022001360204200220003602002002411c6a41023602002002412c6a41033602002002420237020c200241dc8502360208200241033602242002200241206a3602182002200241046a36022820022002360220200241086a41ec85021022000b8307010c7f200028021021030240024002400240200028020822044101460d0020030d012000280218200120022000411c6a28020028020c11000021030c030b2003450d010b0240024020020d00410021020c010b200120026a2105200041146a28020041016a21064100210720012103200121080340200341016a210902400240024020032c0000220a417f4a0d000240024020092005470d004100210b200521030c010b20032d0001413f71210b200341026a220921030b200a411f71210c0240200a41ff0171220a41df014b0d00200b200c41067472210a0c020b0240024020032005470d004100210d2005210e0c010b20032d0000413f71210d200341016a2209210e0b200d200b41067472210b0240200a41f0014f0d00200b200c410c7472210a0c020b02400240200e2005470d004100210a200921030c010b200e41016a2103200e2d0000413f71210a0b200b410674200c411274418080f0007172200a72220a418080c400470d020c040b200a41ff0171210a0b200921030b02402006417f6a2206450d00200720086b20036a21072003210820052003470d010c020b0b200a418080c400460d00024002402007450d0020072002460d0041002103200720024f0d01200120076a2c00004140480d010b200121030b2007200220031b21022003200120031b21010b20040d002000280218200120022000411c6a28020028020c1100000f0b4100210902402002450d002002210a200121030340200920032d000041c00171418001466a2109200341016a2103200a417f6a220a0d000b0b0240200220096b200028020c2206490d002000280218200120022000411c6a28020028020c1100000f0b410021074100210902402002450d00410021092002210a200121030340200920032d000041c00171418001466a2109200341016a2103200a417f6a220a0d000b0b200920026b20066a210a024002400240410020002d0030220320034103461b0e0402000100020b200a21074100210a0c010b200a4101762107200a41016a410176210a0b200741016a2103024003402003417f6a2203450d0120002802182000280204200028021c280210110100450d000b41010f0b2000280204210941012103200028021820012002200028021c28020c1100000d00200a41016a2103200028021c210a20002802182100034002402003417f6a22030d0041000f0b20002009200a280210110100450d000b41010f0b20030b1000200120002802002000280204102a0b0b002000350200200110230b1b00200128021841b68702410e2001411c6a28020028020c1100000b140020002802002001200028020428020c1101000b1b00200128021841fd870241052001411c6a28020028020c1100000b3f01017f0240200028020822022000280204470d002000200241011008200028020821020b200028020020026a20013a00002000200028020841016a3602080bd30101047f230041106b22012400024041002802a08b020d004100417f3602a08b020240024041002802a48b02220220006a220341002802a88b0222044d0d000240200320046b41ffff036a220441107640002202417f470d00410021020c020b20024110742103024041002802a48b0222020d00410020033602a48b02200321020b4100200320044180807c716a3602a88b02200220006a21030b410020033602a48b020b410041002802a08b0241016a3602a08b02200141106a240020020f0b418288024110200141086a41948802100e000b02000b6901037f230041206b220224002001411c6a280200210320012802182104200241086a41106a2000280200220141106a290200370300200241086a41086a200141086a2902003703002002200129020037030820042003200241086a101a2101200241206a240020010b1000200120002802002000280204102a0b1000200120002802002000280208102a0b0900200020011003000bd00101017f230041106b22022400024002400240024020002d00000e03010200010b2002200128021841c98802410b2001411c6a28020028020c11000022003a000820022001360200200241003a0009200241003602040c020b2002200128021841d48802410d2001411c6a28020028020c11000022003a000820022001360200200241003a0009200241003602040c010b2002200128021841e18802410d2001411c6a28020028020c11000022003a000820022001360200200241003a0009200241003602040b200241106a240020000b2c01017f02402002450d00200021030340200320013a0000200341016a21032002417f6a22020d000b0b20000b3601017f02402002450d00200021030340200320012d00003a0000200341016a2103200141016a21012002417f6a22020d000b0b20000b4a01037f4100210302402002450d000240034020002d0000220420012d00002205470d01200141016a2101200041016a21002002417f6a2202450d020c000b0b200420056b21030b20030b0ba80b0100418080020b9f0b63616c6c65642060526573756c743a3a756e77726170282960206f6e20616e2060457272602076616c7565000800000001000000010000000900000068656c6c6f20776f726c6468656c6c6f756e737570706f7274656420616374696f6e216578616d706c65732f68656c6c6f776f726c642f7372632f6c69622e72730000004c800000130000005f8000001e000000140000000e000000b080000011000000708500001700000009030000050000006361706163697479206f766572666c6f77000000308100004600000063010000130000000a00000004000000040000000b0000000c0000000d0000006120666f726d617474696e6720747261697420696d706c656d656e746174696f6e2072657475726e656420616e206572726f72000e00000000000000010000000f0000002f72757374632f373937393031366166663534356637623431636335313730333130323630323062333430393839642f7372632f6c6962636f72652f666d742f6d6f642e727300009881000020000000b88100001200000010000000000000000100000011000000696e646578206f7574206f6620626f756e64733a20746865206c656e20697320206275742074686520696e6465782069732030303031303230333034303530363037303830393130313131323133313431353136313731383139323032313232323332343235323632373238323933303331333233333334333533363337333833393430343134323433343434353436343734383439353035313532353335343535353635373538353936303631363236333634363536363637363836393730373137323733373437353736373737383739383038313832383338343835383638373838383939303931393239333934393539363937393839390000b482000006000000ba820000220000008785000018000000180a000005000000696e64657820206f7574206f662072616e676520666f7220736c696365206f66206c656e67746820fc82000016000000128300000d00000087850000180000001e0a000005000000736c69636520696e64657820737461727473206174202062757420656e64732061742000768300002b000000a1830000150000007a01000015000000608300001600000060040000110000006083000016000000540400002800000000000000000000007372632f6c6962636f72652f666d742f6d6f642e727363616c6c656420604f7074696f6e3a3a756e77726170282960206f6e206120604e6f6e65602076616c75657372632f6c6962636f72652f6f7074696f6e2e7273426f72726f774d75744572726f722c84000000000000d4830000020000003a200000e8830000150000008d040000050000007372632f6c6962636f72652f726573756c742e72734572726f72616c726561647920626f72726f7765640000120000000000000001000000130000002c840000000000002c8400000000000044840000040000004884000001000000206174203a496e76616c696455746638556e6578706563746564454f464972726567756c61724461746100008884000020000000a8840000550000007f08000009000000617373657274696f6e206661696c65643a2032203c3d206275662e6c656e28292f686f6d652f6e6173682f2e636172676f2f72656769737472792f7372632f6769746875622e636f6d2d316563633632393964623965633832332f627974656f726465722d312e332e322f7372632f6c69622e72730000001885000020000000a8840000550000008408000009000000617373657274696f6e206661696c65643a2034203c3d206275662e6c656e28295085000020000000a8840000550000008908000009000000617373657274696f6e206661696c65643a2038203c3d206275662e6c656e28297372632f6c6962616c6c6f632f7261775f7665632e72737372632f6c6962636f72652f736c6963652f6d6f642e7273"; + String contractHash = "259eed30d30d7c473944760023fcc321b8966371"; + Assert.assertEquals(contractHash, Address.AddressFromVmCode(code).toHexString()); + DeployWasmCode tx = ontSdk.wasmvm().makeDeployCodeTransaction(code, "helloWorld", "1.0", "NashMiao", + "wdx7266@vip.qq.com", "wasm contract for java sdk test", payer.getAddressU160(), + 500, 25000000); + JSONObject result = (JSONObject) ontSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); + Assert.assertEquals(1, result.getIntValue("State")); + } + + @Test + public void makeAddInvokeCodeTx() throws Exception { + String contractHash = "bf8ee176c360f7a77b9c45b6faab213bc50eaf5d"; + List params = new ArrayList<>(Arrays.asList(1, 2)); + InvokeWasmCode tx = ontSdk.wasmvm().makeInvokeCodeTransaction(contractHash, "add", params, payer.getAddressU160(), 500, 25000000); + String targetPayload = "5daf0ec53b21abfab6459c7ba7f760c376e18ebf24036164640100000000000000000000000000000002000000000000000000000000000000"; + Assert.assertEquals(targetPayload, Helper.toHexString(tx.invokeCode)); + ontSdk.signTx(tx, new Account[][]{{payer}}); + JSONObject result = (JSONObject) ontSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); + Assert.assertEquals("03000000000000000000000000000000", result.getString("Result")); + params = new ArrayList<>(Arrays.asList(-2, 3)); + tx = ontSdk.wasmvm().makeInvokeCodeTransaction(contractHash, "add", params, payer.getAddressU160(), 500, 25000000); + targetPayload = "5daf0ec53b21abfab6459c7ba7f760c376e18ebf2403616464feffffffffffffffffffffffffffffff03000000000000000000000000000000"; + Assert.assertEquals(targetPayload, Helper.toHexString(tx.invokeCode)); + ontSdk.signTx(tx, new Account[][]{{payer}}); + result = (JSONObject) ontSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); + Assert.assertEquals("01000000000000000000000000000000", result.getString("Result")); + } + + @Test + public void makeNotifyInvokeCodeTx() throws Exception { + String contractHash = "bf8ee176c360f7a77b9c45b6faab213bc50eaf5d"; + List params = new ArrayList<>(); + InvokeWasmCode tx = ontSdk.wasmvm().makeInvokeCodeTransaction(contractHash, "notify", params, payer.getAddressU160(), 500, 25000000); + String targetPayload = "5daf0ec53b21abfab6459c7ba7f760c376e18ebf07066e6f74696679"; + Assert.assertEquals(targetPayload, Helper.toHexString(tx.invokeCode)); + ontSdk.signTx(tx, new Account[][]{{payer}}); + JSONObject result = (JSONObject) ontSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); + Assert.assertEquals("hello", result.getJSONArray("Notify").getJSONObject(0).getJSONArray("States").get(0)); + } + + @Test + public void makeBalanceOfInvokeCodeTx() throws Exception { + List params = new ArrayList<>(Collections.singletonList(Address.decodeBase58("ANDfjwrUroaVtvBguDtrWKRMyxFwvVwnZD"))); + InvokeWasmCode tx = ontSdk.wasmvm().makeInvokeCodeTransaction(oep4Contract, "balanceOf", params, payer.getAddressU160(), 500, 25000000); + String targetPayload = "0faeff23255536928b308e5caa38bc2dc14f30c31e0962616c616e63654f6646b1a18af6b7c9f8a4602f9f73eeb3030f0c29b7"; + Assert.assertEquals(targetPayload, Helper.toHexString(tx.invokeCode)); + ontSdk.signTx(tx, new Account[][]{{payer}}); + JSONObject result = (JSONObject) ontSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); + System.out.println(JSON.toJSONString(result)); + //Assert.assertEquals("00e87648170000000000000000000000", result.getString("Result")); + } + + @Test + public void makeTotalSupplyInvokeCodeTx() throws Exception { + List params = new ArrayList<>(); + InvokeWasmCode tx = ontSdk.wasmvm().makeInvokeCodeTransaction(oep4Contract, "totalSupply", params, payer.getAddressU160(), 500, 25000000); + String targetPayload = "0faeff23255536928b308e5caa38bc2dc14f30c30c0b746f74616c537570706c79"; + Assert.assertEquals(targetPayload, Helper.toHexString(tx.invokeCode)); + ontSdk.signTx(tx, new Account[][]{{payer}}); + JSONObject result = (JSONObject) ontSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); + Assert.assertEquals("00e87648170000000000000000000000", result.getString("Result")); + } + + @Test + public void makeTransferInvokeCodeTx() throws Exception { + List params = new ArrayList<>(Arrays.asList(payer.getAddressU160(), Address.decodeBase58("AazEvfQPcQ2GEFFPLF1ZLwQ7K5jDn81hve"), 10)); + InvokeWasmCode tx = ontSdk.wasmvm().makeInvokeCodeTransaction(oep4Contract, "transfer", params, payer.getAddressU160(), 500, 25000000); + String targetPayload = "0faeff23255536928b308e5caa38bc2dc14f30c341087472616e73666572d2c124dd088190f709b684e0bc676d70c41b3776d2c124dd088190f709b684e0bc676d70c41b37760a000000000000000000000000000000"; + Assert.assertEquals(targetPayload, Helper.toHexString(tx.invokeCode)); + ontSdk.signTx(tx, new Account[][]{{payer}}); + JSONObject result = (JSONObject) ontSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); + Assert.assertEquals("01", result.getString("Result")); + Assert.assertEquals(1, result.getIntValue("State")); + JSONObject notify = result.getJSONArray("Notify").getJSONObject(1); + Assert.assertEquals(oep4Contract, notify.getString("ContractAddress")); + Assert.assertEquals("7472616e73666572", notify.getJSONArray("States").getString(0)); + Assert.assertEquals("d2c124dd088190f709b684e0bc676d70c41b3776", notify.getJSONArray("States").getString(1)); + Assert.assertEquals("d2c124dd088190f709b684e0bc676d70c41b3776", notify.getJSONArray("States").getString(2)); + Assert.assertEquals("0a000000000000000000000000000000", notify.getJSONArray("States").getString(3)); + } + +} diff --git a/src/test/java/com/github/DNAProject/smartcontract/nativevm/AuthTest.java b/src/test/java/com/github/DNAProject/smartcontract/nativevm/AuthTest.java new file mode 100644 index 0000000..f028f05 --- /dev/null +++ b/src/test/java/com/github/DNAProject/smartcontract/nativevm/AuthTest.java @@ -0,0 +1,167 @@ +package com.github.DNAProject.smartcontract.nativevm; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.DnaSdkTest; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.payload.DeployCode; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.crypto.SignatureScheme; +import com.github.DNAProject.sdk.wallet.Identity; +import com.github.DNAProject.smartcontract.neovm.abi.AbiFunction; +import com.github.DNAProject.smartcontract.neovm.abi.AbiInfo; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; + +import static org.junit.Assert.*; + +public class AuthTest { + + DnaSdk sdk; + String codeHex; + String codeAddress; + String abi; + Account account; + String password; + String walletFile = "AuthTest.json"; + Identity adminIdentity; + Identity identity; + Identity identity2; + + @Before + public void setUp() throws Exception { + sdk = DnaSdk.getInstance(); + sdk.setRestful(DnaSdkTest.URL); + sdk.setDefaultConnect(sdk.getRestful()); + sdk.openWalletFile(walletFile); + codeHex = "57c56b6c766b00527ac46c766b51527ac4616c766b00c304696e6974876c766b52527ac46c766b52c3641100616509016c766b53527ac46294006c766b00c30a717565727961646d696e876c766b54527ac46c766b54c3641100616598006c766b53527ac46266006c766b00c303666f6f876c766b55527ac46c766b55c3644200616c766b00c36c766b51c3617c655d01009c6c766b56527ac46c766b56c3640e00006c766b53527ac46221006c766b51c3616521006c766b53527ac4620e00006c766b53527ac46203006c766b53c3616c756652c56b6c766b00527ac461516c766b51527ac46203006c766b51c3616c756651c56b61612a6469643a6f6e743a41617a457666515063513247454646504c46315a4c7751374b356a446e38316876656c766b00527ac46203006c766b00c3616c756653c56b611400000000000000000000000000000000000000066c766b00527ac4006c766b00c311696e6974436f6e747261637441646d696e612a6469643a6f6e743a41617a457666515063513247454646504c46315a4c7751374b356a446e383168766561537951795572755172755279527954727552727568164f6e746f6c6f67792e4e61746976652e496e766f6b656c766b51527ac46c766b51c300517f519c6c766b52527ac46203006c766b52c3616c756657c56b6c766b00527ac46c766b51527ac461556154c66c766b527a527ac46c766b55c36c766b52527ac46c766b52c361682d53797374656d2e457865637574696f6e456e67696e652e476574457865637574696e6753637269707448617368007cc46c766b52c36c766b00c3527cc46c766b52c36c766b51c300c3517cc46c766b52c36c766b51c351c3537cc41400000000000000000000000000000000000000066c766b53527ac4006c766b53c30b766572696679546f6b656e6c766b52c361537951795572755172755279527954727552727568164f6e746f6c6f67792e4e61746976652e496e766f6b656c766b54527ac46c766b54c300517f519c6c766b56527ac46203006c766b56c3616c7566"; + codeAddress = Address.AddressFromVmCode(codeHex).toHexString(); + abi = "{\"hash\":\"0x3acea0d75537d14762b692dc7e3c62b98975fa50\",\"entrypoint\":\"Main\",\"functions\":[{\"name\":\"Main\",\"parameters\":[{\"name\":\"operation\",\"type\":\"String\"},{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"Any\"},{\"name\":\"foo\",\"parameters\":[{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"Boolean\"},{\"name\":\"queryadmin\",\"parameters\":[],\"returntype\":\"ByteArray\"},{\"name\":\"init\",\"parameters\":[],\"returntype\":\"Boolean\"}],\"events\":[]}"; + account = new Account(Helper.hexToBytes(DnaSdkTest.PRIVATEKEY),SignatureScheme.SHA256WITHECDSA); + password = "111111"; + adminIdentity = sdk.getWalletMgr().createIdentityFromPriKey(password,DnaSdkTest.PRIVATEKEY); + identity = sdk.getWalletMgr().createIdentityFromPriKey(password,DnaSdkTest.PRIVATEKEY2); + identity2 = sdk.getWalletMgr().createIdentityFromPriKey(password,DnaSdkTest.PRIVATEKEY3); + + codeHex = "5ac56b6c766b00527ac46c766b51527ac4616c766b00c304696e6974876c766b52527ac46c766b52c3641100616580016c766b53527ac46222016c766b00c303666f6f876c766b54527ac46c766b54c3644400616c766b00c36c766b51c3617c650202009c6c766b55527ac46c766b55c3641500076e6f20617574686c766b53527ac462d6006165db006c766b53527ac462c8006c766b00c304666f6f32876c766b56527ac46c766b56c3644400616c766b00c36c766b51c3617c65a701009c6c766b57527ac46c766b57c3641500076e6f20617574686c766b53527ac4627b00616599006c766b53527ac4626d006c766b00c304666f6f33876c766b58527ac46c766b58c3644400616c766b00c36c766b51c3617c654c01009c6c766b59527ac46c766b59c3641500076e6f20617574686c766b53527ac4622000616557006c766b53527ac4621200046f7665726c766b53527ac46203006c766b53c3616c756651c56b6101416c766b00527ac46203006c766b00c3616c756651c56b6101426c766b00527ac46203006c766b00c3616c756651c56b6101436c766b00527ac46203006c766b00c3616c756653c56b611400000000000000000000000000000000000000066c766b00527ac4006c766b00c311696e6974436f6e747261637441646d696e612a6469643a6f6e743a41617a457666515063513247454646504c46315a4c7751374b356a446e383168766561537951795572755172755279527954727552727568164f6e746f6c6f67792e4e61746976652e496e766f6b656c766b51527ac46c766b51c300517f519c6c766b52527ac46203006c766b52c3616c756657c56b6c766b00527ac46c766b51527ac461556154c66c766b527a527ac46c766b55c36c766b52527ac46c766b52c361682d53797374656d2e457865637574696f6e456e67696e652e476574457865637574696e6753637269707448617368007cc46c766b52c36c766b00c3527cc46c766b52c36c766b51c300c3517cc46c766b52c36c766b51c351c3537cc41400000000000000000000000000000000000000066c766b53527ac4006c766b53c30b766572696679546f6b656e6c766b52c361537951795572755172755279527954727552727568164f6e746f6c6f67792e4e61746976652e496e766f6b656c766b54527ac46c766b54c300517f519c6c766b56527ac46203006c766b56c3616c7566"; + codeAddress = Address.AddressFromVmCode(codeHex).toHexString(); + abi = "{\"hash\":\"0xbc9795db0abe9d2d9ea565286a237dbf6b407165\",\"entrypoint\":\"Main\",\"functions\":[{\"name\":\"Main\",\"parameters\":[{\"name\":\"operation\",\"type\":\"String\"},{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"Any\"},{\"name\":\"foo\",\"parameters\":[],\"returntype\":\"String\"},{\"name\":\"foo2\",\"parameters\":[],\"returntype\":\"String\"},{\"name\":\"foo3\",\"parameters\":[],\"returntype\":\"String\"},{\"name\":\"init\",\"parameters\":[],\"returntype\":\"Boolean\"}],\"events\":[]}"; + } + + @After + public void removeWallet(){ + File file = new File(walletFile); + if(file.exists()){ + if(file.delete()){ + System.out.println("delete wallet file success"); + } + } + } + + @Test + public void test() throws Exception { + sdk.nativevm().dnaId().sendRegister(adminIdentity,password,account,sdk.DEFAULT_GAS_LIMIT,0); + sdk.nativevm().dnaId().sendRegister(identity,password,account,sdk.DEFAULT_GAS_LIMIT,0); + sdk.nativevm().dnaId().sendRegister(identity2,password,account,sdk.DEFAULT_GAS_LIMIT,0); + Transaction tx = sdk.vm().makeDeployCodeTransaction(codeHex, true, "name", + "v1.0", "author", "email", "desp", account.getAddressU160().toBase58(),20000000,0); + sdk.vm().setCodeAddress(codeAddress); + sdk.signTx(tx, new Account[][]{{account}}); + String txHex = Helper.toHexString(tx.toArray()); + Object result = sdk.getConnect().sendRawTransaction(txHex); + Thread.sleep(6000); + DeployCode t = (DeployCode) sdk.getConnect().getTransaction(tx.hash().toHexString()); + assertNotNull(t); + } + + @Test + public void sendTransfer() throws Exception { + String txhash = sdk.nativevm().auth().sendTransfer(identity.dnaid,password,identity.controls.get(0).getSalt(),1,codeAddress,adminIdentity.dnaid,account,sdk.DEFAULT_GAS_LIMIT,0); + Thread.sleep(6000); + Object obj = sdk.getConnect().getSmartCodeEvent(txhash); + assertTrue(((JSONObject)obj).getString("State").equals("1")); + } + + @Test + public void initTest() throws Exception { + + AbiInfo abiInfo = JSON.parseObject(abi,AbiInfo.class); + String name = "init"; + AbiFunction function = abiInfo.getFunction(name); + function.setParamsValue(); + String txhash = (String) sdk.neovm().sendTransaction(Helper.reverse(codeAddress),account,account,sdk.DEFAULT_GAS_LIMIT,0,function,false); + Thread.sleep(6000); + Object obj = sdk.getConnect().getSmartCodeEvent(txhash); + System.out.println(obj); + } + + @Test + public void queryAdmin() throws Exception { + AbiInfo abiInfo = JSON.parseObject(abi,AbiInfo.class); + String name = "queryadmin"; + AbiFunction function = abiInfo.getFunction(name); + function.setParamsValue(); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(codeAddress),account,account,sdk.DEFAULT_GAS_LIMIT,0,function,true); + String res = ((JSONObject)obj).getString("Result"); + String aa = new String(Helper.hexToBytes(res)); + assertTrue("did:ont:AazEvfQPcQ2GEFFPLF1ZLwQ7K5jDn81hve".equals(aa)); + } + + + @Test + public void assignFuncsToRole2() throws Exception { + String txhash = sdk.nativevm().auth().assignFuncsToRole(adminIdentity.dnaid, password, adminIdentity.controls.get(0).getSalt(), + 1, Helper.reverse(codeAddress), "role1", new String[]{"foo1"}, account, sdk.DEFAULT_GAS_LIMIT, 0); + + String txhash2 = sdk.nativevm().auth().assignFuncsToRole(adminIdentity.dnaid, password, adminIdentity.controls.get(0).getSalt(), 1, + Helper.reverse(codeAddress), "role2", new String[]{"foo2","foo3"}, account, sdk.DEFAULT_GAS_LIMIT, 0); + Thread.sleep(6000); + Object obj = sdk.getConnect().getSmartCodeEvent(txhash); + assertTrue(((JSONObject) obj).getString("State").equals("1")); + obj = sdk.getConnect().getSmartCodeEvent(txhash2); + assertTrue(((JSONObject) obj).getString("State").equals("1")); + txhash = sdk.nativevm().auth().assignDnaIdsToRole(adminIdentity.dnaid, password, adminIdentity.controls.get(0).getSalt(), 1, Helper.reverse(codeAddress), "role1", new String[]{identity2.dnaid}, account, sdk.DEFAULT_GAS_LIMIT, 0); + Thread.sleep(6000); + obj = sdk.getConnect().getSmartCodeEvent(txhash); + assertTrue(((JSONObject) obj).getString("State").equals("1")); + String result = sdk.nativevm().auth().verifyToken(identity2.dnaid, password, identity2.controls.get(0).getSalt(), 1, Helper.reverse(codeAddress), "foo1"); + assertTrue(result.equals("01")); + } + + + @Test + public void assignFuncsToRole() throws Exception { + String txhash = sdk.nativevm().auth().assignFuncsToRole(adminIdentity.dnaid, password, adminIdentity.controls.get(0).getSalt(), 1, Helper.reverse(codeAddress), "role", new String[]{"foo"}, account, sdk.DEFAULT_GAS_LIMIT, 0); + Thread.sleep(6000); + Object obj = sdk.getConnect().getSmartCodeEvent(txhash); + assertTrue(((JSONObject) obj).getString("State").equals("1")); + txhash = sdk.nativevm().auth().assignDnaIdsToRole(adminIdentity.dnaid, password, adminIdentity.controls.get(0).getSalt(), 1, Helper.reverse(codeAddress), "role", new String[]{identity2.dnaid}, account, sdk.DEFAULT_GAS_LIMIT, 0); + Thread.sleep(6000); + obj = sdk.getConnect().getSmartCodeEvent(txhash); + assertTrue(((JSONObject) obj).getString("State").equals("1")); + String result = sdk.nativevm().auth().verifyToken(identity2.dnaid, password, identity2.controls.get(0).getSalt(), 1, Helper.reverse(codeAddress), "foo"); + assertTrue(result.equals("01")); + } + + @Test + public void delegate() throws Exception { + sdk.nativevm().auth().delegate(identity2.dnaid,password,identity2.controls.get(0).getSalt(),1,Helper.reverse(codeAddress),identity.dnaid,"role",60*5,1,account,sdk.DEFAULT_GAS_LIMIT,0); + Thread.sleep(6000); + sdk.nativevm().auth().withdraw(identity2.dnaid,password,identity2.controls.get(0).getSalt(),1,Helper.reverse(codeAddress),identity.dnaid,"role1",account,sdk.DEFAULT_GAS_LIMIT,0); + String result = sdk.nativevm().auth().verifyToken(identity2.dnaid, password, identity2.controls.get(0).getSalt(), 1, Helper.reverse(codeAddress), "foo"); + String result2 = sdk.nativevm().auth().verifyToken(identity.dnaid, password, identity.controls.get(0).getSalt(), 1, Helper.reverse(codeAddress), "foo"); + assertTrue(result2.equals("01")); + } + + @Test + public void verifyToken() throws Exception { + String result2 = sdk.nativevm().auth().verifyToken(identity.dnaid, password, identity.controls.get(0).getSalt(), 1, Helper.reverse(codeAddress), "foo"); + assertTrue(result2.equals("01")); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/DNAProject/smartcontract/nativevm/GasTest.java b/src/test/java/com/github/DNAProject/smartcontract/nativevm/GasTest.java new file mode 100644 index 0000000..c59c261 --- /dev/null +++ b/src/test/java/com/github/DNAProject/smartcontract/nativevm/GasTest.java @@ -0,0 +1,78 @@ +package com.github.DNAProject.smartcontract.nativevm; +import com.github.DNAProject.DnaSdkTest; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.DnaSdkTest; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.crypto.SignatureScheme; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class GasTest { + + public String password = "111111"; + DnaSdk ontSdk; + Account account; + Account receiveAcc; + + @Before + public void setUp() throws Exception { + ontSdk=DnaSdk.getInstance(); + ontSdk.setRestful(DnaSdkTest.URL); + account = new Account(Helper.hexToBytes(DnaSdkTest.PRIVATEKEY),SignatureScheme.SHA256WITHECDSA); + receiveAcc = new Account(SignatureScheme.SHA256WITHECDSA); + ontSdk.nativevm().gas().sendTransfer(account,receiveAcc.getAddressU160().toBase58(),10L,account,ontSdk.DEFAULT_GAS_LIMIT,0); + Thread.sleep(6000); + + String accountOng = ontSdk.nativevm().gas().unboundGas(account.getAddressU160().toBase58()); + ontSdk.nativevm().gas().withdrawGas(account,account.getAddressU160().toBase58(),1000,account,ontSdk.DEFAULT_GAS_LIMIT,0); + Thread.sleep(6000); + Object obj = ontSdk.getConnect().getBalance(account.getAddressU160().toBase58()); + System.out.println(obj); + } + @Test + public void sendTransfer() throws Exception { + long accountOng = ontSdk.nativevm().gas().queryBalanceOf(account.getAddressU160().toBase58()); + long receiveAccOng = ontSdk.nativevm().gas().queryBalanceOf(receiveAcc.getAddressU160().toBase58()); + ontSdk.nativevm().gas().sendTransfer(account,receiveAcc.getAddressU160().toBase58(),10L,account,ontSdk.DEFAULT_GAS_LIMIT,0); + Thread.sleep(6000); + long accountOng2 = ontSdk.nativevm().gas().queryBalanceOf(account.getAddressU160().toBase58()); + long receiveAccOng2 = ontSdk.nativevm().gas().queryBalanceOf(receiveAcc.getAddressU160().toBase58()); + Assert.assertTrue(accountOng-accountOng2 == 10); + Assert.assertTrue(receiveAccOng2-receiveAccOng == 10); + } + + + @Test + public void sendApprove() throws Exception { + long allowance = ontSdk.nativevm().gas().queryAllowance(account.getAddressU160().toBase58(),receiveAcc.getAddressU160().toBase58()); + ontSdk.nativevm().gas().sendApprove(account,receiveAcc.getAddressU160().toBase58(),10,account,ontSdk.DEFAULT_GAS_LIMIT,0); + Thread.sleep(6000); + long allowance2 = ontSdk.nativevm().gas().queryAllowance(account.getAddressU160().toBase58(),receiveAcc.getAddressU160().toBase58()); + Assert.assertTrue(allowance2-allowance == 10); + + long acctbalance = ontSdk.nativevm().gas().queryBalanceOf(account.getAddressU160().toBase58()); + long reciebalance = ontSdk.nativevm().gas().queryBalanceOf(receiveAcc.getAddressU160().toBase58()); + ontSdk.nativevm().gas().sendTransferFrom(receiveAcc,account.getAddressU160().toBase58(),receiveAcc.getAddressU160().toBase58(),10,receiveAcc,ontSdk.DEFAULT_GAS_LIMIT,0); + Thread.sleep(6000); + long acctbalance2 = ontSdk.nativevm().gas().queryBalanceOf(account.getAddressU160().toBase58()); + long reciebalance2 = ontSdk.nativevm().gas().queryBalanceOf(receiveAcc.getAddressU160().toBase58()); + Assert.assertTrue(acctbalance-acctbalance2 == 10); + Assert.assertTrue(reciebalance2 - reciebalance == 10); + long allowance3 = ontSdk.nativevm().gas().queryAllowance(account.getAddressU160().toBase58(),receiveAcc.getAddressU160().toBase58()); + Assert.assertTrue(allowance3 == allowance); + } + + @Test + public void queryName() throws Exception { + String name = ontSdk.nativevm().gas().queryName(); + String symbol = ontSdk.nativevm().gas().querySymbol(); + long decimals = ontSdk.nativevm().gas().queryDecimals(); + Assert.assertTrue(decimals == 9); + long total = ontSdk.nativevm().gas().queryTotalSupply(); + Assert.assertFalse(total < 0); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/DNAProject/smartcontract/nativevm/GovernanceTest.java b/src/test/java/com/github/DNAProject/smartcontract/nativevm/GovernanceTest.java new file mode 100644 index 0000000..cd76aa6 --- /dev/null +++ b/src/test/java/com/github/DNAProject/smartcontract/nativevm/GovernanceTest.java @@ -0,0 +1,26 @@ + +package com.github.DNAProject.smartcontract.nativevm; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class GovernanceTest { + @Test + public void newPeerAttributes() { + PeerAttributes peerAttributes1 = new PeerAttributes(); + assertNull(peerAttributes1.peerPubkey); + assertEquals(0, peerAttributes1.maxAuthorize); + assertEquals(0, peerAttributes1.t1PeerCost); + assertEquals(0, peerAttributes1.t2PeerCost); + assertEquals(0, peerAttributes1.tPeerCost); + String peerPubKey = "0379eff8cc07441daad01234291ba3f3da3e323119d97d6f1875da5f414be470b9"; + PeerAttributes peerAttributes2 = new PeerAttributes(peerPubKey); + assertEquals(peerPubKey, peerAttributes2.peerPubkey); + assertEquals(0, peerAttributes2.maxAuthorize); + assertEquals(100, peerAttributes2.t1PeerCost); + assertEquals(100, peerAttributes2.t2PeerCost); + assertEquals(100, peerAttributes2.tPeerCost); + } +} diff --git a/src/test/java/com/github/DNAProject/smartcontract/nativevm/NativeDnaIdTxTest.java b/src/test/java/com/github/DNAProject/smartcontract/nativevm/NativeDnaIdTxTest.java new file mode 100644 index 0000000..88c61d5 --- /dev/null +++ b/src/test/java/com/github/DNAProject/smartcontract/nativevm/NativeDnaIdTxTest.java @@ -0,0 +1,205 @@ +package com.github.DNAProject.smartcontract.nativevm; + +import com.alibaba.fastjson.JSONObject; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.DnaSdkTest; +import com.github.DNAProject.common.Common; +import com.github.DNAProject.core.dnaid.Attribute; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.sdk.info.AccountInfo; +import com.github.DNAProject.sdk.info.IdentityInfo; +import com.github.DNAProject.sdk.wallet.Account; +import com.github.DNAProject.sdk.wallet.Identity; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +public class NativeDnaIdTxTest { + DnaSdk dnaSdk; + String password = "111111"; + Account payer; + com.github.DNAProject.account.Account payerAcct; + Identity identity; + String walletFile = "NativeDNATxTest.json"; + @Before + public void setUp() throws Exception { + dnaSdk = DnaSdk.getInstance(); + dnaSdk.setRestful(DnaSdkTest.URL); + dnaSdk.setDefaultConnect(dnaSdk.getRestful()); + dnaSdk.openWalletFile(walletFile); +// dnaSdk.setSignatureScheme(SignatureScheme.SHA256WITHECDSA); + payer = dnaSdk.getWalletMgr().createAccount(password); + payerAcct = dnaSdk.getWalletMgr().getAccount(payer.address,password,payer.getSalt()); + identity = dnaSdk.getWalletMgr().createIdentity(password); + dnaSdk.nativevm().dnaId().sendRegister(identity,password,payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + Thread.sleep(6000); + + } + + @After + public void removeWallet(){ + File file = new File(walletFile); + if(file.exists()){ + if(file.delete()){ + System.out.println("delete wallet file success"); + } + } + } + + @Test + public void sendRegister() throws Exception { + String dnaid = dnaSdk.nativevm().dnaId().sendGetDDO(identity.dnaid); + if(!dnaid.isEmpty()) { + return; + } + Transaction tx = dnaSdk.nativevm().dnaId().makeRegister(identity.dnaid,identity.controls.get(0).publicKey,payer.address,dnaSdk.DEFAULT_GAS_LIMIT,0); + dnaSdk.signTx(tx, identity.dnaid,password,identity.controls.get(0).getSalt()); + dnaSdk.addSign(tx,payerAcct); + dnaSdk.getConnect().sendRawTransaction(tx); + + Identity identity2 = dnaSdk.getWalletMgr().createIdentity(password); + dnaSdk.nativevm().dnaId().sendRegister(identity2,password,payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + + Identity identity3 = dnaSdk.getWalletMgr().createIdentity(password); + Attribute[] attributes = new Attribute[1]; + attributes[0] = new Attribute("key2".getBytes(),"value2".getBytes(),"type2".getBytes()); + dnaSdk.nativevm().dnaId().sendRegisterWithAttrs(identity3,password,attributes,payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + + Thread.sleep(6000); + String ddo = dnaSdk.nativevm().dnaId().sendGetDDO(identity.dnaid); + Assert.assertTrue(ddo.contains(identity.dnaid)); + + String dd02 = dnaSdk.nativevm().dnaId().sendGetDDO(identity3.dnaid); + Assert.assertTrue(dd02.contains("key2")); + + String keystate = dnaSdk.nativevm().dnaId().sendGetKeyState(identity.dnaid,1); + Assert.assertNotNull(keystate); + + //merkleproof + Object merkleproof = dnaSdk.nativevm().dnaId().getMerkleProof(tx.hash().toHexString()); + boolean b = dnaSdk.nativevm().dnaId().verifyMerkleProof(JSONObject.toJSONString(merkleproof)); + Assert.assertTrue(b); + + //claim + Map map = new HashMap(); + map.put("Issuer", identity.dnaid); + map.put("Subject", identity2.dnaid); + + Map clmRevMap = new HashMap(); + clmRevMap.put("typ","AttestContract"); + clmRevMap.put("addr",identity.dnaid.replace(Common.diddna,"")); + + String claim = dnaSdk.nativevm().dnaId().createDnaIdClaim(identity.dnaid,password,identity.controls.get(0).getSalt(), "claim:context", map, map,clmRevMap,System.currentTimeMillis()/1000 +100000); + boolean b2 = dnaSdk.nativevm().dnaId().verifyDnaIdClaim(claim); + Assert.assertTrue(b2); + } + @Test + public void sendAddPubkey() throws Exception { + IdentityInfo info = dnaSdk.getWalletMgr().createIdentityInfo(password); + IdentityInfo info2 = dnaSdk.getWalletMgr().createIdentityInfo(password); + Transaction tx = dnaSdk.nativevm().dnaId().makeAddPubKey(identity.dnaid,password,identity.controls.get(0).getSalt(),info.pubkey,payer.address,dnaSdk.DEFAULT_GAS_LIMIT,0); + dnaSdk.signTx(tx, identity.dnaid,password,identity.controls.get(0).getSalt()); + dnaSdk.addSign(tx,payerAcct); + dnaSdk.getConnect().sendRawTransaction(tx); + + dnaSdk.nativevm().dnaId().sendAddPubKey(identity.dnaid,password,identity.controls.get(0).getSalt(),info2.pubkey,payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + + Thread.sleep(6000); + String ddo = dnaSdk.nativevm().dnaId().sendGetDDO(identity.dnaid); + Assert.assertTrue(ddo.contains(info.pubkey)); + Assert.assertTrue(ddo.contains(info2.pubkey)); + + String publikeys = dnaSdk.nativevm().dnaId().sendGetPublicKeys(identity.dnaid); + Assert.assertNotNull(publikeys); + + Transaction tx2 = dnaSdk.nativevm().dnaId().makeRemovePubKey(identity.dnaid,password,identity.controls.get(0).getSalt(),info.pubkey,payer.address,dnaSdk.DEFAULT_GAS_LIMIT,0); + dnaSdk.signTx(tx2,identity.dnaid,password,identity.controls.get(0).getSalt()); + dnaSdk.addSign(tx2,payerAcct); + dnaSdk.getConnect().sendRawTransaction(tx2); + + dnaSdk.nativevm().dnaId().sendRemovePubKey(identity.dnaid,password,identity.controls.get(0).getSalt(),info2.pubkey,payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + Thread.sleep(6000); + String ddo3 = dnaSdk.nativevm().dnaId().sendGetDDO(identity.dnaid); + Assert.assertFalse(ddo3.contains(info.pubkey)); + Assert.assertFalse(ddo3.contains(info2.pubkey)); + } + + @Test + public void sendAddAttributes() throws Exception { + Attribute[] attributes = new Attribute[1]; + attributes[0] = new Attribute("key1".getBytes(),"value1".getBytes(),"String".getBytes()); + Transaction tx = dnaSdk.nativevm().dnaId().makeAddAttributes(identity.dnaid,password,identity.controls.get(0).getSalt(),attributes,payer.address,dnaSdk.DEFAULT_GAS_LIMIT,0); + dnaSdk.signTx(tx, identity.dnaid,password,identity.controls.get(0).getSalt()); + dnaSdk.addSign(tx,payerAcct); + dnaSdk.getConnect().sendRawTransaction(tx); + + Attribute[] attributes2 = new Attribute[1]; + attributes2[0] = new Attribute("key99".getBytes(),"value99".getBytes(),"String".getBytes()); + dnaSdk.nativevm().dnaId().sendAddAttributes(identity.dnaid,password,identity.controls.get(0).getSalt(),attributes2,payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + + Thread.sleep(6000); + String ddo = dnaSdk.nativevm().dnaId().sendGetDDO(identity.dnaid); + Assert.assertTrue(ddo.contains("key1")); + Assert.assertTrue(ddo.contains("key99")); + + String attribute = dnaSdk.nativevm().dnaId().sendGetAttributes(identity.dnaid); + Assert.assertTrue(attribute.contains("key1")); + + Transaction tx2= dnaSdk.nativevm().dnaId().makeRemoveAttribute(identity.dnaid,password,identity.controls.get(0).getSalt(),"key1",payer.address,dnaSdk.DEFAULT_GAS_LIMIT,0); + dnaSdk.signTx(tx2,identity.dnaid,password,identity.controls.get(0).getSalt()); + dnaSdk.addSign(tx2,payerAcct); + dnaSdk.getConnect().sendRawTransaction(tx2); + + dnaSdk.nativevm().dnaId().sendRemoveAttribute(identity.dnaid,password,identity.controls.get(0).getSalt(),"key99",payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + Thread.sleep(6000); + + String ddo2 = dnaSdk.nativevm().dnaId().sendGetDDO(identity.dnaid); + Assert.assertFalse(ddo2.contains("key1")); + Assert.assertFalse(ddo2.contains("key99")); + + } + + @Test + public void sendAddRecovery() throws Exception { + Identity identity = dnaSdk.getWalletMgr().createIdentity(password); + dnaSdk.nativevm().dnaId().sendRegister(identity,password,payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + + Identity identity2 = dnaSdk.getWalletMgr().createIdentity(password); + dnaSdk.nativevm().dnaId().sendRegister(identity2,password,payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + + Thread.sleep(6000); + + Account account = dnaSdk.getWalletMgr().createAccount(password); + + Transaction tx = dnaSdk.nativevm().dnaId().makeAddRecovery(identity.dnaid,password,identity.controls.get(0).getSalt(),account.address,payer.address,dnaSdk.DEFAULT_GAS_LIMIT,0); + dnaSdk.signTx(tx, identity.dnaid,password,identity.controls.get(0).getSalt()); + dnaSdk.addSign(tx,payerAcct); + dnaSdk.getConnect().sendRawTransaction(tx); + + dnaSdk.nativevm().dnaId().sendAddRecovery(identity2.dnaid,password,identity2.controls.get(0).getSalt(),account.address,payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + + Thread.sleep(6000); + String ddo = dnaSdk.nativevm().dnaId().sendGetDDO(identity.dnaid); + Assert.assertTrue(ddo.contains(account.address)); + String ddo2 = dnaSdk.nativevm().dnaId().sendGetDDO(identity2.dnaid); + Assert.assertTrue(ddo2.contains(account.address)); + + AccountInfo info2 = dnaSdk.getWalletMgr().createAccountInfo(password); + + Transaction tx2 = dnaSdk.nativevm().dnaId().makeChangeRecovery(identity.dnaid,info2.addressBase58,account.address,password,payerAcct.getAddressU160().toBase58(),dnaSdk.DEFAULT_GAS_LIMIT,0); + dnaSdk.signTx(tx2,account.address,password,account.getSalt()); + + dnaSdk.nativevm().dnaId().sendChangeRecovery(identity2.dnaid,info2.addressBase58,account.address,password,account.getSalt(),payerAcct,dnaSdk.DEFAULT_GAS_LIMIT,0); + Thread.sleep(6000); + + String ddo3 = dnaSdk.nativevm().dnaId().sendGetDDO(identity.dnaid); + Assert.assertTrue(ddo3.contains(account.address)); + String ddo4 = dnaSdk.nativevm().dnaId().sendGetDDO(identity2.dnaid); + Assert.assertTrue(ddo4.contains(info2.addressBase58)); + } +} \ No newline at end of file From 84f1cdd2abf69b2b4cb5d183511e56f95552de19 Mon Sep 17 00:00:00 2001 From: xizho10 Date: Tue, 17 Dec 2019 21:39:16 +0800 Subject: [PATCH 03/18] update docs --- README.md | 13 ++ docs/README.md | 18 +-- docs/Wallet_File_Specification_cn.md | 8 +- docs/asset.md | 4 +- docs/auth.md | 4 - docs/basic.md | 4 +- docs/{identity_claim.md => dnaid.md} | 2 - docs/{attest.md => dnaid_claim.md} | 130 +++++++++++++++++- docs/errorcode.md | 2 - docs/governance.md | 3 - docs/interface.md | 33 ++--- docs/sdk_get_start.md | 28 ++-- docs/smartcontract.md | 48 ++++--- .../{PunicaInitDemo.java => Demo.java} | 4 +- .../DNAProject/smartcontract/WasmVmTest.java | 48 +++---- 15 files changed, 231 insertions(+), 118 deletions(-) rename docs/{identity_claim.md => dnaid.md} (99%) rename docs/{attest.md => dnaid_claim.md} (63%) rename src/main/java/example/smartcontract/{PunicaInitDemo.java => Demo.java} (99%) diff --git a/README.md b/README.md index 4eda7da..5c1f446 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,19 @@ Download URL: mvn clean install ``` +### How to Use + +Add maven dependency: + +``` + + + com.github.DNAProject + DNASDKJava/artifactId> + 2.0.0 + +``` + ## Preparations * Make sure DNA Blockchain has deployed well, RPC port has been opened, and SDK will connect the RPC server to initialize. diff --git a/docs/README.md b/docs/README.md index 5248aed..9bc1f7f 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,25 +1,25 @@

DNA Java SDK 介绍

-

Version 1.0.0

+

Version 2.0.0

# 总体介绍 该项目是本体官方Java SDK,它是一个综合性SDK,目前支持:本地钱包管理、数字身份管理、数字资产管理、智能合约部署和调用、与节点通信等。未来还将支持更丰富的功能和应用。 -## 主要功能 +## 主要内容 -- [介绍](sdk_get_start.md) +- [快速开始](sdk_get_start.md) +- [区块链节点接口](basic.md) +- [数字资产](asset.md) +- [数字身份](dnaid.md) +- [可信声明](dnaid_claim.md) +- [智能合约部署和调用](smartcontract.md) - [接口基本信息](interface.md) -- [区块链节点基本操作](basic.md) - [钱包文件及规范](Wallet_File_Specification_cn.md) -- [数字身份及可信声明管理](identity_claim.md) -- [数字资产](asset.md) -- [数字存证](attest.md) - [权限管理](auth.md) -- [智能合约部署和调用](smartcontract.md) +- [API 文档](https://github.com/DNAProject/DNA/tree/master/docs/specifications) - [错误码](errorcode.md) -- [API 文档](https://apidoc.ont.io/javasdk/) ## 代码结构说明: diff --git a/docs/Wallet_File_Specification_cn.md b/docs/Wallet_File_Specification_cn.md index c782ecc..bcd1df4 100644 --- a/docs/Wallet_File_Specification_cn.md +++ b/docs/Wallet_File_Specification_cn.md @@ -1,8 +1,6 @@

钱包规范

-

Version 1.0.0

- 钱包规范描述了钱包数据结构及导出数字身份或资产账号二维码的数据结构。 @@ -16,7 +14,7 @@ "name": "MyWallet", "version": "1.0", "scrypt": {}, - "defaultDnaid": "did:ont:TJNxJe2Ty8eSCjCDxDPwiS78NRAn8XPTFL", + "defaultDnaid": "did:dna:TJNxJe2Ty8eSCjCDxDPwiS78NRAn8XPTFL", "defaultAccountAddress": "TJNxJe2Ty8eSCjCDxDPwiS78NRAn8XPTFL", "createTime": "2018-03-14T03:12:30.862Z", "identities": [], @@ -60,7 +58,7 @@ "dkLen": 64 }, "identities": [{ - "dnaid": "did:ont:ATcHA9eYKyve8M74CB4p6Ssx7kwXjmREUa", + "dnaid": "did:dna:ATcHA9eYKyve8M74CB4p6Ssx7kwXjmREUa", "label": "mickey", "lock": false, "controls": [{ @@ -122,7 +120,7 @@ SCrypt算法参数,Scrypt数据结构: 数字身份数据结构: ```json { - "dnaid": "did:ont:TQLASLtT6pWbThcSCYU1biVqhMnzhTgLFq", + "dnaid": "did:dna:TQLASLtT6pWbThcSCYU1biVqhMnzhTgLFq", "label": "MyIdentity", "lock": false, "isDefault" : false, diff --git a/docs/asset.md b/docs/asset.md index db330f5..a858f16 100644 --- a/docs/asset.md +++ b/docs/asset.md @@ -1,11 +1,9 @@

数字资产

-

Version 1.0.0

- ## 钱包文件及规范 -钱包文件是一个Json格式的数据存储文件,可同时存储多个数字身份和多个数字资产账户。具体参考[钱包文件规范](../en/Wallet_File_Specification.md)。 +钱包文件是一个Json格式的数据存储文件,可同时存储多个数字身份和多个数字资产账户。具体参考[钱包文件规范](../docs/Wallet_File_Specification.md)。 为了管理数字资产,您首先需要创建/打开一个钱包文件。 diff --git a/docs/auth.md b/docs/auth.md index 82fc4d9..1918001 100644 --- a/docs/auth.md +++ b/docs/auth.md @@ -1,9 +1,5 @@

权限管理

-

Version 1.0.0

- -[English](../en/auth.md) / 中文 - 当前,智能合约的函数可以被任何人调用,这显然不符合现实要求。基于角色的权限管理的基本思想是,每个角色可以调用部分函数,每个实体可以被赋予多种角色(实体是由其DNA ID来标识)。 diff --git a/docs/basic.md b/docs/basic.md index d1e5f61..b93fa2b 100644 --- a/docs/basic.md +++ b/docs/basic.md @@ -1,6 +1,4 @@ -

区块链交互基本操作

- -

Version 1.0.0

+

区块链节点接口

diff --git a/docs/identity_claim.md b/docs/dnaid.md similarity index 99% rename from docs/identity_claim.md rename to docs/dnaid.md index 0e9e7b5..a720b6b 100644 --- a/docs/identity_claim.md +++ b/docs/dnaid.md @@ -1,7 +1,5 @@

数字身份

-

Version 1.0.0

- ## 介绍 diff --git a/docs/attest.md b/docs/dnaid_claim.md similarity index 63% rename from docs/attest.md rename to docs/dnaid_claim.md index 90ae86e..0c738c0 100644 --- a/docs/attest.md +++ b/docs/dnaid_claim.md @@ -1,7 +1,5 @@

可信声明及存证

-

Version 1.0.0

- ## 1. 可信声明 @@ -19,6 +17,128 @@ java-sdk采用JSON Web Token的格式表示claim以便于在声明发行者和申请者之间进行传递,jwt格式包含三部分header,payload,signature. + +### 1.2 可信声明格式 + +我们使用JSON Web Token的扩展格式来表示一个可信声明,它可以在发行者和接收者之间传输。 + +可信声明基本结构由三部分组成:Header,Payload,Signature。我们应该尽可能的多重用JWT标准属性,在某些特殊情况下可以使用定制属性。 + +我们通过在最后附加区块链证明来扩展JWT格式,一个典型的可信声明被组织为**header.payload.signature.blockchain_proof** + + 注意:blockchain_proof是可选的。某些情况下,可信声明可以不包含blockchain_proof + +#### Header +Header部分定义了该可信声明的格式类型,使用的签名方案以及用于验证签名的公钥id +``` +{ + "alg": "ES256", + "typ": "JWT-X", + "kid": "did:ont:TRAtosUZHNSiLhzBdHacyxMX4Bg3cjWy3r#keys-1" +} +``` + +- **alg** 指明使用的签名方案。 + +- **typ** 格式类型,可以是以下两种值 + - JWT:不包含区块链证明的可信声明 + - JWT-X:包含区块链证明的可信声明 + + +- **kid** 指明用于签名验证的公钥。格式和DNA-ID 规范定义的一样:```#keys-``` + +#### Payload +在Payload部分,可信声明id,content,metadata被编码为JSON对象。使用JWT规范中指定的一些名称,即 `jti`,`iss`,`sub`,`iat`,`exp` +``` +{ + "ver": "0.7.0", + "iss": "did:ont:TRAtosUZHNSiLhzBdHacyxMX4Bg3cjWy3r", + "sub": "did:ont:SI59Js0zpNSiPOzBdB5cyxu80BO3cjGT70", + "iat": 1525465044, + "exp": 1530735444, + "jti":"4d9546fdf2eb94a364208fa65a9996b03ba0ca4ab2f56d106dac92e891b6f7fc", + "@context":"https://example.com/template/v1", + "clm":{ + "Name": "Bob Dylan", + "Age": "22" + }, + "clm-rev":{ + "typ": "AttestContract", + "addr": "8055b362904715fd84536e754868f4c8d27ca3f6" + } +} +``` + +- **ver** 指明可信声明版本 +- **iss** 可信声明签发者的ONT ID +- **sub** 可信声明接收者的ONT ID +- **iat** unix时间戳格式的创建时间 +- **exp** unix时间戳格式的过期时间 +- **jti** 可信声明的唯一标识符 +- **@context** 可信声明内容定义文档的uri,包含每个字段的含义和值的类型的定义 +- **clm** 指明了可信声明内容 +- **clm-rev** 指明了可信声明吊销方式。支持的方式在[附录C](claim_spec.md#C-Revocation). + + +要签发一个可信声明,首先需要构造可信声明id、content和metadata的JSON对象,然后使用标准的JSON序列化方法对其进行序列化。最后,使用签发者的某个私钥对header和payload的二进制数据进行签名。例如上面的payload在序列化后看起来像这样: +``` + {"ver":"0.7.0","iss":"did:ont:TRAtosUZHNSiLhzBdHacyxMX4Bg3cjWy3r","sub":"did:ont:SI59Js0zpNSiPOzBdB5cyxu80BO3cjGT70","iat":1525465044,"exp":1530735444,"jti":"4d9546fdf2eb94a364208fa65a9996b03ba0ca4ab2f56d106dac92e891b6f7fc","@context":"https://example.com/template/v1","clm":{"Name":"Bob Dylan","Age":"22"},"clm-rev":{"Type":"Contract","Addr":"8055b362904715fd84536e754868f4c8d27ca3f6"}} + +``` + + +#### Signature + +在构造完Header和Payload部分后,根据JWS标准计算签名。详细的描述在 [RFC 7515 Section 5.1](https://tools.ietf.org/html/rfc7515#section-5.1)。简化的版本如下: + +- 根据JWS规范对Header和Payload部分进行序列化,作为签名的输入 + + sig := sign(Base64URL(header) || . || Base64URL(payload)) + + +- 根据Header部分指定的特定签名方案来计算签名。 + +- 对签名进行编码 + + signature := Base64URL(sig). + + +#### Blockchain proof +``` +{ + "Type":"MerkleProof", + "TxnHash":"c89e76ee58ae6ad99cfab829d3bf5bd7e5b9af3e5b38713c9d76ef2dcba2c8e0", + "ContractAddr": "8055b362904715fd84536e754868f4c8d27ca3f6", + "BlockHeight":10, + "MerkleRoot":"bfc2ac895685fbb01e22c61462f15f2a6e3544835731a43ae0cba82255a9f904", + "Nodes":[{ + "Direction":"Right", + "TargetHash":"2fa49b6440104c2de900699d31506845d244cc0c8c36a2fffb019ee7c0c6e2f6" + }, { + "Direction":"Left", + "TargetHash":"fc4990f9758a310e054d166da842dab1ecd15ad9f8f0122ec71946f20ae964a4" + }] +} +``` + +- **Type** 固定值"MerkleProof" +- **TxnHash** 将可信声明id存证在合约里的交易hash值 +- **ContractAddr** 存证合约的地址 +- **BlockHeight** 存证交易对应的区块高度 +- **MerkleRoot** 该区块高度的区块对应的Merkle树根 +- **Nodes** Merkle树证明的证明路径 + +MerkleProof按照以下格式编码 + + BASE64URL(MerkleProof) + +现在一个完整的可信声明就被创建好了 + + BASE64URL(Header) || '.' || BASE64URL(Payload) || '.' || BASE64URL(Signature) '.' || BASE64URL(MerkleProof) + + +#### 数据结构 + * Claim 具有以下数据结构 ```java @@ -32,7 +152,7 @@ class Claim{ ```java class Header { - public String Alg = "ONT-ES256"; + public String Alg = "DNA-ES256"; public String Typ = "JWT-X"; public String Kid; } @@ -70,7 +190,7 @@ class Payload { `clm` 包含claim内容的对象 `clm-rev` 定义个claim 的撤销机制, -### 1.2 创建可信声明 +### 1.3 创建可信声明 根据用户输入内容构造声明对象,该声明对象里包含了签名后的数据。 创建claim: @@ -113,7 +233,7 @@ String createDnaIdClaim(String signerDnaid, String password,byte[] salt, String -### 1.3 验证可信声明 +### 1.4 验证可信声明 验证claim步骤: * 1.查询链上是否存在Metadata中Issuer的DDO diff --git a/docs/errorcode.md b/docs/errorcode.md index 6117cf8..04ccdee 100644 --- a/docs/errorcode.md +++ b/docs/errorcode.md @@ -1,7 +1,5 @@

错误码

-

Version 1.0.0

- | 返回代码 | 描述信息 | 说明 | diff --git a/docs/governance.md b/docs/governance.md index 6f50f98..5cdbe65 100644 --- a/docs/governance.md +++ b/docs/governance.md @@ -1,8 +1,5 @@

治理合约

-

Version 1.0.0

- - ## 治理合约接口 diff --git a/docs/interface.md b/docs/interface.md index e7b9dc9..d2284c9 100644 --- a/docs/interface.md +++ b/docs/interface.md @@ -97,12 +97,12 @@ ``` ### 数字资产: -1.原生数字资产 -2.Nep-5智能合约数字资产 +1. 原生数字资产 +2. OEP4智能合约数字资产 * 原生数字资产: -ont: +gas: ``` | Main Function | Description @@ -118,26 +118,9 @@ ont: 9 | long queryTotalSupply() | 查询总供应量 ``` -ong: -``` - - | Main Function | Description - -----|-------------------------------------------------------------------------------------------------------------|--------------------------------------------- - 1 | String sendTransfer(Account sendAcct, String recvAddr, long amount,Account payerAcct,long gaslimit,long gasprice) | 转账 - 2 | long queryBalanceOf(String address) | 查询余额 - 3 | long queryAllowance(String fromAddr,String toAddr) | 查询Allowance - 4 | String sendApprove(Account sendAcct, String recvAddr, long amount,Account payerAcct,long gaslimit,long gasprice) | 发送Approve - 5 | String sendTransferFrom(Account sendAcct, String fromAddr, String toAddr,long amount,Account payerAcct,long gaslimit,long gasprice) | 发送TransferFrom - 6 | String queryName() | 查询资产名 - 7 | String querySymbol() | 查询资产Symbol - 8 | long queryDecimals() | 查询精度 - 9 | long queryTotalSupply() | 查询总供应量 - 10 | String claimOng(Account sendAcct, String toAddr, long amount, Account payerAcct, long gaslimit, long gasprice) | 提取ong - 11 | String unclaimOng(String address) | 查询未提取的ong - -``` + -* Nep-5智能合约数字资产: +* OEP4智能合约数字资产: ``` | Main Function | Description @@ -156,9 +139,9 @@ ong: ``` ### 数字身份: -1.数字身份包括注册、公钥、属性、恢复人等操作。 -2.claim接口包括颁发和验证 -3.claim存证接口 +1. 数字身份包括注册、公钥、属性、恢复人等操作。 +2. claim接口包括颁发和验证 +3. claim存证接口 * dnaid功能接口: ``` diff --git a/docs/sdk_get_start.md b/docs/sdk_get_start.md index a3c27be..0550631 100644 --- a/docs/sdk_get_start.md +++ b/docs/sdk_get_start.md @@ -1,15 +1,8 @@

Java sdk 使用说明

-

Version 1.0.0

- -[English](../en/sdk_get_start.md) / 中文 - -ONT中有两种资产:原生资产和合约资产。原生资产如ont和ong。交易所对接时,主要处理这两种类型资产的充值、提现等操作。 - -sdk文档:[sdk文档](https://github.com/DNAProject/DNASDKJava/tree/master/docs/) 本文大纲如下: -* [Java sdk 使用说明](#java-sdk-使用说明) +* [快速开始](#快速开始) * [1. 公私钥和地址](#1-公私钥和地址) * [1.1 公私钥存储](#11-公私钥存储) * [1.1.1 自己存储:](#111-自己存储) @@ -41,13 +34,26 @@ sdk文档:[sdk文档](https://github.com/DNAProject/DNASDKJava/tree/master/doc * [4.1 批量构造交易](#41-批量构造交易) * [4.2 批量发送交易](#42-批量发送交易) * [4.3 在钱包中创建Dnaid](#43-在钱包中创建Dnaid) + +# 快速开始 + +在公私钥对创建前,请先熟悉区块链接口,如果对数字身份和智能合约感兴趣,请参考对应说明。 + +区块链接口请参考: + - [区块链节点接口](basic.md)。 +数字身份请参考: + - [数字身份](dnaid.md) + - [可信声明](dnaid_claim.md) +智能合约请参考: + - [智能合约部署和调用](smartcontract.md) + ## 1. 公私钥和地址 账户是基于公私钥创建的,地址是公钥转换而来。 ### 1.1 **公私钥存储** -公私钥存储可以存储在数据库中,也可以根据钱包规范存储在文件中。 +公私钥存储可以根据情况存储在自己数据库中,也可以根据钱包规范存储在文件中。 #### 1.1.1 自己存储: @@ -124,7 +130,7 @@ Address recvAddr = Address.addressFromMultiPubKeys(2, acct1.serializePublicKey() | 方法名 | 参数 | 参数描述 | | :--- | :--- | :--- | -| addressFromMultiPubkeys | int m,byte\[\]... pubkeys | 最小验签个数(<=公钥个数),公钥 | +| addressFromMultiPubkeys | int m,byte[]... pubkeys | 最小验签个数(<=公钥个数),公钥 | ## 2. 原生资产转账 @@ -137,7 +143,7 @@ Address recvAddr = Address.addressFromMultiPubKeys(2, acct1.serializePublicKey() ```java -String ip = "http://polaris1.ont.io"; +String ip = "http://127.0.0.1"; String rpcUrl = ip + ":" + "20336"; DnaSdk dnaSdk = DnaSdk.getInstance(); dnaSdk.setRpc(rpcUrl); diff --git a/docs/smartcontract.md b/docs/smartcontract.md index a58a0ec..bc8646e 100644 --- a/docs/smartcontract.md +++ b/docs/smartcontract.md @@ -1,7 +1,5 @@

Java sdk 智能合约

-

Version 1.0.0

- ## 介绍 @@ -9,12 +7,12 @@ ## 智能合约部署、调用、事件推送 -> Note:目前java-sdk支持neo智能合约部署和调用,暂不支持WASM合约,NEO和WASM合约部署操作一样,调用略有不同,见下面详解: +> Note:目前java-sdk支持neo和WASM智能合约部署和调用,NEO和WASM合约部署和调用方法不同,见下面详解: ### 部署 -通过[SmartX](https://smartx.ont.io/)编译智能合约,可以在SmartX上直接部署合约,也可以通过java sdk部署合约。 +通过[SmartX]()编译智能合约,可以在SmartX上直接部署合约,也可以通过java sdk部署合约。 ```java InputStream is = new FileInputStream("/Users/sss/dev/test/IdContract/IdContract.avm"); @@ -34,7 +32,7 @@ Thread.sleep(6000); DeployCodeTransaction t = (DeployCodeTransaction) dnaSdk.getConnect().getTransaction(txHex); ``` -**makeDeployCodeTransaction** +**DeployCode** ```java public DeployCode makeDeployCodeTransaction(String codeStr, boolean needStorage, String name, String codeVersion, String author, String email, String desp,String payer,long gaslimit,long gasprice) @@ -56,6 +54,16 @@ public DeployCode makeDeployCodeTransaction(String codeStr, boolean needStorage, | | gasprice | long | gas价格 | 必选 | | 输出参数 | tx | Transaction | 交易实例 | | + +**DeployWasmCode** + +```java +DeployWasmCode tx = dnaSdk.wasmvm().makeDeployCodeTransaction(code, "helloWorld", "1.0", "NashMiao", + "wdx7266@vip.qq.com", "wasm contract for java sdk test", payer.getAddressU160(), + 500, 25000000); + +``` + ### 调用 #### NEO智能合约调用 @@ -109,7 +117,7 @@ public static String invokeContract(byte[] params, Account payerAcct, long gasli -#### WASM智能合约调用-目前不支持WASM +#### WASM智能合约调用 * 基本流程: 1. 构造调用合约中的方法需要的参数; @@ -120,15 +128,18 @@ public static String invokeContract(byte[] params, Account payerAcct, long gasli * 示例: ```java -//设置要调用的合约地址codeAddress -dnaSdk.getSmartcodeTx().setCodeAddress(codeAddress); -String funcName = "add"; -//构造合约函数需要的参数 -String params = dnaSdk.vm().buildWasmContractJsonParam(new Object[]{20,30}); -//指定虚拟机类型构造交易 -Transaction tx = dnaSdk.vm().makeInvokeCodeTransaction(dnaSdk.getSmartcodeTx().getCodeAddress(),funcName,params.getBytes(),VmType.WASMVM.value(),payer,gas); -//发送交易 -dnaSdk.getConnect().sendRawTransaction(tx.toHexString()); +String contractHash = "bf8ee176c360f7a77b9c45b6faab213bc50eaf5d"; +List params = new ArrayList<>(Arrays.asList(1, 2)); +InvokeWasmCode tx = dnaSdk.wasmvm().makeInvokeCodeTransaction(contractHash, "add", params, payer.getAddressU160(), 500, 25000000); + +dnaSdk.signTx(tx, new Account[][]{{payer}}); +JSONObject result = (JSONObject) dnaSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); + +params = new ArrayList<>(Arrays.asList(-2, 3)); +tx = dnaSdk.wasmvm().makeInvokeCodeTransaction(contractHash, "add", params, payer.getAddressU160(), 500, 25000000); + +dnaSdk.signTx(tx, new Account[][]{{payer}}); +result = (JSONObject) dnaSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); ``` #### 智能合约调用例子 @@ -196,16 +207,13 @@ System.out.println(dnaSdk.getConnect().getSmartCodeEvent(tx.hash().toHexString() ```java -//lock 全局变量,同步锁 -public static Object lock = new Object(); -//获得ont实例 String ip = "http://127.0.0.1"; String wsUrl = ip + ":" + "20335"; DnaSdk wm = DnaSdk.getInstance(); wm.setWesocket(wsUrl, lock); wm.setDefaultConnect(wm.getWebSocket()); -wm.openWalletFile("OntAssetDemo.json"); +wm.openWalletFile("AssetDemo.json"); ``` @@ -376,7 +384,7 @@ System.out.println("CodeAddress:" + Address.AddressFromVmCode(code).toHexString( ```java //step1:构造交易 //需先将智能合约参数转换成vm可识别的opcode -Transaction tx = dnaSdk.vm().makeInvokeCodeTransaction(ontContractAddr, null, contract.toArray(), VmType.Native.value(), sender.toBase58(),gaslimit,gasprice); +Transaction tx = dnaSdk.vm().makeInvokeCodeTransaction(contractAddr, null, contract.toArray(), VmType.Native.value(), sender.toBase58(),gaslimit,gasprice); //step2:对交易签名 dnaSdk.signTx(tx, info1.address, password); diff --git a/src/main/java/example/smartcontract/PunicaInitDemo.java b/src/main/java/example/smartcontract/Demo.java similarity index 99% rename from src/main/java/example/smartcontract/PunicaInitDemo.java rename to src/main/java/example/smartcontract/Demo.java index bde9bfd..8f87093 100644 --- a/src/main/java/example/smartcontract/PunicaInitDemo.java +++ b/src/main/java/example/smartcontract/Demo.java @@ -15,13 +15,13 @@ import java.util.List; import java.util.Map; // Smart contract is in : https://github.com/punica-box/punica-init-default-box/tree/master/contracts -public class PunicaInitDemo { +public class Demo { private static DnaSdk dnaSdk = null; public static String contractCode = "013ec56b6a00527ac46a51527ac46a00c3046e616d659c640900658e076c7566616a00c30568656c6c6f9c6424006a51c3c0519e640700006c7566616a51c300c36a52527ac46a52c36551076c7566616a00c3097465737448656c6c6f9c646c006a51c3c0559e640700006c7566616a51c300c36a53527ac46a51c351c36a54527ac46a51c352c36a55527ac46a51c353c36a56527ac46a51c354c36a57527ac46a53c36a54c36a55c36a56c36a57c354795179567275517275537952795572755272756553066c7566616a00c308746573744c6973749c6424006a51c3c0519e640700006c7566616a51c300c36a58527ac46a58c365e8056c7566616a00c30e746573744c697374416e645374729c6451006a51c351c176c9681553797374656d2e52756e74696d652e4e6f74696679616a51c3c0529e640700006c7566616a51c300c36a58527ac46a51c351c36a56527ac46a58c36a56c37c6528056c7566616a00c30e746573745374727563744c6973749c6431006a51c3681553797374656d2e52756e74696d652e4e6f74696679616a51c300c36a59527ac46a59c365a7046c7566616a00c314746573745374727563744c697374416e645374729c6432006a51c3c0529e640700006c7566616a51c300c36a59527ac46a51c351c36a56527ac46a59c36a56c37c65fa036c7566616a00c307746573744d61709c6416006a51c300c36a52527ac46a52c3655b036c7566616a00c30a746573744765744d61709c6424006a51c3c0519e640700006c7566616a51c300c36a5a527ac46a5ac365b1026c7566616a00c30c746573744d6170496e4d61709c6416006a51c300c36a52527ac46a52c365c2016c7566616a00c30f746573744765744d6170496e4d61709c6424006a51c3c0519e640700006c7566616a51c300c36a5a527ac46a5ac365e3006c7566616a00c30d7472616e736665724d756c74699c6416006a51c300c36a5b527ac46a5bc3650b006c756661006c756659c56b6a00527ac4006a52527ac46a00c3c06a53527ac4616a52c36a53c39f6473006a00c36a52c3c36a51527ac46a52c351936a52527ac46a51c3c0539e6420001b7472616e736665724d756c746920706172616d73206572726f722ef0616a51c300c36a51c351c36a51c352c35272652900009c64a2ff157472616e736665724d756c7469206661696c65642ef06288ff616161516c756656c56b6a00527ac46a51527ac46a52527ac4516c756657c56b6a00527ac4681953797374656d2e53746f726167652e476574436f6e7465787461086d61705f6b6579327c681253797374656d2e53746f726167652e476574616a51527ac40f746573744765744d6170496e4d61706a51c352c176c9681553797374656d2e52756e74696d652e4e6f74696679616a51c3681a53797374656d2e52756e74696d652e446573657269616c697a65616a52527ac46a52c36a00c3c36c756659c56b6a00527ac46a00c36a51527ac46a51c3681853797374656d2e52756e74696d652e53657269616c697a65616a52527ac4076d6170496e666f6a52c352c176c9681553797374656d2e52756e74696d652e4e6f74696679616a51c3036b6579c3681853797374656d2e52756e74696d652e53657269616c697a65616a53527ac4681953797374656d2e53746f726167652e476574436f6e7465787461086d61705f6b6579326a53c35272681253797374656d2e53746f726167652e507574616a52c36c756656c56b6a00527ac4681953797374656d2e53746f726167652e476574436f6e7465787461076d61705f6b65797c681253797374656d2e53746f726167652e476574616a51527ac46a51c3681a53797374656d2e52756e74696d652e446573657269616c697a65616a52527ac46a52c36a00c3c36c756657c56b6a00527ac46a00c36a51527ac46a51c3681853797374656d2e52756e74696d652e53657269616c697a65616a52527ac4681953797374656d2e53746f726167652e476574436f6e7465787461076d61705f6b65796a52c35272681253797374656d2e53746f726167652e507574616a51c3036b6579c36c756659c56b6a00527ac46a51527ac414746573745374727563744c697374416e645374726a00c36a51c353c176c9681553797374656d2e52756e74696d652e4e6f746966796100c176c96a52527ac46a52c36a00c3c86a52c36a51c3c86a52c36c756655c56b6a00527ac40e746573745374727563744c6973746a00c352c176c9681553797374656d2e52756e74696d652e4e6f74696679616a00c36c756659c56b6a00527ac46a51527ac40e746573744c697374416e645374726a00c36a51c353c176c9681553797374656d2e52756e74696d652e4e6f746966796100c176c96a52527ac46a52c36a00c3c86a52c36a51c3c86a52c36c756655c56b6a00527ac40b746573744d73674c6973746a00c352c176c9681553797374656d2e52756e74696d652e4e6f74696679616a00c36c75665fc56b6a00527ac46a51527ac46a52527ac46a53527ac46a54527ac4097465737448656c6c6f6a00c36a51c36a52c36a53c36a54c356c176c9681553797374656d2e52756e74696d652e4e6f746966796100c176c96a55527ac46a55c36a00c3c86a55c36a51c3c86a55c36a52c3c86a55c36a53c3c86a55c36a54c3c86a55c36c756654c56b6a00527ac46a00c36c756653c56b046e616d656c7566"; - private PunicaInitDemo(){ + private Demo(){ } diff --git a/src/test/java/com/github/DNAProject/smartcontract/WasmVmTest.java b/src/test/java/com/github/DNAProject/smartcontract/WasmVmTest.java index f139cfa..9f4b0ac 100644 --- a/src/test/java/com/github/DNAProject/smartcontract/WasmVmTest.java +++ b/src/test/java/com/github/DNAProject/smartcontract/WasmVmTest.java @@ -21,7 +21,7 @@ public class WasmVmTest { - private DnaSdk ontSdk; + private DnaSdk dnaSdk; private Account payer; @@ -29,9 +29,9 @@ public class WasmVmTest { @Before public void setUp() throws Exception { - ontSdk = DnaSdk.getInstance(); - ontSdk.setRestful("http://127.0.0.1:20334"); - ontSdk.setDefaultConnect(ontSdk.getRestful()); + dnaSdk = DnaSdk.getInstance(); + dnaSdk.setRestful("http://127.0.0.1:20334"); + dnaSdk.setDefaultConnect(dnaSdk.getRestful()); // ontSdk.openWalletFile("NeoVmTest.json"); payer = new Account(Helper.hexToBytes(DnaSdkTest.PRIVATEKEY), SignatureScheme.SHA256WITHECDSA); } @@ -41,10 +41,10 @@ public void makeDeployCodeTx() throws Exception { String code = "0061736d01000000014c0d60037f7f7f017f60027f7f017f6000017f60017f0060027f7f0060017f017f60037f7f7f0060000060047f7f7f7f0060027e7f017f60017f017e60057f7f7f7f7f017f60047f7f7f7f017f02550403656e76126f6e74696f5f696e7075745f6c656e677468000203656e760f6f6e74696f5f6765745f696e707574000303656e760c6f6e74696f5f72657475726e000403656e760b6f6e74696f5f70616e69630004033837030305040607050607030804040500000507070404060003030001010401040903030a0b0c040001010101010405030101010401000000040501700114140504010101500608017f01418080020b070a0106696e766f6b6500090919010041010b132e2b212c33343504371c1d1e1f1b2f2526322d0a8b393702000b7b01037f230041106b220124000240410b100622020d00410b41011007000b2001420b3702042001200236020020014100410b1008200020012903003702002001280200200128020822026a220341002900bc8002370000200041086a2002410b6a360200200341076a41002800c38002360000200141106a24000b0600200010110b040000000b7b01017f0240024002402000280204220320016b20024f0d00200120026a22022001490d01200341017422012002200120024b1b22014100480d010240024020030d002001100621020c010b200028020020032001101221020b2002450d0220002001360204200020023602000b0f0b1016000b200141011007000bd00402047f017e230041306b22002400410121010240024002400240024002400240024002400240024010002202450d002002417f4c0d012002100a2201450d02200110010b410021032000410036020820002002360204200020013602002002450d0620012d00002102200041013602080240200241837e6a220141024d0d002002ad21040c080b024002400240024020010e03000102000b200041206a20004102100b20002d00204101460d08200041286a28020041014d0d0520002802243300002104410321020c020b200041206a20004104100b20002d00204101460d07200041286a28020041034d0d0520002802243500002104410521020c010b200041206a20004108100b20002d00204101460d06200041206a41086a28020041074d0d0520002802242900002104410921020b41012103200442fd01540d064103410541092004428080808010541b200442808004541b2002460d070c060b100c000b200241011007000b41f08802100d000b41808a02100d000b41b88a02100d000b20002d002121030b200041013a0020200020033a00210c010b200041206a20002004a7100b20002d00204101470d0120002d002121030b200020033a001041808002412b200041106a41ac8002100e000b200041286a28020021022000280224210302400240410c10062201450d002000420c37021420002001360210024020024105470d00200341c78002460d02200341c780024105103a450d020b41808102100d000b410c41011007000b200041206a1005200041106a200041206a100f200028021020002802181010000b0600200010140b830101037f024002400240024020012802042203200128020822046b2002490d00200420026a22052004490d0220032005490d032001280200210320012005360208200041086a2002360200200041046a200320046a360200410021010c010b200041003a0001410121010b200020013a00000f0b200420051029000b200520031020000b05001016000b5b02017f037e230041306b220124002000290208210220002902102103200029020021042001420437031020014201370204200120043703182001200141186a36020020012003370328200120023703202001200141206a1022000b7f01017f230041c0006b220424002004200136020c2004200036020820042003360214200420023602102004412c6a41023602002004413c6a41013602002004420237021c200441c48702360218200441023602342004200441306a3602282004200441106a3602382004200441086a360230200441186a41d887021022000bb90101027f20012802002102024002402001280208220141fd01490d000240200141ffff03490d00200041fe011030200020002802084104100820002000280208220341046a360208200320002802006a20013600000c020b200041fd011030200020002802084102100820002000280208220341026a360208200320002802006a20013b00000c010b2000200110300b200020002802082001100820002000280208220320016a360208200320002802006a2002200110391a0b0900200020011002000b0600200010310b0a0020002001200210130b2301017f0240200210312203450d002003200020022001200120024b1b10391a0b20030b1b01017f0240200010312201450d0020014100200010381a0b20010b05001016000b090041988102100d000b800101027f02400240024020002802042202200028020822036b20014f0d00200320016a22012003490d02200241017422032001200320014b1b22014100480d020240024020020d002001100621020c010b200028020020022001101221020b2002450d0120002001360204200020023602000b0f0b200141011007000b1016000b830301067f230041306b2202240020012802002103024002402001280204220441037422050d00410021060c010b200341046a2107410021060340200728020020066a2106200741086a2107200541786a22050d000b0b024002400240024002400240200141146a2802000d00200621070c010b024020040d0041c48102410041001019000b024002402006410f4b0d002003280204450d010b200620066a220720064f0d010b4101210541002107200241086a21060c010b2007417f4c0d01200241086a2106024020070d0041012105410021070c010b200710062205450d020b200241003602102002200736020c200220053602082002200241086a360214200241186a41106a200141106a290200370300200241186a41086a200141086a29020037030020022001290200370318200241146a41d48102200241186a101a0d0220002006290200370200200041086a200641086a280200360200200241306a24000f0b1015000b200741011007000b41ec81024133200241186a41a08202100e000b6b01017f230041306b2203240020032002360204200320013602002003411c6a41023602002003412c6a41033602002003420237020c200341f88202360208200341033602242003200341206a360218200320033602282003200341046a360220200341086a20001022000bb90801087f230041c0006b22032400200341246a2001360200200341346a200241146a2802002204360200200341033a00382003412c6a2002280210220520044103746a36020020034280808080800437030820032000360220410021062003410036021820034100360210200320053602302003200536022802400240024002400240200228020822070d0020022802002108200228020422092004200420094b1b220a450d0141012104200020082802002008280204200128020c1100000d04200841086a210241012106034002402005280200200341086a200541046a280200110100450d00410121040c060b2006200a4f0d02200241046a210020022802002101200541086a2105200241086a210241012104200641016a2106200328022020012000280200200328022428020c110000450d000c050b0b20022802002108200228020422092002410c6a2802002205200520094b1b220a450d0041012104200020082802002008280204200128020c1100000d03200741106a2105200841086a21024101210603402003200541786a28020036020c2003200541106a2d00003a003820032005417c6a28020036020841002101410021040240024002400240200541086a2802000e0400010203000b2005410c6a2802002100410121040c020b02402005410c6a2802002207200328023422044f0d0041002104200328023020074103746a22072802044104470d0220072802002802002100410121040c020b41b88602200720041019000b4100210420032802282207200328022c460d002003200741086a3602284100210420072802044104470d0020072802002802002100410121040b2003200036021420032004360210024002400240024002400240024020052802000e0404010006040b20032802282200200328022c470d010c050b200541046a2802002200200328023422044f0d01200328023020004103746a22002802044104470d04200028020028020021040c030b2003200041086a36022820002802044104470d03200028020028020021040c020b41b88602200020041019000b200541046a28020021040b410121010b2003200436021c2003200136021802400240200541706a2802004101460d0020032802282204200328022c460d042003200441086a3602280c010b200541746a2802002204200328023422004f0d04200328023020044103746a21040b02402004280200200341086a200441046a280200110100450d00410121040c050b2006200a4f0d01200241046a210020022802002101200541246a2105200241086a210241012104200641016a2106200328022020012000280200200328022428020c110000450d000c040b0b0240200920064d0d00410121042003280220200820064103746a22052802002005280204200328022428020c1100000d030b410021040c020b41a08602100d000b41c88602200420001019000b200341c0006a240020040b02000b02000b2f01017f200028020022002002101720002000280208220320026a360208200320002802006a2001200210391a41000bcb0201027f230041106b220224002000280200210002400240024002402001418001490d002002410036020c2001418010490d0102402001418080044f0d0020022001413f71418001723a000e20022001410676413f71418001723a000d20022001410c76410f7141e001723a000c410321010c030b20022001413f71418001723a000f2002200141127641f001723a000c20022001410676413f71418001723a000e20022001410c76413f71418001723a000d410421010c020b0240200028020822032000280204470d00200041011017200028020821030b200028020020036a20013a00002000200028020841016a3602080c020b20022001413f71418001723a000d20022001410676411f7141c001723a000c410221010b20002001101720002000280208220320016a360208200320002802006a2002410c6a200110391a0b200241106a240041000b6201017f230041206b2202240020022000280200360204200241086a41106a200141106a290200370300200241086a41086a200141086a29020037030020022001290200370308200241046a41d48102200241086a101a2101200241206a240020010b6d01017f230041306b2202240020022001360204200220003602002002411c6a41023602002002412c6a41033602002002420237020c200241948502360208200241033602242002200241206a3602182002200241046a36022820022002360220200241086a41a485021022000b0b002000350200200110230b4602017f017e230041206b2202240020012902002103200241146a20012902083702002002200337020c200220003602082002418883023602042002410136020020021024000bcd0203027f017e037f230041306b22022400412721030240024020004290ce005a0d00200021040c010b412721030340200241096a20036a2205417c6a200020004290ce0080220442f0b17f7e7ca7220641ffff037141e4006e220741017441ca83026a2f00003b00002005417e6a2007419c7f6c20066a41ffff037141017441ca83026a2f00003b00002003417c6a2103200042ffc1d72f5621052004210020050d000b0b02402004a7220541e3004c0d00200241096a2003417e6a22036a2004a7220641ffff037141e4006e2205419c7f6c20066a41ffff037141017441ca83026a2f00003b00000b024002402005410a480d00200241096a2003417e6a22036a200541017441ca83026a2f00003b00000c010b200241096a2003417f6a22036a200541306a3a00000b200141ac88024100200241096a20036a412720036b10272103200241306a240020030bbe0201027f230041e0006b220124000240024002400240200028020822020d00200141003602300c010b20012002360200200141dc006a41013602002001420137024c200141a48802360248200141053602242001200141206a36025820012001360220200141306a200141c8006a101820012802300d010b20014100360208200142013703000c010b200141086a200141306a41086a280200360200200120012903303703000b200041146a28020021022001200029020c3703102001200236021c200141306a41146a4103360200200141c8006a41146a4103360200200141d4006a410636020020014203370234200141ac88023602302001410736024c2001200141c8006a36024020012001411c6a3602582001200141106a36025020012001360248200141206a200141306a1018200128022020012802281036000b02000b0c00428fa2e88daad0abe05a0bc50501067f20002802002205410171220620046a21070240024020054104710d00410021010c010b4100210802402002450d00200221092001210a03402008200a2d000041c00171418001466a2108200a41016a210a2009417f6a22090d000b0b200720026a20086b21070b412b418080c40020061b21080240024020002802084101460d004101210a200020082001200210280d012000280218200320042000411c6a28020028020c1100000f0b02402000410c6a280200220920074b0d004101210a200020082001200210280d012000280218200320042000411c6a28020028020c1100000f0b0240024020054108710d00200920076b21094100210a024002400240410120002d0030220720074103461b0e0402000100020b2009210a410021090c010b2009410176210a200941016a41017621090b200a41016a210a0340200a417f6a220a450d0220002802182000280204200028021c280210110100450d000b41010f0b4101210a200041013a003020004130360204200020082001200210280d01200920076b21084100210a024002400240410120002d0030220920094103461b0e0402000100020b2008210a410021080c010b2008410176210a200841016a41017621080b200a41016a210a02400340200a417f6a220a450d0120002802182000280204200028021c280210110100450d000b41010f0b200028020421094101210a200028021820032004200028021c28020c1100000d01200841016a2108200028021c210220002802182100034002402008417f6a22080d0041000f0b4101210a200020092002280210110100450d000c020b0b200028020421074101210a200020082001200210280d00200028021820032004200028021c28020c1100000d00200941016a2108200028021c210920002802182100034002402008417f6a22080d0041000f0b4101210a200020072009280210110100450d000b0b200a0b5401017f024002402001418080c400460d0041012104200028021820012000411c6a2802002802101101000d010b024020020d0041000f0b2000280218200220032000411c6a28020028020c11000021040b20040b6d01017f230041306b2202240020022001360204200220003602002002411c6a41023602002002412c6a41033602002002420237020c200241dc8502360208200241033602242002200241206a3602182002200241046a36022820022002360220200241086a41ec85021022000b8307010c7f200028021021030240024002400240200028020822044101460d0020030d012000280218200120022000411c6a28020028020c11000021030c030b2003450d010b0240024020020d00410021020c010b200120026a2105200041146a28020041016a21064100210720012103200121080340200341016a210902400240024020032c0000220a417f4a0d000240024020092005470d004100210b200521030c010b20032d0001413f71210b200341026a220921030b200a411f71210c0240200a41ff0171220a41df014b0d00200b200c41067472210a0c020b0240024020032005470d004100210d2005210e0c010b20032d0000413f71210d200341016a2209210e0b200d200b41067472210b0240200a41f0014f0d00200b200c410c7472210a0c020b02400240200e2005470d004100210a200921030c010b200e41016a2103200e2d0000413f71210a0b200b410674200c411274418080f0007172200a72220a418080c400470d020c040b200a41ff0171210a0b200921030b02402006417f6a2206450d00200720086b20036a21072003210820052003470d010c020b0b200a418080c400460d00024002402007450d0020072002460d0041002103200720024f0d01200120076a2c00004140480d010b200121030b2007200220031b21022003200120031b21010b20040d002000280218200120022000411c6a28020028020c1100000f0b4100210902402002450d002002210a200121030340200920032d000041c00171418001466a2109200341016a2103200a417f6a220a0d000b0b0240200220096b200028020c2206490d002000280218200120022000411c6a28020028020c1100000f0b410021074100210902402002450d00410021092002210a200121030340200920032d000041c00171418001466a2109200341016a2103200a417f6a220a0d000b0b200920026b20066a210a024002400240410020002d0030220320034103461b0e0402000100020b200a21074100210a0c010b200a4101762107200a41016a410176210a0b200741016a2103024003402003417f6a2203450d0120002802182000280204200028021c280210110100450d000b41010f0b2000280204210941012103200028021820012002200028021c28020c1100000d00200a41016a2103200028021c210a20002802182100034002402003417f6a22030d0041000f0b20002009200a280210110100450d000b41010f0b20030b1000200120002802002000280204102a0b0b002000350200200110230b1b00200128021841b68702410e2001411c6a28020028020c1100000b140020002802002001200028020428020c1101000b1b00200128021841fd870241052001411c6a28020028020c1100000b3f01017f0240200028020822022000280204470d002000200241011008200028020821020b200028020020026a20013a00002000200028020841016a3602080bd30101047f230041106b22012400024041002802a08b020d004100417f3602a08b020240024041002802a48b02220220006a220341002802a88b0222044d0d000240200320046b41ffff036a220441107640002202417f470d00410021020c020b20024110742103024041002802a48b0222020d00410020033602a48b02200321020b4100200320044180807c716a3602a88b02200220006a21030b410020033602a48b020b410041002802a08b0241016a3602a08b02200141106a240020020f0b418288024110200141086a41948802100e000b02000b6901037f230041206b220224002001411c6a280200210320012802182104200241086a41106a2000280200220141106a290200370300200241086a41086a200141086a2902003703002002200129020037030820042003200241086a101a2101200241206a240020010b1000200120002802002000280204102a0b1000200120002802002000280208102a0b0900200020011003000bd00101017f230041106b22022400024002400240024020002d00000e03010200010b2002200128021841c98802410b2001411c6a28020028020c11000022003a000820022001360200200241003a0009200241003602040c020b2002200128021841d48802410d2001411c6a28020028020c11000022003a000820022001360200200241003a0009200241003602040c010b2002200128021841e18802410d2001411c6a28020028020c11000022003a000820022001360200200241003a0009200241003602040b200241106a240020000b2c01017f02402002450d00200021030340200320013a0000200341016a21032002417f6a22020d000b0b20000b3601017f02402002450d00200021030340200320012d00003a0000200341016a2103200141016a21012002417f6a22020d000b0b20000b4a01037f4100210302402002450d000240034020002d0000220420012d00002205470d01200141016a2101200041016a21002002417f6a2202450d020c000b0b200420056b21030b20030b0ba80b0100418080020b9f0b63616c6c65642060526573756c743a3a756e77726170282960206f6e20616e2060457272602076616c7565000800000001000000010000000900000068656c6c6f20776f726c6468656c6c6f756e737570706f7274656420616374696f6e216578616d706c65732f68656c6c6f776f726c642f7372632f6c69622e72730000004c800000130000005f8000001e000000140000000e000000b080000011000000708500001700000009030000050000006361706163697479206f766572666c6f77000000308100004600000063010000130000000a00000004000000040000000b0000000c0000000d0000006120666f726d617474696e6720747261697420696d706c656d656e746174696f6e2072657475726e656420616e206572726f72000e00000000000000010000000f0000002f72757374632f373937393031366166663534356637623431636335313730333130323630323062333430393839642f7372632f6c6962636f72652f666d742f6d6f642e727300009881000020000000b88100001200000010000000000000000100000011000000696e646578206f7574206f6620626f756e64733a20746865206c656e20697320206275742074686520696e6465782069732030303031303230333034303530363037303830393130313131323133313431353136313731383139323032313232323332343235323632373238323933303331333233333334333533363337333833393430343134323433343434353436343734383439353035313532353335343535353635373538353936303631363236333634363536363637363836393730373137323733373437353736373737383739383038313832383338343835383638373838383939303931393239333934393539363937393839390000b482000006000000ba820000220000008785000018000000180a000005000000696e64657820206f7574206f662072616e676520666f7220736c696365206f66206c656e67746820fc82000016000000128300000d00000087850000180000001e0a000005000000736c69636520696e64657820737461727473206174202062757420656e64732061742000768300002b000000a1830000150000007a01000015000000608300001600000060040000110000006083000016000000540400002800000000000000000000007372632f6c6962636f72652f666d742f6d6f642e727363616c6c656420604f7074696f6e3a3a756e77726170282960206f6e206120604e6f6e65602076616c75657372632f6c6962636f72652f6f7074696f6e2e7273426f72726f774d75744572726f722c84000000000000d4830000020000003a200000e8830000150000008d040000050000007372632f6c6962636f72652f726573756c742e72734572726f72616c726561647920626f72726f7765640000120000000000000001000000130000002c840000000000002c8400000000000044840000040000004884000001000000206174203a496e76616c696455746638556e6578706563746564454f464972726567756c61724461746100008884000020000000a8840000550000007f08000009000000617373657274696f6e206661696c65643a2032203c3d206275662e6c656e28292f686f6d652f6e6173682f2e636172676f2f72656769737472792f7372632f6769746875622e636f6d2d316563633632393964623965633832332f627974656f726465722d312e332e322f7372632f6c69622e72730000001885000020000000a8840000550000008408000009000000617373657274696f6e206661696c65643a2034203c3d206275662e6c656e28295085000020000000a8840000550000008908000009000000617373657274696f6e206661696c65643a2038203c3d206275662e6c656e28297372632f6c6962616c6c6f632f7261775f7665632e72737372632f6c6962636f72652f736c6963652f6d6f642e7273"; String contractHash = "259eed30d30d7c473944760023fcc321b8966371"; Assert.assertEquals(contractHash, Address.AddressFromVmCode(code).toHexString()); - DeployWasmCode tx = ontSdk.wasmvm().makeDeployCodeTransaction(code, "helloWorld", "1.0", "NashMiao", + DeployWasmCode tx = dnaSdk.wasmvm().makeDeployCodeTransaction(code, "helloWorld", "1.0", "NashMiao", "wdx7266@vip.qq.com", "wasm contract for java sdk test", payer.getAddressU160(), 500, 25000000); - JSONObject result = (JSONObject) ontSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); + JSONObject result = (JSONObject) dnaSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); Assert.assertEquals(1, result.getIntValue("State")); } @@ -52,18 +52,18 @@ public void makeDeployCodeTx() throws Exception { public void makeAddInvokeCodeTx() throws Exception { String contractHash = "bf8ee176c360f7a77b9c45b6faab213bc50eaf5d"; List params = new ArrayList<>(Arrays.asList(1, 2)); - InvokeWasmCode tx = ontSdk.wasmvm().makeInvokeCodeTransaction(contractHash, "add", params, payer.getAddressU160(), 500, 25000000); + InvokeWasmCode tx = dnaSdk.wasmvm().makeInvokeCodeTransaction(contractHash, "add", params, payer.getAddressU160(), 500, 25000000); String targetPayload = "5daf0ec53b21abfab6459c7ba7f760c376e18ebf24036164640100000000000000000000000000000002000000000000000000000000000000"; Assert.assertEquals(targetPayload, Helper.toHexString(tx.invokeCode)); - ontSdk.signTx(tx, new Account[][]{{payer}}); - JSONObject result = (JSONObject) ontSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); + dnaSdk.signTx(tx, new Account[][]{{payer}}); + JSONObject result = (JSONObject) dnaSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); Assert.assertEquals("03000000000000000000000000000000", result.getString("Result")); params = new ArrayList<>(Arrays.asList(-2, 3)); - tx = ontSdk.wasmvm().makeInvokeCodeTransaction(contractHash, "add", params, payer.getAddressU160(), 500, 25000000); + tx = dnaSdk.wasmvm().makeInvokeCodeTransaction(contractHash, "add", params, payer.getAddressU160(), 500, 25000000); targetPayload = "5daf0ec53b21abfab6459c7ba7f760c376e18ebf2403616464feffffffffffffffffffffffffffffff03000000000000000000000000000000"; Assert.assertEquals(targetPayload, Helper.toHexString(tx.invokeCode)); - ontSdk.signTx(tx, new Account[][]{{payer}}); - result = (JSONObject) ontSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); + dnaSdk.signTx(tx, new Account[][]{{payer}}); + result = (JSONObject) dnaSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); Assert.assertEquals("01000000000000000000000000000000", result.getString("Result")); } @@ -71,22 +71,22 @@ public void makeAddInvokeCodeTx() throws Exception { public void makeNotifyInvokeCodeTx() throws Exception { String contractHash = "bf8ee176c360f7a77b9c45b6faab213bc50eaf5d"; List params = new ArrayList<>(); - InvokeWasmCode tx = ontSdk.wasmvm().makeInvokeCodeTransaction(contractHash, "notify", params, payer.getAddressU160(), 500, 25000000); + InvokeWasmCode tx = dnaSdk.wasmvm().makeInvokeCodeTransaction(contractHash, "notify", params, payer.getAddressU160(), 500, 25000000); String targetPayload = "5daf0ec53b21abfab6459c7ba7f760c376e18ebf07066e6f74696679"; Assert.assertEquals(targetPayload, Helper.toHexString(tx.invokeCode)); - ontSdk.signTx(tx, new Account[][]{{payer}}); - JSONObject result = (JSONObject) ontSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); + dnaSdk.signTx(tx, new Account[][]{{payer}}); + JSONObject result = (JSONObject) dnaSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); Assert.assertEquals("hello", result.getJSONArray("Notify").getJSONObject(0).getJSONArray("States").get(0)); } @Test public void makeBalanceOfInvokeCodeTx() throws Exception { List params = new ArrayList<>(Collections.singletonList(Address.decodeBase58("ANDfjwrUroaVtvBguDtrWKRMyxFwvVwnZD"))); - InvokeWasmCode tx = ontSdk.wasmvm().makeInvokeCodeTransaction(oep4Contract, "balanceOf", params, payer.getAddressU160(), 500, 25000000); + InvokeWasmCode tx = dnaSdk.wasmvm().makeInvokeCodeTransaction(oep4Contract, "balanceOf", params, payer.getAddressU160(), 500, 25000000); String targetPayload = "0faeff23255536928b308e5caa38bc2dc14f30c31e0962616c616e63654f6646b1a18af6b7c9f8a4602f9f73eeb3030f0c29b7"; Assert.assertEquals(targetPayload, Helper.toHexString(tx.invokeCode)); - ontSdk.signTx(tx, new Account[][]{{payer}}); - JSONObject result = (JSONObject) ontSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); + dnaSdk.signTx(tx, new Account[][]{{payer}}); + JSONObject result = (JSONObject) dnaSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); System.out.println(JSON.toJSONString(result)); //Assert.assertEquals("00e87648170000000000000000000000", result.getString("Result")); } @@ -94,22 +94,22 @@ public void makeBalanceOfInvokeCodeTx() throws Exception { @Test public void makeTotalSupplyInvokeCodeTx() throws Exception { List params = new ArrayList<>(); - InvokeWasmCode tx = ontSdk.wasmvm().makeInvokeCodeTransaction(oep4Contract, "totalSupply", params, payer.getAddressU160(), 500, 25000000); + InvokeWasmCode tx = dnaSdk.wasmvm().makeInvokeCodeTransaction(oep4Contract, "totalSupply", params, payer.getAddressU160(), 500, 25000000); String targetPayload = "0faeff23255536928b308e5caa38bc2dc14f30c30c0b746f74616c537570706c79"; Assert.assertEquals(targetPayload, Helper.toHexString(tx.invokeCode)); - ontSdk.signTx(tx, new Account[][]{{payer}}); - JSONObject result = (JSONObject) ontSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); + dnaSdk.signTx(tx, new Account[][]{{payer}}); + JSONObject result = (JSONObject) dnaSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); Assert.assertEquals("00e87648170000000000000000000000", result.getString("Result")); } @Test public void makeTransferInvokeCodeTx() throws Exception { List params = new ArrayList<>(Arrays.asList(payer.getAddressU160(), Address.decodeBase58("AazEvfQPcQ2GEFFPLF1ZLwQ7K5jDn81hve"), 10)); - InvokeWasmCode tx = ontSdk.wasmvm().makeInvokeCodeTransaction(oep4Contract, "transfer", params, payer.getAddressU160(), 500, 25000000); + InvokeWasmCode tx = dnaSdk.wasmvm().makeInvokeCodeTransaction(oep4Contract, "transfer", params, payer.getAddressU160(), 500, 25000000); String targetPayload = "0faeff23255536928b308e5caa38bc2dc14f30c341087472616e73666572d2c124dd088190f709b684e0bc676d70c41b3776d2c124dd088190f709b684e0bc676d70c41b37760a000000000000000000000000000000"; Assert.assertEquals(targetPayload, Helper.toHexString(tx.invokeCode)); - ontSdk.signTx(tx, new Account[][]{{payer}}); - JSONObject result = (JSONObject) ontSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); + dnaSdk.signTx(tx, new Account[][]{{payer}}); + JSONObject result = (JSONObject) dnaSdk.getRestful().sendRawTransactionPreExec(tx.toHexString()); Assert.assertEquals("01", result.getString("Result")); Assert.assertEquals(1, result.getIntValue("State")); JSONObject notify = result.getJSONArray("Notify").getJSONObject(1); From db57245ac5d3e6f4b7b0c579b4cd7eff945cdaee Mon Sep 17 00:00:00 2001 From: xizho10 Date: Tue, 17 Dec 2019 21:39:16 +0800 Subject: [PATCH 04/18] update docs --- docs/README.md | 2 +- docs/dnaid.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index 9bc1f7f..9617a1b 100644 --- a/docs/README.md +++ b/docs/README.md @@ -5,7 +5,7 @@ # 总体介绍 -该项目是本体官方Java SDK,它是一个综合性SDK,目前支持:本地钱包管理、数字身份管理、数字资产管理、智能合约部署和调用、与节点通信等。未来还将支持更丰富的功能和应用。 +该项目是DNA官方Java SDK,它是一个综合性SDK,目前支持:本地钱包管理、数字身份管理、数字资产管理、智能合约部署和调用、与节点通信等。未来还将支持更丰富的功能和应用。 ## 主要内容 diff --git a/docs/dnaid.md b/docs/dnaid.md index a720b6b..041ad00 100644 --- a/docs/dnaid.md +++ b/docs/dnaid.md @@ -101,7 +101,7 @@ dnaSdk.signTx(tx,identity.dnaid,password); dnaSdk.getConnect().sendRawTransaction(tx); ``` -链上注册成功后,对应此DNA ID的身份描述对象DDO将被存储在本体区块链上。 +链上注册成功后,对应此DNA ID的身份描述对象DDO将被存储在区块链上。 关于DDO的信息可以从[DNA ID 身份标识协议](https://github.com/ontio/ontology-DID/blob/master/README_cn.md) From 88a8fe5241587496f95e2ad5519a559f5dec690f Mon Sep 17 00:00:00 2001 From: xizho10 Date: Wed, 18 Dec 2019 11:47:39 +0800 Subject: [PATCH 05/18] update claim --- .settings/org.eclipse.core.resources.prefs | 3 -- .settings/org.eclipse.jdt.core.prefs | 13 ------- .settings/org.eclipse.m2e.core.prefs | 4 -- docs/README.md | 5 ++- docs/asset.md | 2 +- docs/interface.md | 2 - .../github/DNAProject/account/Account.java | 2 +- .../github/DNAProject/sdk/claim/Claim.java | 2 +- .../github/DNAProject/sdk/wallet/Account.java | 2 +- .../DNAProject/smartcontract/wasmvm/Oep4.java | 8 ++++ src/main/java/example/dnaid/ClaimDemo.java | 37 ++++++++++++++----- 11 files changed, 42 insertions(+), 38 deletions(-) delete mode 100644 .settings/org.eclipse.core.resources.prefs delete mode 100644 .settings/org.eclipse.jdt.core.prefs delete mode 100644 .settings/org.eclipse.m2e.core.prefs create mode 100644 src/main/java/com/github/DNAProject/smartcontract/wasmvm/Oep4.java diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs deleted file mode 100644 index e9441bb..0000000 --- a/.settings/org.eclipse.core.resources.prefs +++ /dev/null @@ -1,3 +0,0 @@ -eclipse.preferences.version=1 -encoding//src/main/java=UTF-8 -encoding/=UTF-8 diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 13b3428..0000000 --- a/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,13 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.8 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.source=1.8 diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs deleted file mode 100644 index f897a7f..0000000 --- a/.settings/org.eclipse.m2e.core.prefs +++ /dev/null @@ -1,4 +0,0 @@ -activeProfiles= -eclipse.preferences.version=1 -resolveWorkspaceProjects=true -version=1 diff --git a/docs/README.md b/docs/README.md index 9617a1b..1d1d5e0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -15,10 +15,11 @@ - [数字身份](dnaid.md) - [可信声明](dnaid_claim.md) - [智能合约部署和调用](smartcontract.md) -- [接口基本信息](interface.md) +- [SDK接口描述](interface.md) - [钱包文件及规范](Wallet_File_Specification_cn.md) - [权限管理](auth.md) -- [API 文档](https://github.com/DNAProject/DNA/tree/master/docs/specifications) +- [治理合约](governance.md) +- [节点API文档](https://github.com/DNAProject/DNA/tree/master/docs/specifications) - [错误码](errorcode.md) ## 代码结构说明: diff --git a/docs/asset.md b/docs/asset.md index a858f16..d61a8fd 100644 --- a/docs/asset.md +++ b/docs/asset.md @@ -3,7 +3,7 @@ ## 钱包文件及规范 -钱包文件是一个Json格式的数据存储文件,可同时存储多个数字身份和多个数字资产账户。具体参考[钱包文件规范](../docs/Wallet_File_Specification.md)。 +钱包文件是一个Json格式的数据存储文件,可同时存储多个数字身份和多个数字资产账户。具体参考[钱包文件规范](Wallet_File_Specification.md)。 为了管理数字资产,您首先需要创建/打开一个钱包文件。 diff --git a/docs/interface.md b/docs/interface.md index d2284c9..3dbc16a 100644 --- a/docs/interface.md +++ b/docs/interface.md @@ -1,7 +1,5 @@

DNA Java SDK 接口

-

Version 1.0.0

- ## 介绍: diff --git a/src/main/java/com/github/DNAProject/account/Account.java b/src/main/java/com/github/DNAProject/account/Account.java index 924eba6..13371eb 100644 --- a/src/main/java/com/github/DNAProject/account/Account.java +++ b/src/main/java/com/github/DNAProject/account/Account.java @@ -51,7 +51,7 @@ import java.util.Arrays; import java.util.Base64; - +//KeyPair,GcmDecoded,GcmEncode public class Account { private KeyType keyType; private Object[] curveParams; diff --git a/src/main/java/com/github/DNAProject/sdk/claim/Claim.java b/src/main/java/com/github/DNAProject/sdk/claim/Claim.java index c2820c8..55c6d8b 100644 --- a/src/main/java/com/github/DNAProject/sdk/claim/Claim.java +++ b/src/main/java/com/github/DNAProject/sdk/claim/Claim.java @@ -96,7 +96,7 @@ public String getClaimStr() { } class Header { - public String Alg = "ONT-ES256"; + public String Alg = "DNA-ES256"; public String Typ = "JWT-X"; public String Kid; public Header(String alg,String typ, String kid) { diff --git a/src/main/java/com/github/DNAProject/sdk/wallet/Account.java b/src/main/java/com/github/DNAProject/sdk/wallet/Account.java index b55bf34..7b7a4a7 100644 --- a/src/main/java/com/github/DNAProject/sdk/wallet/Account.java +++ b/src/main/java/com/github/DNAProject/sdk/wallet/Account.java @@ -27,7 +27,7 @@ import java.util.Map; /** - * + * Account info in wallet */ public class Account { public String label = ""; diff --git a/src/main/java/com/github/DNAProject/smartcontract/wasmvm/Oep4.java b/src/main/java/com/github/DNAProject/smartcontract/wasmvm/Oep4.java new file mode 100644 index 0000000..627f4cb --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/wasmvm/Oep4.java @@ -0,0 +1,8 @@ +package com.github.DNAProject.smartcontract.wasmvm; + +/** + * @Description: + * @date 2019/12/18 + */ +public class Oep4 { +} diff --git a/src/main/java/example/dnaid/ClaimDemo.java b/src/main/java/example/dnaid/ClaimDemo.java index 21a0351..f4f6dc4 100644 --- a/src/main/java/example/dnaid/ClaimDemo.java +++ b/src/main/java/example/dnaid/ClaimDemo.java @@ -24,9 +24,7 @@ import com.github.DNAProject.common.Helper; import com.github.DNAProject.sdk.wallet.Identity; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; /** @@ -38,25 +36,44 @@ public static void main(String[] args) { try { DnaSdk dnaSdk = getDnaSdk(); - String privatekey0 = "c19f16785b8f3543bbaf5e1dbb5d398dfa6c85aaad54fc9d71203ce83e505c07"; + String privatekey0 = "523c5fcf74823831756f0bcb3634234f10b3beb1c05595058534577752ad2d9f"; Account acct0 = new Account(Helper.hexToBytes(privatekey0), dnaSdk.defaultSignScheme); + System.out.println(dnaSdk.getConnect().getBalance(acct0.getAddressU160().toBase58())); + dnaSdk.getWalletMgr().getWallet().clearIdentity(); + dnaSdk.getWalletMgr().writeWallet(); List dids = dnaSdk.getWalletMgr().getWallet().getIdentities(); if (dids.size() < 2) { Identity identity = dnaSdk.getWalletMgr().createIdentity("passwordtest"); - dnaSdk.nativevm().dnaId().sendRegister(identity,"passwordtest",acct0,0,0); + dnaSdk.nativevm().dnaId().sendRegister(identity,"passwordtest",acct0,20000,500); identity = dnaSdk.getWalletMgr().createIdentity("passwordtest"); - dnaSdk.nativevm().dnaId().sendRegister(identity,"passwordtest",acct0,0,0); + dnaSdk.nativevm().dnaId().sendRegister(identity,"passwordtest",acct0,20000,500); dids = dnaSdk.getWalletMgr().getWallet().getIdentities(); + dnaSdk.getWalletMgr().writeWallet(); Thread.sleep(6000); } - Map map = new HashMap(); - map.put("Issuer", dids.get(0).dnaid); - map.put("Subject", dids.get(1).dnaid); + Map metaDataMap = new HashMap<>(); + metaDataMap.put("Issuer", dids.get(0).dnaid); + metaDataMap.put("Subject", dids.get(1).dnaid); - String claim = dnaSdk.nativevm().dnaId().createDnaIdClaim(dids.get(0).dnaid,"passwordtest",new byte[]{}, "claim:context", map, map,map,0); + Map clvMap = new HashMap(); + clvMap.put("typ", "AttestContract"); + clvMap.put("addr", "8055b362904715fd84536e754868f4c8d27ca3f6"); + + Calendar c = Calendar.getInstance(); + c.setTime(new Date()); + c.add(Calendar.YEAR, 1); + long expires = c.getTimeInMillis() / 1000L; + + Map claimInfoMap = new HashMap(); + claimInfoMap.put("name","Bob Dylan"); + claimInfoMap.put("age","22"); + + + String claim = dnaSdk.nativevm().dnaId().createDnaIdClaim(dids.get(0).dnaid,"passwordtest",dids.get(0).controls.get(0).getSalt(), "claim:context", claimInfoMap, metaDataMap,clvMap,expires); System.out.println(claim); + System.out.println(new String(Base64.getDecoder().decode(claim.split("\\.")[1]))); boolean b = dnaSdk.nativevm().dnaId().verifyDnaIdClaim(claim); System.out.println(b); From 7ad08b08218d1f46814646a1ca3ed2ca0e6dfde9 Mon Sep 17 00:00:00 2001 From: xizho10 Date: Fri, 3 Jan 2020 19:35:15 +0800 Subject: [PATCH 06/18] update project name --- DNASDKJava.iml => DNA-java-sdk.iml | 0 README.md | 4 ++-- docs/README.md | 4 ++-- docs/sdk_get_start.md | 12 ++++++------ pom.xml | 14 +++++++------- .../java/example/smartcontract/DeployCodeDemo.java | 4 ++-- 6 files changed, 19 insertions(+), 19 deletions(-) rename DNASDKJava.iml => DNA-java-sdk.iml (100%) diff --git a/DNASDKJava.iml b/DNA-java-sdk.iml similarity index 100% rename from DNASDKJava.iml rename to DNA-java-sdk.iml diff --git a/README.md b/README.md index 5c1f446..8b90b6c 100644 --- a/README.md +++ b/README.md @@ -33,10 +33,10 @@ mvn clean install Add maven dependency: ``` - + com.github.DNAProject - DNASDKJava/artifactId> + DNA-java-sdk/artifactId> 2.0.0 ``` diff --git a/docs/README.md b/docs/README.md index 1d1d5e0..4a23429 100644 --- a/docs/README.md +++ b/docs/README.md @@ -56,10 +56,10 @@ $ mvn clean install ``` - + com.github.DNAProject - DNASDKJava/artifactId> + DNA-java-sdk/artifactId> 2.0.0 ``` diff --git a/docs/sdk_get_start.md b/docs/sdk_get_start.md index 0550631..c6e1f62 100644 --- a/docs/sdk_get_start.md +++ b/docs/sdk_get_start.md @@ -75,7 +75,7 @@ com.github.DNAProject.account.Account acct2 = new com.github.DNAProject.account. #### 1.1.2 按钱包规范存储: -账户和身份信息保持在遵循钱包规范的文件中。[例子](https://github.com/DNAProject/DNASDKJava/blob/master/src/main/java/example/wallet/WalletDemo.java) +账户和身份信息保持在遵循钱包规范的文件中。[例子](https://github.com/DNAProject/DNA-java-sdk/blob/master/src/main/java/example/wallet/WalletDemo.java) @@ -134,7 +134,7 @@ Address recvAddr = Address.addressFromMultiPubKeys(2, acct1.serializePublicKey() ## 2. 原生资产转账 -参考例子:[例子](https://github.com/DNAProject/DNASDKJava/blob/master/src/main/java/example/transaction/MakeTxWithoutWalletDemo.java) +参考例子:[例子](https://github.com/DNAProject/DNA-java-sdk/blob/master/src/main/java/example/transaction/MakeTxWithoutWalletDemo.java) ### 2.1 初始化 @@ -564,7 +564,7 @@ dnaSdk.addSign(txRx,acct0); **SDK与签名机交互**: -[例子](https://github.com/DNAProject/DNASDKJava/blob/master/src/main/java/example/signature/SignServerDemo.java) +[例子](https://github.com/DNAProject/DNA-java-sdk/blob/master/src/main/java/example/signature/SignServerDemo.java) ```java 节点启动时打开签名机服务: @@ -595,7 +595,7 @@ dnaSdk.getSignServer().sendSigTransferTx("ont","TU5exRFVqjRi5wnMVzNoWKBq9WFncLXE **对数据做签名** -SDK提供直接对数据做签名的接口。[例子](https://github.com/DNAProject/DNASDKJava/blob/master/src/main/java/example/signature/SignatureDemo.java) +SDK提供直接对数据做签名的接口。[例子](https://github.com/DNAProject/DNA-java-sdk/blob/master/src/main/java/example/signature/SignatureDemo.java) ```java @@ -658,7 +658,7 @@ String txhash = dnaSdk.neovm().oep4().sendTransfer(acct1, acct2.getAddressU160() ### 3.3 并发 -实现步骤如 [例子](https://github.com/DNAProject/DNASDKJava/tree/master/src/main/java/example/oep/Oep4MultiTheadDemo.java) +实现步骤如 [例子](https://github.com/DNAProject/DNA-java-sdk/tree/master/src/main/java/example/oep/Oep4MultiTheadDemo.java) @@ -666,7 +666,7 @@ String txhash = dnaSdk.neovm().oep4().sendTransfer(acct1, acct2.getAddressU160() SDK发送注册Dnaid和转账等交易时,根据钱包中账户和身份信息解密出私钥再做签名,这个过程大概需要1-2秒时间。为了节省发交易时间,可以多线程或多机器事先创建交易,再批量发送。 -实现步骤如下,[例子](https://github.com/DNAProject/DNASDKJava/tree/master/src/main/java/example/transaction/CreateManyTx.java) +实现步骤如下,[例子](https://github.com/DNAProject/DNA-java-sdk/tree/master/src/main/java/example/transaction/CreateManyTx.java) ### 4.1 批量构造交易 diff --git a/pom.xml b/pom.xml index 1380dad..bea1770 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ 4.0.0 com.github.DNAProject - DNASDKJava + DNA-java-sdk 2.0.0 @@ -23,11 +23,11 @@ - DNASDKJava-snapshots + DNA-java-sdk-snapshots https://oss.sonatype.org/content/repositories/snapshots - DNASDKJava-release + DNA-java-sdk-release https://oss.sonatype.org/service/local/staging/deploy/maven2 @@ -41,15 +41,15 @@ master - https://github.com/DNAProject/DNASDKJava - scm:git:git@github.com:DNAProject/DNASDKJava.git - scm:git:git@github.com:DNAProject/DNASDKJava.git + https://github.com/DNAProject/DNA-java-sdk + scm:git:git@github.com:DNAProject/DNA-java-sdk.git + scm:git:git@github.com:DNAProject/DNA-java-sdk.git hellomyworld messixaviinsta0303@163.com - DNAProject + DNA-java-sdk diff --git a/src/main/java/example/smartcontract/DeployCodeDemo.java b/src/main/java/example/smartcontract/DeployCodeDemo.java index 5a07434..e93e47d 100644 --- a/src/main/java/example/smartcontract/DeployCodeDemo.java +++ b/src/main/java/example/smartcontract/DeployCodeDemo.java @@ -47,10 +47,10 @@ public static void main(String[] args) { String privatekey1 = "523c5fcf74823831756f0bcb3634234f10b3beb1c05595058534577752ad2d9f"; Account acct0 = new Account(Helper.hexToBytes(privatekey0), dnaSdk.defaultSignScheme); String code = ""; - code = "0114c56b05322e302e306a00527ac4681953797374656d2e53746f726167652e476574436f6e746578746a51527ac404544553546a52527ac404544553546a53527ac4586a54527ac40400e1f5056a55527ac422414e4835624872727431313158774e456e75505a6a3675393544643675374734443668204f6e746f6c6f67792e52756e74696d652e426173653538546f416464726573736a56527ac40500ac23fc066a57527ac401016a58527ac401026a59527ac401036a5a527ac40b546f74616c537570706c796a5b527ac40d5061757365436f6e74726163746a5c527ac4054f776e65726a5d527ac46c0137c56b6a00527ac46a51527ac46a52527ac46a51c304696e69747d9c7c75641500006a00c306ad05000000006e6c75666203006a51c3046e616d657d9c7c75641500006a00c3062107000000006e6c75666203006a51c30673796d626f6c7d9c7c75641500006a00c3063907000000006e6c75666203006a51c308646563696d616c737d9c7c75641500006a00c3065107000000006e6c75666203006a51c30b746f74616c537570706c797d9c7c75641500006a00c3066907000000006e6c75666203006a51c30962616c616e63654f667d9c7c756435006a52c3c0517d9e7c75640a00006c75666203006a52c300c36a54527ac46a54c3516a00c3069a07000000006e6c75666203006a51c3087472616e736665727d9c7c75644f006a52c3c0537d9e7c75640a00006c75666239006a52c300c36a55527ac46a52c351c36a56527ac46a52c352c36a57527ac46a57c36a56c36a55c3536a00c3060008000000006e6c75666203006a51c30d7472616e736665724d756c74697d9c7c756418006a52c3516a00c306160a000000006e6c75666203006a51c30c7472616e7366657246726f6d7d9c7c75645c006a52c3c0547d9e7c75640a00006c75666203006a52c300c36a58527ac46a52c351c36a55527ac46a52c352c36a56527ac46a52c353c36a57527ac46a57c36a56c36a55c36a58c3546a00c306f20b000000006e6c75666203006a51c307617070726f76657d9c7c75644f006a52c3c0537d9e7c75640a00006c75666203006a52c300c36a59527ac46a52c351c36a58527ac46a52c352c36a57527ac46a57c36a58c36a59c3536a00c306d20a000000006e6c75666203006a51c309616c6c6f77616e63657d9c7c756442006a52c3c0527d9e7c75640a00006c75666203006a52c300c36a59527ac46a52c351c36a58527ac46a58c36a59c3526a00c306b00e000000006e6c75666203006a51c3056f776e65727d9c7c75641500006a00c306fb0e000000006e6c75666203006a51c30769734f776e65727d9c7c756435006a52c3c0517d9e7c75640a00006c75666203006a52c300c36a54527ac46a54c3516a00c3062c0f000000006e6c75666203006a51c3117472616e736665724f776e6572736869707d9c7c756435006a52c3c0517d9e7c75640a00006c75666203006a52c300c36a54527ac46a54c3516a00c306770f000000006e6c75666203006a51c30570617573657d9c7c75641500006a00c306ce10000000006e6c75666203006a51c307756e70617573657d9c7c75641500006a00c3064111000000006e6c75666203006a51c3097669657750617573657d9c7c75641500006a00c306b411000000006e6c75666203006a51c30d667265657a654163636f756e747d9c7c756435006a52c3c0517d9e7c75640a00006c75666203006a52c300c36a54527ac46a54c3516a00c306a512000000006e6c75666203006a51c30f756e667265657a654163636f756e747d9c7c756435006a52c3c0517d9e7c75640a00006c75666203006a52c300c36a54527ac46a54c3516a00c3065013000000006e6c75666203006a51c31176696577467265657a654163636f756e747d9c7c756435006a52c3c0517d9e7c75640a00006c75666203006a52c300c36a54527ac46a54c3516a00c306fb13000000006e6c7566620300006c75665ac56b6a00527ac46a51527ac46203000e4f776e657220696c6c6567616c216a00c356c3c001147d9c7c75526a00c306a210000000006e756a00c356c36a00c35dc36a00c351c3681253797374656d2e53746f726167652e5075746a00c35dc36a00c351c3681253797374656d2e53746f726167652e4765746a53527ac413416c726561647920696e697469616c697a65646a00c35bc36a00c351c3681253797374656d2e53746f726167652e476574007d9c7c75526a00c306a210000000006e756a00c357c36a00c355c3956a54527ac46a54c36a00c35bc36a00c351c3681253797374656d2e53746f726167652e5075746a54c36a00c358c36a53c37e6a00c351c3681253797374656d2e53746f726167652e5075746a54c36a53c300087472616e7366657254c1681553797374656d2e52756e74696d652e4e6f746966796a53c300117472616e736665724f776e65727368697053c1681553797374656d2e52756e74696d652e4e6f74696679516c756655c56b6a00527ac46a51527ac46203006a00c352c36c756655c56b6a00527ac46a51527ac46203006a00c353c36c756655c56b6a00527ac46a51527ac46203006a00c354c36c756655c56b6a00527ac46a51527ac46203006a00c35bc36a00c351c3681253797374656d2e53746f726167652e4765746c756658c56b6a00527ac46a51527ac46a52527ac46203001461646472657373206c656e677468206572726f726a52c3c001147d9c7c75526a00c306a210000000006e756a00c358c36a52c37e6a00c351c3681253797374656d2e53746f726167652e4765746c75665ec56b6a00527ac46a51527ac46a52527ac46a53527ac46a54527ac46203001461646472657373206c656e677468206572726f726a53c3c001147d9c7c7576640e00756a52c3c001147d9c7c75526a00c306a210000000006e750f496e76616c696420696e766f6b65726a52c3681b53797374656d2e52756e74696d652e436865636b5769746e657373517d9c7c75526a00c306a210000000006e750e496e76616c696420416d6f756e746a54c3007da07c75526a00c306a210000000006e75006a00c306e511000000006e6a52c3516a00c3063514000000006e6a53c3516a00c3063514000000006e6a00c358c36a52c37e6a56527ac46a56c36a00c351c3681253797374656d2e53746f726167652e4765746a57527ac4124e6f7420656e6f7567682062616c616e63656a54c36a57c37da17c75526a00c306a210000000006e756a54c36a57c37d9c7c756425006a56c36a00c351c3681553797374656d2e53746f726167652e44656c6574656226006a57c36a54c3946a56c36a00c351c3681253797374656d2e53746f726167652e5075746a00c358c36a53c37e6a58527ac46a58c36a00c351c3681253797374656d2e53746f726167652e4765746a59527ac46a59c36a54c3936a58c36a00c351c3681253797374656d2e53746f726167652e5075746a54c36a53c36a52c3087472616e7366657254c1681553797374656d2e52756e74696d652e4e6f74696679516c75665bc56b6a00527ac46a51527ac46a52527ac4620300006a53527ac46a52c36a54527ac46a54c3c06a55527ac46a53c36a55c39f6485006a54c36a53c3c36a56527ac46a53c351936a53527ac46a56c3c0537d9e7c756423001b7472616e736665724d756c746920706172616d73206572726f722ef0620300147472616e736665724d756c7469206661696c65646a56c352c36a56c351c36a56c300c3536a00c3060008000000006e526a00c306a210000000006e756277ff516c75665cc56b6a00527ac46a51527ac46a52527ac46a53527ac46a54527ac46203001461646472657373206c656e677468206572726f726a53c3c001147d9c7c7576640e00756a52c3c001147d9c7c75526a00c306a210000000006e750f496e76616c696420696e766f6b65726a52c3681b53797374656d2e52756e74696d652e436865636b5769746e657373517d9c7c75526a00c306a210000000006e750e496e76616c696420616d6f756e746a54c3007da07c75526a00c306a210000000006e756a00c359c36a52c37e6a53c37e6a56527ac46a54c36a56c36a00c351c3681253797374656d2e53746f726167652e5075746a54c36a53c36a52c308617070726f76616c54c1681553797374656d2e52756e74696d652e4e6f74696679516c75660112c56b6a00527ac46a51527ac46a52527ac46a53527ac46a54527ac46a55527ac46203001461646472657373206c656e677468206572726f726a52c3c001147d9c7c7576641d00756a53c3c001147d9c7c7576640e00756a54c3c001147d9c7c75526a00c306a210000000006e750f496e76616c696420696e766f6b65726a52c3681b53797374656d2e52756e74696d652e436865636b5769746e657373517d9c7c75526a00c306a210000000006e75006a00c306e511000000006e6a52c3516a00c3063514000000006e6a53c3516a00c3063514000000006e6a54c3516a00c3063514000000006e6a00c358c36a53c37e6a57527ac46a57c36a00c351c3681253797374656d2e53746f726167652e4765746a58527ac40e496e76616c696420616d6f756e746a55c36a58c37da17c7576640c00756a55c3007da07c75526a00c306a210000000006e756a00c359c36a53c37e6a52c37e6a59527ac46a59c36a00c351c3681253797374656d2e53746f726167652e4765746a5a527ac46a00c358c36a54c37e6a5b527ac40e496e76616c696420616d6f756e746a55c36a5ac37da17c75526a00c306a210000000006e756a55c36a5ac37d9c7c756448006a59c36a00c351c3681553797374656d2e53746f726167652e44656c6574656a58c36a55c3946a57c36a00c351c3681253797374656d2e53746f726167652e5075746249006a5ac36a55c3946a59c36a00c351c3681253797374656d2e53746f726167652e5075746a58c36a55c3946a57c36a00c351c3681253797374656d2e53746f726167652e5075746a5bc36a00c351c3681253797374656d2e53746f726167652e4765746a5c527ac46a5cc36a55c3936a5bc36a00c351c3681253797374656d2e53746f726167652e5075746a55c36a54c36a53c3087472616e7366657254c1681553797374656d2e52756e74696d652e4e6f74696679516c756659c56b6a00527ac46a51527ac46a52527ac46a53527ac46203006a00c359c36a52c37e6a53c37e6a54527ac46a54c36a00c351c3681253797374656d2e53746f726167652e4765746c756655c56b6a00527ac46a51527ac46203006a00c35dc36a00c351c3681253797374656d2e53746f726167652e4765746c756657c56b6a00527ac46a51527ac46a52527ac46203006a00c35dc36a00c351c3681253797374656d2e53746f726167652e4765746a52c37d9c7c75640a00516c7566620700006c75666c756658c56b6a00527ac46a51527ac46a52527ac4620300006a00c3063d10000000006e1461646472657373206c656e677468206572726f726a52c3c001147d9c7c75526a00c306a210000000006e756a00c35dc36a00c351c3681253797374656d2e53746f726167652e4765746a54527ac46a52c36a00c35dc36a00c351c3681253797374656d2e53746f726167652e5075746a52c36a54c3117472616e736665724f776e65727368697053c1681553797374656d2e52756e74696d652e4e6f74696679516c756656c56b6a00527ac46a51527ac4620300094e6f74204f776e65726a00c35dc36a00c351c3681253797374656d2e53746f726167652e476574681b53797374656d2e52756e74696d652e436865636b5769746e657373526a00c306a210000000006e756c756657c56b6a00527ac46a51527ac46a52527ac46a53527ac46203006a52c391640a006a53c3f0620300516c756655c56b6a00527ac46a51527ac4620300006a00c3063d10000000006e006a00c306e511000000006e516a00c35cc36a00c351c3681253797374656d2e53746f726167652e507574510d636f6e7472616374506175736552c1681553797374656d2e52756e74696d652e4e6f74696679516c756655c56b6a00527ac46a51527ac4620300006a00c3063d10000000006e006a00c3064412000000006e006a00c35cc36a00c351c3681253797374656d2e53746f726167652e507574000d636f6e7472616374506175736552c1681553797374656d2e52756e74696d652e4e6f74696679516c756655c56b6a00527ac46a51527ac46203006a00c35cc36a00c351c3681253797374656d2e53746f726167652e4765746c756655c56b6a00527ac46a51527ac46203001b4e6f74207061757365207374617465206f6620436f6e74726163746a00c35cc36a00c351c3681253797374656d2e53746f726167652e476574007d9c7c75526a00c306a210000000006e756c756655c56b6a00527ac46a51527ac46203001d4e6f7420756e7061757365207374617465206f6620436f6e74726163746a00c35cc36a00c351c3681253797374656d2e53746f726167652e476574517d9c7c75526a00c306a210000000006e756c756658c56b6a00527ac46a51527ac46a52527ac4620300006a00c3063d10000000006e6a52c3516a00c3063514000000006e1461646472657373206c656e677468206572726f726a52c3c001147d9c7c75526a00c306a210000000006e75516a00c35ac36a52c37e6a00c351c3681253797374656d2e53746f726167652e507574516a52c30a75736572467265657a6553c1681553797374656d2e52756e74696d652e4e6f74696679516c756658c56b6a00527ac46a51527ac46a52527ac4620300006a00c3063d10000000006e6a52c3516a00c3069f14000000006e1461646472657373206c656e677468206572726f726a52c3c001147d9c7c75526a00c306a210000000006e75006a00c35ac36a52c37e6a00c351c3681253797374656d2e53746f726167652e507574006a52c30a75736572467265657a6553c1681553797374656d2e52756e74696d652e4e6f74696679516c756657c56b6a00527ac46a51527ac46a52527ac46203006a00c35ac36a52c37e6a00c351c3681253797374656d2e53746f726167652e4765746c756657c56b6a00527ac46a51527ac46a52527ac46203001d4e6f7420756e66726f7a656e207374617465206f66206163636f756e746a00c35ac36a52c37e6a00c351c3681253797374656d2e53746f726167652e476574007d9c7c75526a00c306a210000000006e756c756657c56b6a00527ac46a51527ac46a52527ac46203001b4e6f742066726f7a656e207374617465206f66206163636f756e746a00c35ac36a52c37e6a00c351c3681253797374656d2e53746f726167652e476574517d9c7c75526a00c306a210000000006e756c7566"; + code = "5ec56b05322e302e306a00527ac4681953797374656d2e53746f726167652e476574436f6e746578746a51527ac4074d79546f6b656e6a52527ac4034d59546a53527ac4586a54527ac40400e1f5056a55527ac422414e4835624872727431313158774e456e75505a6a36753935446436753747344436681b444e412e52756e74696d652e426173653538546f416464726573736a56527ac40400ca9a3b6a57527ac401016a58527ac401026a59527ac40b546f74616c537570706c796a5a527ac46c0124c56b6a00527ac46a51527ac46a52527ac46a51c304696e69747d9c7c75641500006a00c3067f03000000006e6c75666203006a51c3046e616d657d9c7c75641500006a00c306ad04000000006e6c75666203006a51c30673796d626f6c7d9c7c75641500006a00c306c504000000006e6c75666203006a51c308646563696d616c737d9c7c75641500006a00c306dd04000000006e6c75666203006a51c30b746f74616c537570706c797d9c7c75641500006a00c306f504000000006e6c75666203006a51c30962616c616e63654f667d9c7c756435006a52c3c0517d9e7c75640a00006c75666203006a52c300c36a54527ac46a54c3516a00c3062605000000006e6c75666203006a51c3087472616e736665727d9c7c75644f006a52c3c0537d9e7c75640a00006c75666239006a52c300c36a55527ac46a52c351c36a56527ac46a52c352c36a57527ac46a57c36a56c36a55c3536a00c3068605000000006e6c75666203006a51c30d7472616e736665724d756c74697d9c7c756418006a52c3516a00c3062c07000000006e6c75666203006a51c30c7472616e7366657246726f6d7d9c7c75645c006a52c3c0547d9e7c75640a00006c75666203006a52c300c36a58527ac46a52c351c36a55527ac46a52c352c36a56527ac46a52c353c36a57527ac46a57c36a56c36a55c36a58c3546a00c306f808000000006e6c75666203006a51c307617070726f76657d9c7c75644f006a52c3c0537d9e7c75640a00006c75666203006a52c300c36a59527ac46a52c351c36a58527ac46a52c352c36a57527ac46a57c36a58c36a59c3536a00c306e807000000006e6c75666203006a51c309616c6c6f77616e63657d9c7c756442006a52c3c0527d9e7c75640a00006c75666203006a52c300c36a59527ac46a52c351c36a58527ac46a58c36a59c3526a00c306400b000000006e6c7566620300006c756659c56b6a00527ac46a51527ac46203006a00c356c3c001147d9e7c756434000e4f776e657220696c6c6567616c2151c176c9681553797374656d2e52756e74696d652e4e6f74696679006c75666203006a00c35ac36a00c351c3681253797374656d2e53746f726167652e47657464360014416c726561647920696e697469616c697a656421681553797374656d2e52756e74696d652e4e6f74696679006c7566628a006a00c357c36a00c355c3956a52527ac46a52c36a00c35ac36a00c351c3681253797374656d2e53746f726167652e5075746a52c36a00c358c36a00c356c37e6a00c351c3681253797374656d2e53746f726167652e5075746a52c36a00c356c300087472616e7366657254c1681553797374656d2e52756e74696d652e4e6f74696679516c75666c756655c56b6a00527ac46a51527ac46203006a00c352c36c756655c56b6a00527ac46a51527ac46203006a00c353c36c756655c56b6a00527ac46a51527ac46203006a00c354c36c756655c56b6a00527ac46a51527ac46203006a00c35ac36a00c351c3681253797374656d2e53746f726167652e4765746c756657c56b6a00527ac46a51527ac46a52527ac46203006a52c3c001147d9e7c75641c001461646472657373206c656e677468206572726f72f06203006a00c358c36a52c37e6a00c351c3681253797374656d2e53746f726167652e4765746c75665ec56b6a00527ac46a51527ac46a52527ac46a53527ac46a54527ac46203006a53c3c001147d9e7c7576630e00756a52c3c001147d9e7c75641c001461646472657373206c656e677468206572726f72f06203006a52c3681b53797374656d2e52756e74696d652e436865636b5769746e657373007d9c7c7576630c00756a54c3007d9f7c75640a00006c75666203006a00c358c36a52c37e6a55527ac46a55c36a00c351c3681253797374656d2e53746f726167652e4765746a56527ac46a54c36a56c37da07c75640a00006c75666203006a54c36a56c37d9c7c756425006a55c36a00c351c3681553797374656d2e53746f726167652e44656c6574656226006a56c36a54c3946a55c36a00c351c3681253797374656d2e53746f726167652e5075746a00c358c36a53c37e6a57527ac46a57c36a00c351c3681253797374656d2e53746f726167652e4765746a58527ac46a58c36a54c3936a57c36a00c351c3681253797374656d2e53746f726167652e5075746a54c36a53c36a52c3087472616e7366657254c1681553797374656d2e52756e74696d652e4e6f74696679516c75665ac56b6a00527ac46a51527ac46a52527ac4620300006a53527ac46a52c36a54527ac46a54c3c06a55527ac46a53c36a55c39f6485006a54c36a53c3c36a56527ac46a53c351936a53527ac46a56c3c0537d9e7c756423001b7472616e736665724d756c746920706172616d73206572726f722ef06203006a56c352c36a56c351c36a56c300c3536a00c3068605000000006e007d9c7c75641d00157472616e736665724d756c7469206661696c65642ef06203006277ff516c75665cc56b6a00527ac46a51527ac46a52527ac46a53527ac46a54527ac46203006a53c3c001147d9e7c7576630e00756a52c3c001147d9e7c75641c001461646472657373206c656e677468206572726f72f06203006a52c3681b53797374656d2e52756e74696d652e436865636b5769746e657373007d9c7c75640a00006c75666203006a54c36a52c3516a00c3062605000000006e7da07c7576630c00756a54c3007d9f7c75640a00006c75666203006a00c359c36a52c37e6a53c37e6a56527ac46a54c36a56c36a00c351c3681253797374656d2e53746f726167652e5075746a54c36a53c36a52c308617070726f76616c54c1681553797374656d2e52756e74696d652e4e6f74696679516c75660113c56b6a00527ac46a51527ac46a52527ac46a53527ac46a54527ac46a55527ac46203006a52c3c001147d9e7c7576631d00756a53c3c001147d9e7c7576630e00756a54c3c001147d9e7c75641c001461646472657373206c656e677468206572726f72f06203006a52c3681b53797374656d2e52756e74696d652e436865636b5769746e657373007d9c7c75640a00006c75666203006a00c358c36a53c37e6a56527ac46a56c36a00c351c3681253797374656d2e53746f726167652e4765746a57527ac46a55c36a57c37da07c7576630c00756a55c3007d9f7c75640a00006c75666203006a00c359c36a53c37e6a52c37e6a58527ac46a58c36a00c351c3681253797374656d2e53746f726167652e4765746a59527ac46a00c358c36a54c37e6a5a527ac46a55c36a59c37da07c75640a00006c7566629b006a55c36a59c37d9c7c756448006a58c36a00c351c3681553797374656d2e53746f726167652e44656c6574656a57c36a55c3946a56c36a00c351c3681253797374656d2e53746f726167652e5075746249006a59c36a55c3946a58c36a00c351c3681253797374656d2e53746f726167652e5075746a57c36a55c3946a56c36a00c351c3681253797374656d2e53746f726167652e5075746a5ac36a00c351c3681253797374656d2e53746f726167652e4765746a5b527ac46a5bc36a55c3936a5ac36a00c351c3681253797374656d2e53746f726167652e5075746a55c36a54c36a53c3087472616e7366657254c1681553797374656d2e52756e74696d652e4e6f74696679516c756659c56b6a00527ac46a51527ac46a52527ac46a53527ac46203006a00c359c36a52c37e6a53c37e6a54527ac46a54c36a00c351c3681253797374656d2e53746f726167652e4765746c7566"; System.out.println("ContractAddress:" + Address.AddressFromVmCode(code).toHexString()); - if (true) { + if (false) { System.out.println(dnaSdk.getConnect().getContractJson(Address.AddressFromVmCode(code).toHexString())); System.exit(0); } From 8aa82a1d84cf1137754a35c4fa0bcad7c86d7dab Mon Sep 17 00:00:00 2001 From: xizho10 Date: Fri, 3 Jan 2020 19:38:52 +0800 Subject: [PATCH 07/18] add smartcontract file --- .../java/com/github/DNAProject/DnaSdk.java | 645 ++++++++ .../DNAProject/smartcontract/NativeVm.java | 70 + .../DNAProject/smartcontract/NeoVm.java | 110 ++ .../github/DNAProject/smartcontract/Vm.java | 144 ++ .../DNAProject/smartcontract/WasmVm.java | 63 + .../smartcontract/nativevm/Auth.java | 625 +++++++ .../smartcontract/nativevm/DnaId.java | 1177 ++++++++++++++ .../smartcontract/nativevm/Gas.java | 457 ++++++ .../smartcontract/nativevm/GlobalParams.java | 337 ++++ .../smartcontract/nativevm/Governance.java | 1448 +++++++++++++++++ .../smartcontract/nativevm/abi/AbiEvent.java | 68 + .../nativevm/abi/AbiFunction.java | 69 + .../smartcontract/nativevm/abi/AbiInfo.java | 106 ++ .../nativevm/abi/NativeBuildParams.java | 156 ++ .../smartcontract/nativevm/abi/Parameter.java | 95 ++ .../smartcontract/nativevm/abi/Struct.java | 18 + .../smartcontract/nativevm/abi/SubType.java | 59 + .../smartcontract/neovm/ClaimRecord.java | 224 +++ .../DNAProject/smartcontract/neovm/Nep5.java | 225 +++ .../DNAProject/smartcontract/neovm/Oep4.java | 385 +++++ .../DNAProject/smartcontract/neovm/Oep5.java | 276 ++++ .../DNAProject/smartcontract/neovm/Oep8.java | 472 ++++++ .../smartcontract/neovm/Record.java | 121 ++ .../smartcontract/neovm/abi/AbiEvent.java | 67 + .../smartcontract/neovm/abi/AbiFunction.java | 81 + .../smartcontract/neovm/abi/AbiInfo.java | 105 ++ .../smartcontract/neovm/abi/BuildParams.java | 356 ++++ .../smartcontract/neovm/abi/Parameter.java | 108 ++ .../smartcontract/neovm/abi/Struct.java | 18 + .../smartcontract/neovm/oep5/Oep5Param.java | 10 + .../smartcontract/neovm/oep8/Oep8State.java | 14 + .../neovm/oep8/TransferFrom.java | 16 + 32 files changed, 8125 insertions(+) create mode 100644 src/main/java/com/github/DNAProject/DnaSdk.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/NativeVm.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/NeoVm.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/Vm.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/WasmVm.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/nativevm/Auth.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/nativevm/DnaId.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/nativevm/Gas.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/nativevm/GlobalParams.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/nativevm/Governance.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/nativevm/abi/AbiEvent.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/nativevm/abi/AbiFunction.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/nativevm/abi/AbiInfo.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/nativevm/abi/NativeBuildParams.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/nativevm/abi/Parameter.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/nativevm/abi/Struct.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/nativevm/abi/SubType.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/neovm/ClaimRecord.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/neovm/Nep5.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/neovm/Oep4.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/neovm/Oep5.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/neovm/Oep8.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/neovm/Record.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/neovm/abi/AbiEvent.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/neovm/abi/AbiFunction.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/neovm/abi/AbiInfo.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/neovm/abi/BuildParams.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/neovm/abi/Parameter.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/neovm/abi/Struct.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/neovm/oep5/Oep5Param.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/neovm/oep8/Oep8State.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/neovm/oep8/TransferFrom.java diff --git a/src/main/java/com/github/DNAProject/DnaSdk.java b/src/main/java/com/github/DNAProject/DnaSdk.java new file mode 100644 index 0000000..5441e5d --- /dev/null +++ b/src/main/java/com/github/DNAProject/DnaSdk.java @@ -0,0 +1,645 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Common; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.DataSignature; +import com.github.DNAProject.core.payload.DeployCode; +import com.github.DNAProject.core.payload.InvokeCode; +import com.github.DNAProject.core.program.Program; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.core.asset.Sig; +import com.github.DNAProject.crypto.Digest; +import com.github.DNAProject.crypto.SignatureScheme; +import com.github.DNAProject.sdk.exception.SDKException; +import com.github.DNAProject.sdk.manager.*; +import com.github.DNAProject.smartcontract.NativeVm; +import com.github.DNAProject.smartcontract.NeoVm; +import com.github.DNAProject.smartcontract.Vm; +import com.github.DNAProject.smartcontract.WasmVm; +import com.github.DNAProject.smartcontract.nativevm.abi.NativeBuildParams; +import com.github.DNAProject.smartcontract.nativevm.abi.Struct; +import com.github.DNAProject.smartcontract.neovm.abi.BuildParams; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.*; + +/** + * DNA Sdk + */ +public class DnaSdk { + private WalletMgr walletMgr; + private ConnectMgr connRpc; + private ConnectMgr connRestful; + private ConnectMgr connWebSocket; + private ConnectMgr connDefault; + private ConnectMgr sideChainConnectMgr; + + private Vm vm = null; + private NativeVm nativevm = null; + private NeoVm neovm = null; + private WasmVm wasmvm = null; + private SignServer signServer = null; + + + private static DnaSdk instance = null; + public SignatureScheme defaultSignScheme = SignatureScheme.SHA256WITHECDSA; + public long DEFAULT_GAS_LIMIT = 20000; + public long DEFAULT_DEPLOY_GAS_LIMIT = 30000000; + public static synchronized DnaSdk getInstance(){ + if(instance == null){ + instance = new DnaSdk(); + } + return instance; + } + private DnaSdk(){ + } + public SignServer getSignServer() throws SDKException{ + if(signServer == null){ + throw new SDKException(ErrorCode.OtherError("signServer null")); + } + return signServer; + } + public NativeVm nativevm() throws SDKException{ + if(nativevm == null){ + vm(); + nativevm = new NativeVm(getInstance()); + } + return nativevm; + } + public NeoVm neovm() { + if(neovm == null){ + vm(); + neovm = new NeoVm(getInstance()); + } + return neovm; + } + public WasmVm wasmvm() { + if(wasmvm == null){ + vm(); + wasmvm = new WasmVm(getInstance()); + } + return wasmvm; + } + + public Vm vm() { + if(vm == null){ + vm = new Vm(getInstance()); + } + return vm; + } + public ConnectMgr getRpc() throws SDKException{ + if(connRpc == null){ + throw new SDKException(ErrorCode.ConnRestfulNotInit); + } + return connRpc; + } + + public ConnectMgr getRestful() throws SDKException{ + if(connRestful == null){ + throw new SDKException(ErrorCode.ConnRestfulNotInit); + } + return connRestful; + } + public ConnectMgr getConnect(){ + if(connDefault != null){ + return connDefault; + } + if(connRpc != null){ + return connRpc; + } + if(connRestful != null){ + return connRestful; + } + if(connWebSocket != null){ + return connWebSocket; + } + return null; + } + + public ConnectMgr getSideChainConnectMgr() { + return sideChainConnectMgr; + } + + public void setSideChainRpc(String url) { + this.sideChainConnectMgr = new ConnectMgr(url, "rpc"); + } + public void setSideChainRest(String url) { + this.sideChainConnectMgr = new ConnectMgr(url, "restful"); + } + public void setSideChainWebsocket(String url,Object lock) { + this.sideChainConnectMgr = new ConnectMgr(url, "websocket", lock); + } + public void setDefaultConnect(ConnectMgr conn){ + connDefault = conn; + } + public void setConnectTestNet(){ + try { + String rpcUrl = "http://polaris1.ont.io:20336"; + getInstance().setRpc(rpcUrl); + connDefault = getInstance().getRpc(); + } catch (SDKException e) { + e.printStackTrace(); + } + } + public void setConnectMainNet(){ + try { + String rpcUrl = "http://dappnode1.ont.io:20336"; + getInstance().setRpc(rpcUrl); + connDefault = getInstance().getRpc(); + } catch (SDKException e) { + e.printStackTrace(); + } + } + public ConnectMgr getWebSocket() throws SDKException{ + if(connWebSocket == null){ + throw new SDKException(ErrorCode.WebsocketNotInit); + } + return connWebSocket; + } + + + /** + * get Wallet Mgr + * @return + */ + public WalletMgr getWalletMgr() { + return walletMgr; + } + + + /** + * + * @param scheme + */ + public void setSignatureScheme(SignatureScheme scheme) { + defaultSignScheme = scheme; + walletMgr.setSignatureScheme(scheme); + } + + public void setSignServer(String url) throws Exception{ + this.signServer = new SignServer(url); + } + public void setRpc(String url) { + this.connRpc = new ConnectMgr(url, "rpc"); + } + + public void setRestful(String url) { + this.connRestful = new ConnectMgr(url,"restful"); + } + + public void setWesocket(String url,Object lock) { + connWebSocket = new ConnectMgr(url,"websocket",lock); + } + /** + * + * @param path + */ + public void openWalletFile(String path) { + + try { + this.walletMgr = new WalletMgr(path,defaultSignScheme); + setSignatureScheme(defaultSignScheme); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * + * @param tx + * @param addr + * @param password + * @return + * @throws Exception + */ + public Transaction addSign(Transaction tx,String addr,String password,byte[] salt) throws Exception { + return addSign(tx,getWalletMgr().getAccount(addr,password,salt)); + } + public Transaction addSign(Transaction tx,Account acct) throws Exception { + if(tx.sigs == null){ + tx.sigs = new Sig[0]; + } else { + if (tx.sigs.length >= Common.TX_MAX_SIG_SIZE) { + throw new SDKException(ErrorCode.ParamErr("the number of transaction signatures should not be over 16")); + } + } + Sig[] sigs = new Sig[tx.sigs.length + 1]; + for(int i= 0; i< tx.sigs.length; i++){ + sigs[i] = tx.sigs[i]; + } + sigs[tx.sigs.length] = new Sig(); + sigs[tx.sigs.length].M = 1; + sigs[tx.sigs.length].pubKeys = new byte[1][]; + sigs[tx.sigs.length].sigData = new byte[1][]; + sigs[tx.sigs.length].pubKeys[0] = acct.serializePublicKey(); + sigs[tx.sigs.length].sigData[0] = tx.sign(acct,acct.getSignatureScheme()); + tx.sigs = sigs; + return tx; + } + + /** + * + * @param tx + * @param M + * @param pubKeys + * @param acct + * @return + * @throws Exception + */ + public Transaction addMultiSign(Transaction tx,int M,byte[][] pubKeys, Account acct) throws Exception { + addMultiSign(tx,M,pubKeys,tx.sign(acct, acct.getSignatureScheme())); + return tx; + } + public Transaction addMultiSign(Transaction tx,int M,byte[][] pubKeys, byte[] signatureData) throws Exception { + pubKeys = Program.sortPublicKeys(pubKeys); + if (tx.sigs == null) { + tx.sigs = new Sig[0]; + } else { + if (tx.sigs.length > Common.TX_MAX_SIG_SIZE || M > pubKeys.length || M <= 0 || signatureData == null || pubKeys == null) { + throw new SDKException(ErrorCode.ParamError); + } + for (int i = 0; i < tx.sigs.length; i++) { + if(Arrays.deepEquals(tx.sigs[i].pubKeys,pubKeys)){ + if (tx.sigs[i].sigData.length + 1 > pubKeys.length) { + throw new SDKException(ErrorCode.ParamErr("too more sigData")); + } + if(tx.sigs[i].M != M){ + throw new SDKException(ErrorCode.ParamErr("M error")); + } + int len = tx.sigs[i].sigData.length; + byte[][] sigData = new byte[len+1][]; + for (int j = 0; j < tx.sigs[i].sigData.length; j++) { + sigData[j] = tx.sigs[i].sigData[j]; + } + sigData[len] = signatureData; + tx.sigs[i].sigData = sigData; + return tx; + } + } + } + Sig[] sigs = new Sig[tx.sigs.length + 1]; + for (int i = 0; i < tx.sigs.length; i++) { + sigs[i] = tx.sigs[i]; + } + sigs[tx.sigs.length] = new Sig(); + sigs[tx.sigs.length].M = M; + sigs[tx.sigs.length].pubKeys = pubKeys; + sigs[tx.sigs.length].sigData = new byte[1][]; + sigs[tx.sigs.length].sigData[0] = signatureData; + + tx.sigs = sigs; + return tx; + } + public Transaction signTx(Transaction tx, String addressOrDnaid, String password,byte[] salt) throws Exception{ + signTx(tx, new Account[][]{{getWalletMgr().getAccount(addressOrDnaid, password,salt)}}); + return tx; + } + /** + * sign tx + * @param tx + * @param accounts + * @return + */ + public Transaction signTx(Transaction tx, Account[][] accounts) throws Exception{ + if (accounts.length > Common.TX_MAX_SIG_SIZE) { + throw new SDKException(ErrorCode.ParamErr("the number of transaction signatures should not be over 16")); + } + Sig[] sigs = new Sig[accounts.length]; + for (int i = 0; i < accounts.length; i++) { + sigs[i] = new Sig(); + sigs[i].pubKeys = new byte[accounts[i].length][]; + sigs[i].sigData = new byte[accounts[i].length][]; + for (int j = 0; j < accounts[i].length; j++) { + sigs[i].M++; + byte[] signature = tx.sign(accounts[i][j], accounts[i][j].getSignatureScheme()); + sigs[i].pubKeys[j] = accounts[i][j].serializePublicKey(); + sigs[i].sigData[j] = signature; + } + } + tx.sigs = sigs; + return tx; + } + + /** + * signTx + * @param tx + * @param accounts + * @param M + * @return + * @throws SDKException + */ + public Transaction signTx(Transaction tx, Account[][] accounts, int[] M) throws Exception { + if (accounts.length > Common.TX_MAX_SIG_SIZE) { + throw new SDKException(ErrorCode.ParamErr("the number of transaction signatures should not be over 16")); + } + if (M.length != accounts.length) { + throw new SDKException(ErrorCode.ParamError); + } + tx = signTx(tx,accounts); + for (int i = 0; i < tx.sigs.length; i++) { + if (M[i] > tx.sigs[i].pubKeys.length || M[i] < 0) { + throw new SDKException(ErrorCode.ParamError); + } + tx.sigs[i].M = M[i]; + } + return tx; + } + + public byte[] signatureData(Account acct, byte[] data) throws SDKException { + DataSignature sign = null; + try { + data = Digest.sha256(Digest.sha256(data)); + sign = new DataSignature(defaultSignScheme, acct, data); + return sign.signature(); + } catch (Exception e) { + throw new SDKException(e); + } + } + + public boolean verifySignature(byte[] pubkey, byte[] data, byte[] signature) throws SDKException { + DataSignature sign = null; + try { + sign = new DataSignature(); + data = Digest.sha256(Digest.sha256(data)); + return sign.verifySignature(new Account(false, pubkey), data, signature); + } catch (Exception e) { + throw new SDKException(e); + } + } + public boolean verifyTransaction(Transaction tx) { + try { + boolean result = true; + for (int i = 0; i < tx.sigs.length; i++) { + if (tx.sigs[i].M == 1) { + if (tx.sigs[i].pubKeys.length != 1 || tx.sigs[i].sigData.length != 1) { + throw new SDKException(ErrorCode.OtherError("index" + i + "pubKeys or sigData number != 1")); + } + Account account = new Account(false, tx.sigs[i].pubKeys[0]); + boolean verify = account.verifySignature(Digest.hash256(tx.getHashData()), tx.sigs[i].sigData[0]); + if (!verify) { + return false; + } + } else if (tx.sigs[i].M > 1) { + int m = 0; + for (int j = 0; j < tx.sigs[i].pubKeys.length; j++) { + Account account = new Account(false, tx.sigs[i].pubKeys[j]); + for (int k = 0; k < tx.sigs[i].sigData.length; k++) { + boolean verify = account.verifySignature(Digest.hash256(tx.getHashData()), tx.sigs[i].sigData[k]); + if (verify) { + m++; + break; + } + } + } + if (m < tx.sigs[i].M) { + return false; + } + } + } + return result; + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + private void buildMap(Map map,Object ele){ + try { + for(Map.Entry e:((Map) ele).entrySet()) { + Object tmp = e.getValue(); + if(tmp instanceof String){ + String pre = ((String) tmp).substring(0,10); + if(pre.contains("String")) { + String data = ((String) tmp).replace("String:",""); + e.setValue(data.getBytes()); + }else if(pre.contains("ByteArray")) { + String data = ((String) tmp).replace("ByteArray:",""); + e.setValue(Helper.hexToBytes(data)); + }else if(pre.contains("Long")) { + String data = ((String) tmp).replace("Long:",""); + e.setValue(data); + }else if(pre.contains("Address")) { + String data = ((String) tmp).replace("Address:",""); + e.setValue(Address.decodeBase58(data).toArray()); + } else { + throw new Exception(ErrorCode.OtherError("String type data error: "+ e)); + } + }else if(tmp instanceof Map){ + Map data = new HashMap(); + buildMap(data, tmp); + e.setValue(data); + } + map.put(e.getKey(),e.getValue()); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + private void buildArgs(List args,Object ele){ + try { + if(ele instanceof Boolean){ + args.add(ele); + }else if(ele instanceof Long){ + args.add(ele); + } else if(ele instanceof Integer){ + args.add(ele); + } else if(ele instanceof Map){ + Map map = new HashMap(); + buildMap(map,ele); + args.add(map); + } else if(ele instanceof String){ + if(((String) ele).substring(0,5).contains("Long:")) { + String data = ((String) ele).replace("Long:",""); + args.add(new BigInteger(data).longValue()); + }else if(((String) ele).substring(0,7).contains("String:")) { + String data = ((String) ele).replace("String:",""); + args.add(data.getBytes()); + }else if(((String) ele).substring(0,8).contains("Address:")) { + String data = ((String) ele).replace("Address:",""); + args.add(Address.decodeBase58(data).toArray()); + }else if(((String) ele).substring(0,10).contains("ByteArray:")) { + String data = ((String) ele).replace("ByteArray:",""); + args.add(Helper.hexToBytes(data)); + }else { + throw new Exception(ErrorCode.OtherError("String type data error: "+ele)); + } + } else if(ele instanceof List){ + List tmp = new ArrayList(); + for (int i = 0; i < ((List)ele).size(); i++) { + buildArgs(tmp, ((List) ele).get(i)); + } + args.add(tmp); + } else{ + throw new Exception(ErrorCode.OtherError("type not found")); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + public List[] buildInvokeFunctionByJson(String configStr) { + try { + Map config = (Map) JSON.parseObject(configStr); + List functions = ((List)config.get("functions")); + List[] paramLists = new List[functions.size()]; + for(int i =0;i < functions.size();i++) { + Map func = (Map)functions.get(i); + String operation = (String) func.get("operation"); + List args = (List) func.get("args"); + List paramList = new ArrayList<>(); + paramList.add(operation.getBytes()); + List args2 = new ArrayList(); + for (int j = 0; j < args.size(); j++) { + Object ele = ((Map) args.get(j)).get("value"); + buildArgs(args2, ele); + } + paramList.add(args2); + paramLists[i] = paramList; + } + return paramLists; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + private Transaction makeNativeTransaction(String contractHash, List paramList, String payer, long gasLimit, long gasPrice) { + try { + String GAS = "0200000000000000000000000000000000000000"; + String DNAID = "0300000000000000000000000000000000000000"; + String method = new String((byte[]) paramList.get(0)); + List list = new ArrayList(); + Struct struct = new Struct(); + struct.list = (List) paramList.get(1); + if (contractHash.equals(GAS)) { + List listStruct = new ArrayList(); + listStruct.add(struct); + if(method.equals("transfer")) { + list.add(listStruct); + }else{ + list.add(struct); + } + }else if(contractHash.equals(DNAID)){ + if(method.equals("getDDO")){ + list.add(struct.list.get(0)); + }else { + list.add(struct); + } + } + byte[] args = NativeBuildParams.createCodeParamsScript(list); + return vm().buildNativeParams(new Address(Helper.hexToBytes(Helper.reverse(contractHash))), method, args, payer, gasLimit, gasPrice); + } catch (SDKException e) { + e.printStackTrace(); + } + return null; + } + + public Transaction[] makeTransactionByJson(String str) { + Map map = JSON.parseObject(str); + Map config = null; + try { + String action = ((String) map.get("action")); + if (!action.equals("invoke") && !action.equals("invokeRead") && !action.equals("invokePasswordFree")) { + throw new Exception(ErrorCode.OtherError("not found action is invoke or invokeRead or invokePasswordFree")); + } + config = (Map) ((Map) map.get("params")).get("invokeConfig"); + String payer = (String) config.get("payer"); + long gasLimit = (int) config.get("gasLimit"); + long gasPrice = (int) config.get("gasPrice"); + String contractHash = (String) config.get("contractHash"); + + List[] paramList = buildInvokeFunctionByJson(JSON.toJSONString(config)); + Transaction[] txs = new Transaction[paramList.length]; + for(int i=0;i< paramList.length;i++) { + if(contractHash.contains("00000000000000000000000000000000000000")){ + txs[i] = makeNativeTransaction(contractHash,paramList[i],payer, gasLimit, gasPrice); + } else { + byte[] params = BuildParams.createCodeParamsScript(paramList[i]); + txs[i] = vm().makeInvokeCodeTransaction(Helper.reverse(contractHash), null, params, payer, gasLimit, gasPrice); + } + } + return txs; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public Map parseTransaction(String txhexstr) throws SDKException { + Map map = new HashMap(); + try { + Transaction tx = Transaction.deserializeFrom(Helper.hexToBytes(txhexstr)); + if (tx instanceof DeployCode) { + map.put("txType", "deploy"); + map.put("author", ((DeployCode) tx).author); + map.put("email", ((DeployCode) tx).email); + map.put("version", ((DeployCode) tx).version); + map.put("description", ((DeployCode) tx).description); + map.put("name", ((DeployCode) tx).name); + } else if (tx instanceof InvokeCode) { + map.put("txType", "invoke"); + byte[] code = ((InvokeCode) tx).code; + String codeHexStr = Helper.toHexString(code); + if (codeHexStr.length() > 44 && codeHexStr.substring(codeHexStr.length() - 44, codeHexStr.length()).equals(Helper.toHexString(Vm.NATIVE_INVOKE_NAME.getBytes()))) { + if (codeHexStr.substring(codeHexStr.length() - 92 - 16, codeHexStr.length() - 92).equals(Helper.toHexString("transfer".getBytes()))) { + map.put("method", "transfer"); + map.put("from", Address.parse(codeHexStr.substring(8, 48)).toBase58()); + map.put("to", Address.parse(codeHexStr.substring(56, 96)).toBase58()); + map.put("amount", new BigInteger("00")); + if (codeHexStr.substring(102, 103).equals("5")) { + map.put("amount", code[51] - 0x50); + } else { + map.put("amount", Helper.BigIntFromNeoBytes(Helper.hexToBytes(codeHexStr.substring(104, 104 + code[51] * 2)))); + } + if (codeHexStr.substring(codeHexStr.length() - 50 - 40, codeHexStr.length() - 50).equals(this.nativevm().gas().getContractAddress())) { + map.put("asset", "gas"); + map.put("amount", ((BigInteger) map.get("amount")).doubleValue() / 1000000000L); + } + } else if (codeHexStr.substring(codeHexStr.length() - 92 - 24, codeHexStr.length() - 92).equals(Helper.toHexString("transferFrom".getBytes()))) { + map.put("method", "transferFrom"); + map.put("from", Address.parse(codeHexStr.substring(8, 48)).toBase58()); + map.put("to", Address.parse(codeHexStr.substring(56, 96)).toBase58()); + map.put("amount", new BigInteger("00")); + if (codeHexStr.substring(102, 103).equals("5")) { + map.put("amount", code[51] - 0x50); + } else { + map.put("amount", Helper.BigIntFromNeoBytes(Helper.hexToBytes(codeHexStr.substring(104, 104 + code[51] * 2)))); + } + if (codeHexStr.substring(codeHexStr.length() - 50 - 40, codeHexStr.length() - 50).equals(this.nativevm().gas().getContractAddress())) { + map.put("asset", "gas"); + map.put("amount", ((BigInteger) map.get("amount")).doubleValue() / 1000000000L); + } + } + } + } else { + throw new SDKException(ErrorCode.OtherError("tx type error")); + } + } catch (IOException e) { + e.printStackTrace(); + } + return map; + } +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/NativeVm.java b/src/main/java/com/github/DNAProject/smartcontract/NativeVm.java new file mode 100644 index 0000000..8257dad --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/NativeVm.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.smartcontract; + +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.smartcontract.nativevm.*; + +public class NativeVm { + private Gas gas = null; + private DnaId dnaId = null; + private GlobalParams globalParams = null; + private Auth auth = null; + private Governance governance = null; + private DnaSdk sdk; + public NativeVm(DnaSdk sdk){ + this.sdk = sdk; + } + /** + * get Asset Tx + * @return instance + */ + + public Gas gas() { + if(gas == null){ + gas = new Gas(sdk); + } + return gas; + } + public DnaId dnaId(){ + if (dnaId == null){ + dnaId = new DnaId(sdk); + } + return dnaId; + } + public GlobalParams gParams(){ + if (globalParams == null){ + globalParams = new GlobalParams(sdk); + } + return globalParams; + } + public Auth auth(){ + if (auth == null){ + auth = new Auth(sdk); + } + return auth; + } + public Governance governance(){ + if (governance == null){ + governance = new Governance(sdk); + } + return governance; + } +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/NeoVm.java b/src/main/java/com/github/DNAProject/smartcontract/NeoVm.java new file mode 100644 index 0000000..564ca36 --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/NeoVm.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.smartcontract; + +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.smartcontract.neovm.*; +import com.github.DNAProject.smartcontract.neovm.abi.AbiFunction; +import com.github.DNAProject.sdk.exception.SDKException; +import com.github.DNAProject.smartcontract.neovm.abi.BuildParams; + +public class NeoVm { + private Oep4 oep4Tx = null; + private Oep5 oep5Tx = null; + private Oep8 oep8Tx = null; + private Record recordTx = null; + private ClaimRecord claimRecordTx = null; + + private DnaSdk sdk; + public NeoVm(DnaSdk sdk){ + this.sdk = sdk; + } + /** + * get OntAsset Tx + * @return instance + */ + public Oep4 oep4(){ + if(oep4Tx == null) { + oep4Tx = new Oep4(sdk); + } + return oep4Tx; + } + public Oep5 oep5(){ + if(oep5Tx == null) { + oep5Tx = new Oep5(sdk); + } + return oep5Tx; + } + public Oep8 oep8(){ + if(oep8Tx == null) { + oep8Tx = new Oep8(sdk); + } + return oep8Tx; + } + + /** + * RecordTx + * @return instance + */ + public Record record() { + if(recordTx == null){ + recordTx = new Record(sdk); + } + return recordTx; + } + + public ClaimRecord claimRecord(){ + if (claimRecordTx == null){ + claimRecordTx = new ClaimRecord(sdk); + } + return claimRecordTx; + } + public Object sendTransaction(String contractAddr, Account acct,Account payerAcct, long gaslimit, long gasprice, AbiFunction func, boolean preExec) throws Exception { + byte[] params; + if (func != null) { + params = BuildParams.serializeAbiFunction(func); + } else { + params = new byte[]{}; + } + if (preExec) { + Transaction tx = sdk.vm().makeInvokeCodeTransaction(contractAddr, null, params, null,0, 0); + if (acct != null) { + sdk.signTx(tx, new Account[][]{{acct}}); + } + Object obj = sdk.getConnect().sendRawTransactionPreExec(tx.toHexString()); + return obj; + } else { + String payer = payerAcct.getAddressU160().toBase58(); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(contractAddr, null, params, payer,gaslimit, gasprice); + sdk.signTx(tx, new Account[][]{{acct}}); + if(!acct.getAddressU160().toBase58().equals(payerAcct.getAddressU160().toBase58())){ + sdk.addSign(tx,payerAcct); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (!b) { + throw new SDKException(ErrorCode.SendRawTxError); + } + return tx.hash().toHexString(); + } + } +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/Vm.java b/src/main/java/com/github/DNAProject/smartcontract/Vm.java new file mode 100644 index 0000000..62be80a --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/Vm.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.smartcontract; + +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Common; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.core.scripts.ScriptOp; +import com.github.DNAProject.core.transaction.Attribute; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.payload.DeployCode; +import com.github.DNAProject.core.payload.InvokeCode; +import com.github.DNAProject.core.scripts.ScriptBuilder; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.sdk.exception.SDKException; + +import java.math.BigInteger; +import java.util.*; + +/** + * + */ +public class Vm { + private DnaSdk sdk; + private String contractAddress = null; + public static String NATIVE_INVOKE_NAME = "System.Native.Invoke"; + public String getCodeAddress() { + return contractAddress; + } + public void setCodeAddress(String codeHash) { + this.contractAddress = codeHash.replace("0x", ""); + } + + public Vm(DnaSdk sdk) { + this.sdk = sdk; + } + + + /** + * + * @param codeStr + * @param needStorage + * @param name + * @param codeVersion + * @param author + * @param email + * @param desp + * @param payer + * @param gaslimit + * @param gasprice + * @return + * @throws SDKException + */ + public DeployCode makeDeployCodeTransaction(String codeStr, boolean needStorage, String name, String codeVersion, String author, String email, String desp,String payer,long gaslimit,long gasprice) throws SDKException { + if (name == null || name.equals("") || codeVersion == null || codeVersion.equals("") || author == null || author.equals("") || email == null || email.equals("") || desp == null || desp.equals("")) { + throw new SDKException(ErrorCode.OtherError("param error,can not be empty")); + } + DeployCode tx = new DeployCode(); + if(payer != null){ + tx.payer = Address.decodeBase58(payer.replace(Common.diddna,"")); + } + tx.attributes = new Attribute[0]; + tx.nonce = new Random().nextInt(); + tx.code = Helper.hexToBytes(codeStr); + tx.version = codeVersion; + tx.needStorage = needStorage; + tx.name = name; + tx.author = author; + tx.email = email; + tx.gasLimit = gaslimit; + tx.gasPrice = gasprice; + tx.description = desp; + return tx; + } + //NEO makeInvokeCodeTransaction + public InvokeCode makeInvokeCodeTransaction(String codeAddr,String method,byte[] params, String payer,long gaslimit,long gasprice) throws SDKException { + params = Helper.addBytes(params,new byte[]{0x67}); + params = Helper.addBytes(params, Address.parse(codeAddr).toArray()); + InvokeCode tx = new InvokeCode(); + tx.attributes = new Attribute[0]; + tx.nonce = new Random().nextInt(); + tx.code = params; + tx.gasLimit = gaslimit; + tx.gasPrice = gasprice; + if(payer != null){ + tx.payer = Address.decodeBase58(payer.replace(Common.diddna,"")); + } + return tx; + } + /** + * Native makeInvokeCodeTransaction + * @param params + * @param payer + * @param gaslimit + * @param gasprice + * @return + * @throws SDKException + */ + public InvokeCode makeInvokeCodeTransaction(byte[] params,String payer,long gaslimit,long gasprice) throws SDKException { + + InvokeCode tx = new InvokeCode(); + tx.attributes = new Attribute[0]; + tx.nonce = new Random().nextInt(); + tx.code = params; + tx.gasLimit = gaslimit; + tx.gasPrice = gasprice; + if(payer != null){ + tx.payer = Address.decodeBase58(payer.replace(Common.diddna,"")); + } + return tx; + } + + public Transaction buildNativeParams(Address codeAddr,String initMethod,byte[] args,String payer,long gaslimit,long gasprice) throws SDKException { + ScriptBuilder sb = new ScriptBuilder(); + if(args.length >0) { + sb.add(args); + } + sb.emitPushByteArray(initMethod.getBytes()); + sb.emitPushByteArray(codeAddr.toArray()); + sb.emitPushInteger(BigInteger.valueOf(0)); + sb.emit(ScriptOp.OP_SYSCALL); + sb.emitPushByteArray(NATIVE_INVOKE_NAME.getBytes()); + Transaction tx = makeInvokeCodeTransaction(sb.toArray(),payer,gaslimit,gasprice); + return tx; + } +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/WasmVm.java b/src/main/java/com/github/DNAProject/smartcontract/WasmVm.java new file mode 100644 index 0000000..e7d6294 --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/WasmVm.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.smartcontract; + +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.core.scripts.WasmScriptBuilder; +import com.github.DNAProject.core.transaction.Attribute; +import com.github.DNAProject.sdk.exception.SDKException; +import com.github.DNAProject.core.payload.DeployWasmCode; +import com.github.DNAProject.core.payload.InvokeWasmCode; + +import java.util.List; +import java.util.Random; + +public class WasmVm { + + private DnaSdk sdk; + + public WasmVm(DnaSdk sdk) { + this.sdk = sdk; + } + + public DeployWasmCode makeDeployCodeTransaction(String codeStr, String name, String codeVersion, String author, + String email, String description, Address payer, long gasLimit, + long gasPrice) throws SDKException { + if (name == null || name.equals("") || codeVersion == null || codeVersion.equals("") || author == null || author.equals("") || email == null || email.equals("") || description == null || description.equals("")) { + throw new SDKException(ErrorCode.InvalidInterfaceParam); + } + return new DeployWasmCode(codeStr, name, codeVersion, author, email, description, payer, gasLimit, gasPrice); + } + + public InvokeWasmCode makeInvokeCodeTransaction(String contractHash, String method, List params, Address payer, + long gasLimit, long gasPrice) { + byte[] invokeCode = WasmScriptBuilder.createWasmInvokeCode(contractHash, method, params); + InvokeWasmCode tx = new InvokeWasmCode(invokeCode); + tx.payer = payer; + tx.gasLimit = gasLimit; + tx.gasPrice = gasPrice; + tx.attributes = new Attribute[0]; + tx.nonce = new Random().nextInt(); + return tx; + } + +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/nativevm/Auth.java b/src/main/java/com/github/DNAProject/smartcontract/nativevm/Auth.java new file mode 100644 index 0000000..6853392 --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/nativevm/Auth.java @@ -0,0 +1,625 @@ +package com.github.DNAProject.smartcontract.nativevm; + +import com.alibaba.fastjson.JSONObject; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; +import com.github.DNAProject.sdk.exception.SDKException; +import com.github.DNAProject.smartcontract.nativevm.abi.NativeBuildParams; +import com.github.DNAProject.smartcontract.nativevm.abi.Struct; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + + +public class Auth { + private DnaSdk sdk; + private final String contractAddress = "0000000000000000000000000000000000000006"; + public Auth(DnaSdk sdk) { + this.sdk = sdk; + } + + public String getContractAddress() { + return contractAddress; + } + + public String sendInit(String adminDnaId,String password,byte[] salt, String contractAddr,Account payerAcct,long gaslimit,long gasprice) throws Exception { + if(adminDnaId ==null || adminDnaId.equals("")){ + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + BinaryWriter bw = new BinaryWriter(bos); + bw.writeVarBytes(adminDnaId.getBytes()); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(contractAddr,"initContractAdmin",null, payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + sdk.signTx(tx,adminDnaId,password,salt); + sdk.addSign(tx,payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (!b) { + throw new SDKException(ErrorCode.SendRawTxError); + } + return tx.hash().toHexString(); + } + + + /** + * + * @param adminDnaId + * @param password + * @param contractAddr + * @param newAdminDnaID + * @param keyNo + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public String sendTransfer(String adminDnaId, String password,byte[] salt,long keyNo, String contractAddr, String newAdminDnaID, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if(adminDnaId ==null || adminDnaId.equals("") || contractAddr == null || contractAddr.equals("") || newAdminDnaID==null || newAdminDnaID.equals("")||payerAcct==null){ + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if(keyNo <0 || gaslimit <0 || gasprice <0){ + throw new SDKException(ErrorCode.ParamErr("keyNo or gaslimit or gasprice should not be less than 0")); + } + Transaction tx = makeTransfer(adminDnaId,contractAddr,newAdminDnaID,keyNo,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + sdk.signTx(tx,adminDnaId,password,salt); + sdk.addSign(tx,payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (!b) { + throw new SDKException(ErrorCode.SendRawTxError); + } + return tx.hash().toHexString(); + } + + /** + * + * @param adminDnaID + * @param contractAddr + * @param newAdminDnaID + * @param keyNo + * @param payer + * @param gaslimit + * @param gasprice + * @return + * @throws SDKException + */ + public Transaction makeTransfer(String adminDnaID,String contractAddr, String newAdminDnaID,long keyNo,String payer,long gaslimit,long gasprice) throws SDKException { + if(adminDnaID ==null || adminDnaID.equals("") || contractAddr == null || contractAddr.equals("") || newAdminDnaID==null || newAdminDnaID.equals("")){ + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if(keyNo <0 || gaslimit <0 || gasprice <0){ + throw new SDKException(ErrorCode.ParamErr("keyNo or gaslimit or gasprice should not be less than 0")); + } + + List list = new ArrayList(); + list.add(new Struct().add(Helper.hexToBytes(contractAddr),newAdminDnaID.getBytes(),keyNo)); + byte[] arg = NativeBuildParams.createCodeParamsScript(list); + + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"transfer",arg,payer,gaslimit,gasprice); + return tx; + } + + /** + * + * @param dnaid + * @param password + * @param contractAddr + * @param funcName + * @param keyNo + * @return + * @throws Exception + */ + public String verifyToken(String dnaid,String password,byte[] salt,long keyNo, String contractAddr,String funcName) throws Exception { + if(dnaid ==null || dnaid.equals("") || password ==null || password.equals("")|| contractAddr == null || contractAddr.equals("") || funcName==null || funcName.equals("")){ + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if(keyNo < 0){ + throw new SDKException(ErrorCode.ParamErr("key or gaslimit or gas price should not be less than 0")); + } + Transaction tx = makeVerifyToken(dnaid,contractAddr,funcName,keyNo); + sdk.signTx(tx,dnaid,password,salt); + Object obj = sdk.getConnect().sendRawTransactionPreExec(tx.toHexString()); + if (obj == null){ + throw new SDKException(ErrorCode.OtherError("sendRawTransaction PreExec error: ")); + } + return ((JSONObject)obj).getString("Result"); + } + + /** + * + * @param dnaid + * @param contractAddr + * @param funcName + * @param keyNo + * @return + * @throws SDKException + */ + public Transaction makeVerifyToken(String dnaid,String contractAddr,String funcName,long keyNo) throws SDKException { + if(dnaid ==null || dnaid.equals("")|| contractAddr == null || contractAddr.equals("") || funcName==null || funcName.equals("")){ + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if(keyNo < 0){ + throw new SDKException(ErrorCode.ParamErr("key or gaslimit or gas price should not be less than 0")); + } + List list = new ArrayList(); + list.add(new Struct().add(Helper.hexToBytes(contractAddr),dnaid.getBytes(),funcName.getBytes(),keyNo)); + byte[] arg = NativeBuildParams.createCodeParamsScript(list); + + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"verifyToken",arg,null,0,0); + return tx; + } + + /** + * + * @param adminDnaID + * @param password + * @param contractAddr + * @param role + * @param funcName + * @param keyNo + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public String assignFuncsToRole(String adminDnaID,String password,byte[] salt, long keyNo,String contractAddr,String role,String[] funcName,Account payerAcct,long gaslimit,long gasprice) throws Exception { + if(adminDnaID ==null || adminDnaID.equals("") || contractAddr == null || contractAddr.equals("") || role==null || role.equals("") || funcName == null || funcName.length == 0||payerAcct==null){ + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if(keyNo < 0 || gaslimit < 0 || gasprice < 0){ + throw new SDKException(ErrorCode.ParamErr("keyNo or gaslimit or gas price should not be less than 0")); + } + Transaction tx = makeAssignFuncsToRole(adminDnaID,contractAddr,role,funcName,keyNo,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + sdk.signTx(tx,adminDnaID,password,salt); + sdk.addSign(tx,payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if(b){ + return tx.hash().toHexString(); + } + return null; + } + + /** + * + * @param adminDnaID + * @param contractAddr + * @param role + * @param funcName + * @param keyNo + * @param payer + * @param gaslimit + * @param gasprice + * @return + * @throws SDKException + */ + public Transaction makeAssignFuncsToRole(String adminDnaID,String contractAddr,String role,String[] funcName,long keyNo,String payer,long gaslimit,long gasprice) throws SDKException { + if(adminDnaID ==null || adminDnaID.equals("") || contractAddr == null || contractAddr.equals("") || role==null || role.equals("") || funcName == null || funcName.length == 0 + || payer==null || payer.equals("")){ + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if(keyNo < 0 || gaslimit < 0 || gasprice < 0){ + throw new SDKException(ErrorCode.ParamErr("keyNo or gaslimit or gas price should not be less than 0")); + } + + List list = new ArrayList(); + Struct struct = new Struct(); + struct.add(Helper.hexToBytes(contractAddr),adminDnaID.getBytes(),role.getBytes()); + struct.add(funcName.length); + for (int i = 0; i < funcName.length; i++) { + struct.add(funcName[i]); + } + struct.add(keyNo); + list.add(struct); + byte[] arg = NativeBuildParams.createCodeParamsScript(list); + + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"assignFuncsToRole",arg,payer,gaslimit,gasprice); + return tx; + } + + /** + * + * @param adminDnaId + * @param password + * @param contractAddr + * @param role + * @param dnaIDs + * @param keyNo + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public String assignDnaIdsToRole(String adminDnaId, String password, byte[] salt, long keyNo, String contractAddr, String role, String[] dnaIDs, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if(adminDnaId == null || adminDnaId.equals("") || password==null || password.equals("") || contractAddr== null || contractAddr.equals("") || + role == null || role.equals("") || dnaIDs==null || dnaIDs.length == 0){ + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if(keyNo<0 || gaslimit < 0 || gasprice < 0){ + throw new SDKException(ErrorCode.ParamErr("keyNo or gaslimit or gasprice should not be less than 0")); + } + Transaction tx = makeAssignDnaIDsToRole(adminDnaId,contractAddr,role,dnaIDs,keyNo,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + sdk.signTx(tx,adminDnaId,password,salt); + sdk.addSign(tx,payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if(b){ + return tx.hash().toHexString(); + } + return null; + } + + /** + * + * @param adminDnaId + * @param contractAddr + * @param role + * @param dnaIDs + * @param keyNo + * @param payer + * @param gaslimit + * @param gasprice + * @return + * @throws SDKException + */ + public Transaction makeAssignDnaIDsToRole(String adminDnaId, String contractAddr, String role, String[] dnaIDs, long keyNo, String payer, long gaslimit, long gasprice) throws SDKException { + if(adminDnaId == null || adminDnaId.equals("") || contractAddr== null || contractAddr.equals("") || + role == null || role.equals("") || dnaIDs==null || dnaIDs.length == 0){ + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if(keyNo <0 || gaslimit < 0 || gasprice < 0){ + throw new SDKException(ErrorCode.ParamErr("keyNo or gaslimit or gasprice should not be less than 0")); + } + byte[][] dnaId = new byte[dnaIDs.length][]; + for(int i=0; i< dnaIDs.length ; i++){ + dnaId[i] = dnaIDs[i].getBytes(); + } + List list = new ArrayList(); + Struct struct = new Struct(); + struct.add(Helper.hexToBytes(contractAddr),adminDnaId.getBytes(),role.getBytes()); + struct.add(dnaId.length); + for(int i =0;i. + * + */ + +package com.github.DNAProject.smartcontract.nativevm; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.*; +import com.github.DNAProject.core.DataSignature; +import com.github.DNAProject.core.block.Block; +import com.github.DNAProject.core.dnaid.Attribute; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.crypto.Curve; +import com.github.DNAProject.crypto.KeyType; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.merkle.MerkleVerifier; +import com.github.DNAProject.sdk.claim.Claim; +import com.github.DNAProject.sdk.exception.SDKException; +import com.github.DNAProject.sdk.info.AccountInfo; +import com.github.DNAProject.sdk.wallet.Identity; +import com.github.DNAProject.smartcontract.nativevm.abi.NativeBuildParams; +import com.github.DNAProject.smartcontract.nativevm.abi.Struct; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.*; + +public class DnaId { + private DnaSdk sdk; + private String contractAddress = "0000000000000000000000000000000000000003"; + + + public DnaId(DnaSdk sdk) { + this.sdk = sdk; + } + + + public String getContractAddress() { + return contractAddress; + } + + /** + * @param ident + * @param password + * @param payerAcct + * @param gaslimit + * @param gasprice + * @param isPreExec + * @return + * @throws Exception + */ + public String sendRegister(Identity ident, String password, Account payerAcct, long gaslimit, long gasprice, boolean isPreExec) throws Exception { + if (ident == null || password == null || password.equals("") || payerAcct == null) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + + Transaction tx = makeRegister(ident.dnaid,ident.controls.get(0).publicKey, payerAcct.getAddressU160().toBase58(), gaslimit, gasprice); + sdk.getWalletMgr().writeWallet(); + sdk.signTx(tx, ident.dnaid, password,ident.controls.get(0).getSalt()); + sdk.addSign(tx, payerAcct); + if (isPreExec) { + Object obj = sdk.getConnect().sendRawTransactionPreExec(tx.toHexString()); + String result = ((JSONObject) obj).getString("Result"); + if (Integer.parseInt(result) == 0) { + throw new SDKException(ErrorCode.OtherError("sendRawTransaction PreExec error: "+ obj)); + } + } else { + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (!b) { + throw new SDKException(ErrorCode.SendRawTxError); + } + } + return tx.hash().toHexString(); + } + + public String sendRegisterPreExec(Identity ident, String password, Account payerAcct, long gaslimit, long gasprice) throws Exception { + return sendRegister(ident, password, payerAcct, gaslimit, gasprice, true); + } + + public String sendRegister(Identity ident, String password, Account payerAcct, long gaslimit, long gasprice) throws Exception { + return sendRegister(ident, password, payerAcct, gaslimit, gasprice, false); + } + + + /** + * @param dnaid + * @param payer + * @param gasprice + * @return + * @throws Exception + */ + public Transaction makeRegister(String dnaid,String publickey, String payer, long gaslimit, long gasprice) throws Exception { + if (payer == null || payer.equals("")) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + byte[] pk = Helper.hexToBytes(publickey); + + List list = new ArrayList(); + list.add(new Struct().add(dnaid,pk)); + byte[] args = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"regIDWithPublicKey",args,payer,gaslimit, gasprice); + return tx; + } + + /** + * @param ident + * @param password + * @param attributes + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + + public String sendRegisterWithAttrs(Identity ident, String password, Attribute[] attributes, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if (ident == null || password == null || password.equals("") || payerAcct == null) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + String dnaid = ident.dnaid; + Transaction tx = makeRegisterWithAttrs(dnaid, password,ident.controls.get(0).getSalt(), ident.controls.get(0).publicKey, attributes, payerAcct.getAddressU160().toBase58(), gaslimit, gasprice); + sdk.signTx(tx, dnaid, password,ident.controls.get(0).getSalt()); + sdk.addSign(tx, payerAcct); + Identity identity = sdk.getWalletMgr().getWallet().addDnaIdController(dnaid, ident.controls.get(0).key, ident.dnaid,ident.controls.get(0).publicKey); + sdk.getWalletMgr().writeWallet(); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + return tx.hash().toHexString(); + } + + /** + * @param dnaid + * @param password + * @param attributes + * @param payer + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public Transaction makeRegisterWithAttrs(String dnaid, String password,byte[] salt, String publickey, Attribute[] attributes, String payer, long gaslimit, long gasprice) throws Exception { + if (password == null || password.equals("") || payer == null || payer.equals("")) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + byte[] pk = Helper.hexToBytes(publickey); + + List list = new ArrayList(); + Struct struct = new Struct().add(dnaid.getBytes(), pk); + struct.add(attributes.length); + for (int i = 0; i < attributes.length; i++) { + struct.add(attributes[i].key, attributes[i].valueType, attributes[i].value); + } + list.add(struct); + byte[] args = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"regIDWithAttributes",args,payer,gaslimit, gasprice); + return tx; + } + + private byte[] serializeAttributes(Attribute[] attributes) throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + BinaryWriter bw = new BinaryWriter(baos); + bw.writeSerializableArray(attributes); + return baos.toByteArray(); + } + + /** + * @param dnaid + * @return + * @throws Exception + */ + public String sendGetPublicKeys(String dnaid) throws Exception { + if (dnaid == null || dnaid.equals("")) { + throw new SDKException(ErrorCode.ParamErr("dnaid should not be null")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + + List list = new ArrayList(); + list.add(dnaid.getBytes()); + byte[] arg = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"getPublicKeys",arg,null,0,0); + + Object obj = sdk.getConnect().sendRawTransactionPreExec(tx.toHexString()); + String res = ((JSONObject) obj).getString("Result"); + if (res.equals("")) { + return res; + } + ByteArrayInputStream bais = new ByteArrayInputStream(Helper.hexToBytes(res)); + BinaryReader br = new BinaryReader(bais); + List pubKeyList = new ArrayList(); + while (true) { + try { + Map publicKeyMap = new HashMap(); + publicKeyMap.put("PubKeyId", dnaid + "#keys-" + String.valueOf(br.readInt())); + byte[] pubKey = br.readVarBytes(); + if(pubKey.length == 33){ + publicKeyMap.put("Type", KeyType.ECDSA.name()); + publicKeyMap.put("Curve", Curve.P256); + publicKeyMap.put("Value", Helper.toHexString(pubKey)); + } else { + publicKeyMap.put("Type", KeyType.fromLabel(pubKey[0])); + publicKeyMap.put("Curve", Curve.fromLabel(pubKey[1])); + publicKeyMap.put("Value", Helper.toHexString(pubKey)); + } + pubKeyList.add(publicKeyMap); + } catch (Exception e) { + break; + } + } + return JSON.toJSONString(pubKeyList); + } + + /** + * @param dnaid + * @return + * @throws Exception + */ + public String sendGetKeyState(String dnaid, int index) throws Exception { + if (dnaid == null || dnaid.equals("") || index < 0) { + throw new SDKException(ErrorCode.ParamErr("parameter is wrong")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } +// byte[] parabytes = NativeBuildParams.buildParams(dnaid.getBytes(), index); +// Transaction tx = sdk.vm().makeInvokeCodeTransaction(contractAddress, "getKeyState", parabytes, null, 0, 0); + + List list = new ArrayList(); + list.add(new Struct().add(dnaid.getBytes(),index)); + byte[] arg = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"getKeyState",arg,null,0,0); + + Object obj = sdk.getConnect().sendRawTransactionPreExec(tx.toHexString()); + String res = ((JSONObject) obj).getString("Result"); + if (res.equals("")) { + return res; + } + return new String(Helper.hexToBytes(res)); + } + + public String sendGetAttributes(String dnaid) throws Exception { + if (dnaid == null || dnaid.equals("")) { + throw new SDKException(ErrorCode.ParamErr("dnaid should not be null")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + + + List list = new ArrayList(); + list.add(dnaid.getBytes()); + byte[] arg = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"getAttributes",arg,null,0,0); + + Object obj = sdk.getConnect().sendRawTransactionPreExec(tx.toHexString()); + String res = ((JSONObject) obj).getString("Result"); + if (res.equals("")) { + return res; + } + + ByteArrayInputStream bais = new ByteArrayInputStream(Helper.hexToBytes(res)); + BinaryReader br = new BinaryReader(bais); + List attrsList = new ArrayList(); + while (true) { + try { + Map attributeMap = new HashMap(); + attributeMap.put("Key", new String(br.readVarBytes())); + attributeMap.put("Type", new String(br.readVarBytes())); + attributeMap.put("Value", new String(br.readVarBytes())); + attrsList.add(attributeMap); + } catch (Exception e) { + break; + } + } + + return JSON.toJSONString(attrsList); + } + + + /** + * @param dnaid + * @param password + * @param newpubkey + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public String sendAddPubKey(String dnaid, String password,byte[] salt, String newpubkey, Account payerAcct, long gaslimit, long gasprice) throws Exception { + return sendAddPubKey(dnaid, null, password,salt, newpubkey, payerAcct, gaslimit, gasprice); + } + + /** + * @param dnaid + * @param recovery + * @param password + * @param newpubkey + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public String sendAddPubKey(String dnaid, String recovery,String password,byte[] salt, String newpubkey, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if (dnaid == null || dnaid.equals("") || password == null || password.equals("") || payerAcct == null) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + Transaction tx = makeAddPubKey(dnaid, recovery, password, salt,newpubkey, payerAcct.getAddressU160().toBase58(), gaslimit, gasprice); + String addr; + if (recovery != null) { + addr = recovery.replace(Common.diddna, ""); + } else { + addr = dnaid; + } + sdk.signTx(tx, addr, password,salt); + sdk.addSign(tx, payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + public String sendAddPubKey(String dnaid, Account controler, String newpubkey, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if (dnaid == null || dnaid.equals("") || payerAcct == null) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + byte[] arg; + List list = new ArrayList(); + list.add(new Struct().add(dnaid.getBytes(), Helper.hexToBytes(newpubkey), controler.serializePublicKey())); + arg = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"addKey",arg,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + sdk.addSign(tx, controler); + sdk.addSign(tx, payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + /** + * @param dnaid + * @param password + * @param newpubkey + * @param payer + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public Transaction makeAddPubKey(String dnaid, String password, byte[] salt,String newpubkey, String payer, long gaslimit, long gasprice) throws Exception { + return makeAddPubKey(dnaid, null, password,salt, newpubkey, payer, gaslimit, gasprice); + } + + /** + * @param dnaid + * @param recovery + * @param password + * @param newpubkey + * @param payer + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public Transaction makeAddPubKey(String dnaid, String recovery, String password,byte[] salt, String newpubkey, String payer, long gaslimit, long gasprice) throws Exception { + if (dnaid == null || dnaid.equals("") || payer == null || payer.equals("") || newpubkey == null || newpubkey.equals("")) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + byte[] arg; + if (recovery == null) { + AccountInfo info = sdk.getWalletMgr().getAccountInfo(dnaid, password,salt); + byte[] pk = Helper.hexToBytes(info.pubkey); + List list = new ArrayList(); + list.add(new Struct().add(dnaid.getBytes(),Helper.hexToBytes(newpubkey),pk)); + arg = NativeBuildParams.createCodeParamsScript(list); + } else { + List list = new ArrayList(); + list.add(new Struct().add(dnaid.getBytes(),Helper.hexToBytes(newpubkey),Address.decodeBase58(recovery.replace(Common.diddna,"")).toArray())); + arg = NativeBuildParams.createCodeParamsScript(list); + } + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"addKey",arg,payer,gaslimit,gasprice); + + return tx; + } + + + /** + * @param dnaid + * @param password + * @param removePubkey + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public String sendRemovePubKey(String dnaid, String password,byte[] salt, String removePubkey, Account payerAcct, long gaslimit, long gasprice) throws Exception { + return sendRemovePubKey(dnaid, null, password, salt,removePubkey, payerAcct, gaslimit, gasprice); + } + + /** + * @param dnaid + * @param recovery + * @param password + * @param removePubkey + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public String sendRemovePubKey(String dnaid, String recovery, String password,byte[] salt, String removePubkey, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if (dnaid == null || dnaid.equals("") || password == null || password.equals("") || payerAcct == null) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + Transaction tx = makeRemovePubKey(dnaid, recovery, password,salt, removePubkey, payerAcct.getAddressU160().toBase58(), gaslimit, gasprice); + String addr; + if (recovery == null) { + addr = dnaid;//.replace(Common.diddna, ""); + } else { + addr = recovery.replace(Common.diddna, ""); + } + sdk.signTx(tx, addr, password,salt); + sdk.addSign(tx, payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + public String sendRemovePubKey(String dnaid, Account controler, String removePubkey, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if (dnaid == null || dnaid.equals("") || payerAcct == null) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + byte[] arg; + List list = new ArrayList(); + list.add(new Struct().add(dnaid.getBytes(), Helper.hexToBytes(removePubkey), controler.serializePublicKey())); + arg = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"removeKey",arg,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + sdk.addSign(tx, controler); + sdk.addSign(tx, payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + /** + * @param dnaid + * @param password + * @param removePubkey + * @param payer + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public Transaction makeRemovePubKey(String dnaid, String password,byte[] salt, String removePubkey, String payer, long gaslimit, long gasprice) throws Exception { + return makeRemovePubKey(dnaid, null, password,salt, removePubkey, payer, gaslimit, gasprice); + } + + /** + * @param dnaid + * @param recoveryAddr + * @param password + * @param removePubkey + * @param payer + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public Transaction makeRemovePubKey(String dnaid, String recoveryAddr, String password,byte[] salt, String removePubkey, String payer, long gaslimit, long gasprice) throws Exception { + if (dnaid == null || dnaid.equals("") || password == null || password.equals("") || payer == null || payer.equals("") || removePubkey == null || removePubkey.equals("")) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + byte[] arg; + if (recoveryAddr == null) { + AccountInfo info = sdk.getWalletMgr().getAccountInfo(dnaid, password,salt); + byte[] pk = Helper.hexToBytes(info.pubkey); +// parabytes = NativeBuildParams.buildParams(dnaid, Helper.hexToBytes(removePubkey), pk); + List list = new ArrayList(); + list.add(new Struct().add(dnaid.getBytes(),Helper.hexToBytes(removePubkey),pk)); + arg = NativeBuildParams.createCodeParamsScript(list); + + } else { +// parabytes = NativeBuildParams.buildParams(dnaid, Helper.hexToBytes(removePubkey), Address.decodeBase58(recoveryAddr).toArray()); + List list = new ArrayList(); + list.add(new Struct().add(dnaid.getBytes(),Helper.hexToBytes(removePubkey),Address.decodeBase58(recoveryAddr.replace(Common.diddna,"")).toArray())); + arg = NativeBuildParams.createCodeParamsScript(list); + } + +// Transaction tx = sdk.vm().makeInvokeCodeTransaction(contractAddress, "removeKey", parabytes, payer, gaslimit, gasprice); + + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"removeKey",arg,payer,gaslimit,gasprice); + return tx; + } + + /** + * @param dnaid + * @param password + * @param recoveryAddr + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + + public String sendAddRecovery(String dnaid, String password,byte[] salt, String recoveryAddr, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if (dnaid == null || dnaid.equals("") || password == null || password.equals("") || payerAcct == null || recoveryAddr == null || recoveryAddr.equals("")) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + String addr = dnaid.replace(Common.diddna, ""); + Transaction tx = makeAddRecovery(dnaid, password,salt, recoveryAddr, payerAcct.getAddressU160().toBase58(), gaslimit, gasprice); + sdk.signTx(tx, dnaid, password,salt); + sdk.addSign(tx, payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + + /** + * @param dnaid + * @param password + * @param recoveryAddr + * @param payer + * @param gasprice + * @return + * @throws Exception + */ + public Transaction makeAddRecovery(String dnaid, String password,byte[] salt, String recoveryAddr, String payer, long gaslimit, long gasprice) throws Exception { + if (dnaid == null || dnaid.equals("") || password == null || password.equals("") || payer == null || payer.equals("") || recoveryAddr == null || recoveryAddr.equals("")) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AccountInfo info = sdk.getWalletMgr().getAccountInfo(dnaid, password,salt); + byte[] pk = Helper.hexToBytes(info.pubkey); + + List list = new ArrayList(); + list.add(new Struct().add(dnaid,Address.decodeBase58(recoveryAddr), pk)); + byte[] arg = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"addRecovery",arg,payer,gaslimit,gasprice); + return tx; + } + + /** + * @param dnaid + * @param password + * @param newRecovery + * @param oldRecovery + * @return + * @throws Exception + */ + public String sendChangeRecovery(String dnaid, String newRecovery, String oldRecovery, String password,byte[] salt,Account payerAcct, long gaslimit, long gasprice) throws Exception { + if (dnaid == null || dnaid.equals("") || password == null || password.equals("")) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + Transaction tx = makeChangeRecovery(dnaid, newRecovery, oldRecovery, password,payerAcct.getAddressU160().toBase58(), gaslimit, gasprice); + sdk.signTx(tx, oldRecovery, password,salt); + sdk.addSign(tx,payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + + /** + * @param dnaid + * @param newRecovery + * @param oldRecovery + * @param password + * @param gasprice + * @return + * @throws SDKException + */ + public Transaction makeChangeRecovery(String dnaid, String newRecovery, String oldRecovery, String password,String payer, long gaslimit, long gasprice) throws SDKException { + if (dnaid == null || dnaid.equals("") || password == null || password.equals("") || newRecovery == null || oldRecovery == null ) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + Address newAddr = Address.decodeBase58(newRecovery.replace(Common.diddna,"")); + Address oldAddr = Address.decodeBase58(oldRecovery.replace(Common.diddna,"")); + + List list = new ArrayList(); + list.add(new Struct().add(dnaid,newAddr, oldAddr)); + byte[] arg = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"changeRecovery",arg,payer,gaslimit,gasprice); + return tx; + } + + /** + * + * @param dnaid + * @param newRecovery + * @param oldRecovery + * @param accounts + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + private String sendChangeRecovery(String dnaid, String newRecovery, String oldRecovery, Account[] accounts, Account payerAcct,long gaslimit, long gasprice) throws Exception { + if (dnaid == null || dnaid.equals("") || accounts == null || accounts.length == 0 || newRecovery == null || oldRecovery == null ) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + Address newAddr = Address.decodeBase58(newRecovery.replace(Common.diddna,"")); + Address oldAddr = Address.decodeBase58(oldRecovery.replace(Common.diddna,"")); + byte[] parabytes = NativeBuildParams.buildParams(dnaid.getBytes(),newAddr.toArray(),oldAddr.toArray()); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(contractAddress, "changeRecovery", parabytes, payerAcct.getAddressU160().toBase58(), gaslimit, gasprice); + sdk.signTx(tx, new Account[][]{accounts}); + sdk.addSign(tx, payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + + /** + * @param dnaid + * @param password + * @param attributes + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public String sendAddAttributes(String dnaid, String password,byte[] salt, Attribute[] attributes, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if (dnaid == null || dnaid.equals("") || password == null || attributes == null || attributes.length == 0 || payerAcct == null) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + String addr = dnaid.replace(Common.diddna, ""); + Transaction tx = makeAddAttributes(dnaid, password, salt,attributes, payerAcct.getAddressU160().toBase58(), gaslimit, gasprice); + sdk.signTx(tx, dnaid, password,salt); + sdk.addSign(tx, payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + public String sendAddAttributes(String dnaid, Account controler, Attribute[] attributes, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if (dnaid == null || dnaid.equals("") || attributes == null || attributes.length == 0 || payerAcct == null) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + List list = new ArrayList(); + Struct struct = new Struct().add(dnaid.getBytes()); + struct.add(attributes.length); + for (int i = 0; i < attributes.length; i++) { + struct.add(attributes[i].key, attributes[i].valueType, attributes[i].value); + } + struct.add(controler.serializePublicKey()); + list.add(struct); + byte[] args = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"addAttributes",args,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + sdk.addSign(tx, controler); + sdk.addSign(tx, payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + /** + * @param dnaid + * @param password + * @param attributes + * @param payer + * @param gasprice + * @return + * @throws Exception + */ + public Transaction makeAddAttributes(String dnaid, String password,byte[] salt, Attribute[] attributes, String payer, long gaslimit, long gasprice) throws Exception { + if (dnaid == null || dnaid.equals("") || password == null || attributes == null || attributes.length == 0 || payer == null || payer.equals("")) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AccountInfo info = sdk.getWalletMgr().getAccountInfo(dnaid, password,salt); + password = null; + byte[] pk = Helper.hexToBytes(info.pubkey); + List list = new ArrayList(); + Struct struct = new Struct().add(dnaid.getBytes()); + struct.add(attributes.length); + for (int i = 0; i < attributes.length; i++) { + struct.add(attributes[i].key, attributes[i].valueType, attributes[i].value); + } + struct.add(pk); + list.add(struct); + byte[] args = NativeBuildParams.createCodeParamsScript(list); + + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"addAttributes",args,payer,gaslimit,gasprice); + return tx; + } + + /** + * @param dnaid + * @param password + * @param path + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public String sendRemoveAttribute(String dnaid, String password,byte[] salt, String path, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if (dnaid == null || dnaid.equals("") || password == null || payerAcct == null || path == null || path.equals("")) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + String addr = dnaid.replace(Common.diddna, ""); + Transaction tx = makeRemoveAttribute(dnaid, password, salt,path, payerAcct.getAddressU160().toBase58(), gaslimit, gasprice); + sdk.signTx(tx, dnaid, password,salt); + sdk.addSign(tx, payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + public String sendRemoveAttribute(String dnaid, Account controler, String path, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if (dnaid == null || dnaid.equals("") || payerAcct == null || path == null || path.equals("")) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + List list = new ArrayList(); + list.add(new Struct().add(dnaid.getBytes(), path.getBytes(), controler.serializePublicKey())); + byte[] arg = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"removeAttribute",arg,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + sdk.addSign(tx, controler); + sdk.addSign(tx, payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + /** + * @param dnaid + * @param password + * @param path + * @param payer + * @param gasprice + * @return + * @throws Exception + */ + public Transaction makeRemoveAttribute(String dnaid, String password,byte[] salt, String path, String payer, long gaslimit, long gasprice) throws Exception { + if (dnaid == null || dnaid.equals("") || password == null || payer == null || payer.equals("") || path == null || path.equals("") || payer == null || payer.equals("")) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AccountInfo info = sdk.getWalletMgr().getAccountInfo(dnaid, password,salt); + byte[] pk = Helper.hexToBytes(info.pubkey); + + List list = new ArrayList(); + list.add(new Struct().add(dnaid.getBytes(), path.getBytes(), pk)); + byte[] arg = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"removeAttribute",arg,payer,gaslimit,gasprice); + return tx; + } + + /** + * @param txhash + * @return + * @throws Exception + */ + public Object getMerkleProof(String txhash) throws Exception { + if (txhash == null || txhash.equals("")) { + throw new SDKException(ErrorCode.ParamErr("txhash should not be null")); + } + Map proof = new HashMap(); + Map map = new HashMap(); + int height = sdk.getConnect().getBlockHeightByTxHash(txhash); + map.put("Type", "MerkleProof"); + map.put("TxnHash", txhash); + map.put("BlockHeight", height); + + Map tmpProof = (Map) sdk.getConnect().getMerkleProof(txhash); + UInt256 txroot = UInt256.parse((String) tmpProof.get("TransactionsRoot")); + int blockHeight = (int) tmpProof.get("BlockHeight"); + UInt256 curBlockRoot = UInt256.parse((String) tmpProof.get("CurBlockRoot")); + int curBlockHeight = (int) tmpProof.get("CurBlockHeight"); + List hashes = (List) tmpProof.get("TargetHashes"); + UInt256[] targetHashes = new UInt256[hashes.size()]; + for (int i = 0; i < hashes.size(); i++) { + targetHashes[i] = UInt256.parse((String) hashes.get(i)); + } + map.put("MerkleRoot", curBlockRoot.toHexString()); + map.put("Nodes", MerkleVerifier.getProof(txroot, blockHeight, targetHashes, curBlockHeight + 1)); + proof.put("Proof", map); + return proof; + } + + /** + * @param merkleProof + * @return + * @throws Exception + */ + public boolean verifyMerkleProof(String merkleProof) throws Exception { + if (merkleProof == null || merkleProof.equals("")) { + throw new SDKException(ErrorCode.ParamErr("claim should not be null")); + } + try { + JSONObject obj = JSON.parseObject(merkleProof); + Map proof = (Map) obj.getJSONObject("Proof"); + String txhash = (String) proof.get("TxnHash"); + int blockHeight = (int) proof.get("BlockHeight"); + UInt256 merkleRoot = UInt256.parse((String) proof.get("MerkleRoot")); + Block block = sdk.getConnect().getBlock(blockHeight); + if (block.height != blockHeight) { + throw new SDKException("blockHeight not match"); + } + boolean containTx = false; + for (int i = 0; i < block.transactions.length; i++) { + if (block.transactions[i].hash().toHexString().equals(txhash)) { + containTx = true; + } + } + if (!containTx) { + throw new SDKException(ErrorCode.OtherError("not contain this tx")); + } + UInt256 txsroot = block.transactionsRoot; + + List nodes = (List) proof.get("Nodes"); + return MerkleVerifier.Verify(txsroot, nodes, merkleRoot); + } catch (Exception e) { + e.printStackTrace(); + throw new SDKException(e); + } + } + + /** + * @param signerDnaid + * @param password + * @param context + * @param claimMap + * @param metaData + * @param clmRevMap + * @param expire + * @return + * @throws Exception + */ + public String createDnaIdClaim(String signerDnaid, String password,byte[] salt, String context, Map claimMap, Map metaData, Map clmRevMap, long expire) throws Exception { + if (signerDnaid == null || signerDnaid.equals("") || password == null || password.equals("") || context == null || context.equals("") || claimMap == null || metaData == null || clmRevMap == null || expire <= 0) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (expire < System.currentTimeMillis() / 1000) { + throw new SDKException(ErrorCode.ExpireErr); + } + Claim claim = null; + try { + String sendDid = (String) metaData.get("Issuer"); + String receiverDid = (String) metaData.get("Subject"); + if (sendDid == null || receiverDid == null) { + throw new SDKException(ErrorCode.DidNull); + } + String issuerDdo = sendGetDDO(sendDid); + JSONArray owners = JSON.parseObject(issuerDdo).getJSONArray("Owners"); + if (owners == null) { + throw new SDKException(ErrorCode.NotExistCliamIssuer); + } + String pubkeyId = null; + Account acct = sdk.getWalletMgr().getAccount(signerDnaid, password,salt); + String pk = Helper.toHexString(acct.serializePublicKey()); + for (int i = 0; i < owners.size(); i++) { + JSONObject obj = owners.getJSONObject(i); + if (obj.getString("Value").equals(pk)) { + pubkeyId = obj.getString("PubKeyId"); + break; + } + } + if (pubkeyId == null) { + throw new SDKException(ErrorCode.NotFoundPublicKeyId); + } + String[] receiverDidStr = receiverDid.split(":"); + if (receiverDidStr.length != 3) { + throw new SDKException(ErrorCode.DidError); + } + claim = new Claim(sdk.getWalletMgr().getSignatureScheme(), acct, context, claimMap, metaData, clmRevMap, pubkeyId, expire); + return claim.getClaimStr(); + } catch (SDKException e) { + throw new SDKException(ErrorCode.CreateDnaIdClaimErr); + } + } + + /** + * @param claim + * @return + * @throws Exception + */ + public boolean verifyDnaIdClaim(String claim) throws Exception { + if (claim == null) { + throw new SDKException(ErrorCode.ParamErr("claim should not be null")); + } + DataSignature sign = null; + try { + + String[] obj = claim.split("\\."); + if (obj.length != 3) { + throw new SDKException(ErrorCode.ParamError); + } + byte[] payloadBytes = Base64.getDecoder().decode(obj[1].getBytes()); + JSONObject payloadObj = JSON.parseObject(new String(payloadBytes)); + String issuerDid = payloadObj.getString("iss"); + String[] str = issuerDid.split(":"); + if (str.length != 3) { + throw new SDKException(ErrorCode.DidError); + } + String issuerDdo = sendGetDDO(issuerDid); + JSONArray owners = JSON.parseObject(issuerDdo).getJSONArray("Owners"); + if (owners == null) { + throw new SDKException(ErrorCode.NotExistCliamIssuer); + } + byte[] signatureBytes = Base64.getDecoder().decode(obj[2]); + byte[] headerBytes = Base64.getDecoder().decode(obj[0].getBytes()); + JSONObject header = JSON.parseObject(new String(headerBytes)); + String kid = header.getString("kid"); + String id = kid.split("#keys-")[1]; + String pubkeyStr = owners.getJSONObject(Integer.parseInt(id) - 1).getString("Value"); + sign = new DataSignature(); + byte[] data = (obj[0] + "." + obj[1]).getBytes(); + return sign.verifySignature(new Account(false, Helper.hexToBytes(pubkeyStr)), data, signatureBytes); + } catch (Exception e) { + throw new SDKException(ErrorCode.VerifyDnaIdClaimErr); + } + } + + + /** + * @param dnaid + * @return + * @throws Exception + */ + public String sendGetDDO(String dnaid) throws Exception { + if (dnaid == null) { + throw new SDKException(ErrorCode.ParamErr("dnaid should not be null")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + + List list = new ArrayList(); + list.add(dnaid.getBytes()); + byte[] arg = NativeBuildParams.createCodeParamsScript(list); + + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"getDDO",arg,null,0,0); + Object obj = sdk.getConnect().sendRawTransactionPreExec(tx.toHexString()); + String res = ((JSONObject) obj).getString("Result"); + if (res.equals("")) { + return res; + } + Map map = parseDdoData(dnaid, res); + if (map.size() == 0) { + return ""; + } + return JSON.toJSONString(map); + } + + private Map parseDdoData(String dnaid, String obj) throws Exception { + byte[] bys = Helper.hexToBytes(obj); + + ByteArrayInputStream bais = new ByteArrayInputStream(bys); + BinaryReader br = new BinaryReader(bais); + byte[] publickeyBytes; + byte[] attributeBytes; + byte[] recoveryBytes; + try { + publickeyBytes = br.readVarBytes(); + } catch (Exception e) { + publickeyBytes = new byte[]{}; + } + try { + attributeBytes = br.readVarBytes(); + } catch (Exception e) { + e.printStackTrace(); + attributeBytes = new byte[]{}; + } + try { + recoveryBytes = br.readVarBytes(); + } catch (Exception e) { + recoveryBytes = new byte[]{}; + } + List pubKeyList = new ArrayList(); + if (publickeyBytes.length != 0) { + ByteArrayInputStream bais1 = new ByteArrayInputStream(publickeyBytes); + BinaryReader br1 = new BinaryReader(bais1); + while (true) { + try { + Map publicKeyMap = new HashMap(); + publicKeyMap.put("PubKeyId", dnaid + "#keys-" + String.valueOf(br1.readInt())); + byte[] pubKey = br1.readVarBytes(); + if(pubKey.length == 33){ + publicKeyMap.put("Type", KeyType.ECDSA.name()); + publicKeyMap.put("Curve", Curve.P256); + publicKeyMap.put("Value", Helper.toHexString(pubKey)); + } else { + publicKeyMap.put("Type", KeyType.fromLabel(pubKey[0])); + publicKeyMap.put("Curve", Curve.fromLabel(pubKey[1])); + publicKeyMap.put("Value", Helper.toHexString(pubKey)); + } + + pubKeyList.add(publicKeyMap); + } catch (Exception e) { + break; + } + } + } + List attrsList = new ArrayList(); + if (attributeBytes.length != 0) { + ByteArrayInputStream bais2 = new ByteArrayInputStream(attributeBytes); + BinaryReader br2 = new BinaryReader(bais2); + while (true) { + try { + Map attributeMap = new HashMap(); + attributeMap.put("Key", new String(br2.readVarBytes())); + attributeMap.put("Type", new String(br2.readVarBytes())); + attributeMap.put("Value", new String(br2.readVarBytes())); + attrsList.add(attributeMap); + } catch (Exception e) { + break; + } + } + } + + Map map = new HashMap(); + map.put("Owners", pubKeyList); + map.put("Attributes", attrsList); + if (recoveryBytes.length != 0) { + map.put("Recovery", Address.parse(Helper.toHexString(recoveryBytes)).toBase58()); + } + map.put("DnaId", dnaid); + return map; + } +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/nativevm/Gas.java b/src/main/java/com/github/DNAProject/smartcontract/nativevm/Gas.java new file mode 100644 index 0000000..421ce84 --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/nativevm/Gas.java @@ -0,0 +1,457 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ +package com.github.DNAProject.smartcontract.nativevm; + +import com.alibaba.fastjson.JSONObject; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.asset.State; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.sdk.exception.SDKException; +import com.github.DNAProject.smartcontract.nativevm.abi.NativeBuildParams; +import com.github.DNAProject.smartcontract.nativevm.abi.Struct; + +import java.util.ArrayList; +import java.util.List; + + +/** + * + */ +public class Gas { + private DnaSdk sdk; + private final String contract = "0000000000000000000000000000000000000001"; + private final String gasContract = "0000000000000000000000000000000000000002"; + + public Gas(DnaSdk sdk) { + this.sdk = sdk; + } + + public String getContractAddress() { + return gasContract; + } + + /** + * + * @param sendAcct + * @param recvAddr + * @param amount + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public String sendTransfer(Account sendAcct, String recvAddr, long amount, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if (sendAcct == null || payerAcct == null ) { + throw new SDKException(ErrorCode.ParamErr("parameters should not be null")); + } + if (amount <= 0 || gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("amount or gasprice or gaslimit should not be less than 0")); + } + Transaction tx = makeTransfer(sendAcct.getAddressU160().toBase58(), recvAddr, amount, payerAcct.getAddressU160().toBase58(), gaslimit, gasprice); + sdk.signTx(tx, new Account[][]{{sendAcct}}); + if(!sendAcct.equals(payerAcct)){ + sdk.addSign(tx,payerAcct); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + public String sendTransferMulti(Account[] accounts, State[] states,Account payerAcct,long gaslimit, long gasprice) throws Exception { + if (accounts == null || payerAcct == null ) { + throw new SDKException(ErrorCode.ParamErr("parameters should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("amount or gasprice or gaslimit should not be less than 0")); + } + Transaction tx = makeTransfer(states, payerAcct.getAddressU160().toBase58(), gaslimit, gasprice); + sdk.signTx(tx, new Account[][]{{payerAcct}}); + for(int i =0;i. + * + */ + +package com.github.DNAProject.smartcontract.nativevm; + +import com.alibaba.fastjson.JSONObject; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.globalparams.Params; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.network.exception.ConnectorException; +import com.github.DNAProject.sdk.exception.SDKException; +import com.github.DNAProject.smartcontract.nativevm.abi.NativeBuildParams; +import com.github.DNAProject.smartcontract.nativevm.abi.Struct; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class GlobalParams { + private DnaSdk sdk; + private final String contractAddress = "0000000000000000000000000000000000000004"; + public GlobalParams(DnaSdk sdk) { + this.sdk = sdk; + } + + public boolean init() throws Exception{ + Transaction tx = sdk.vm().makeInvokeCodeTransaction(contractAddress,"init", new byte[]{}, null,0,0); + return sdk.getConnect().sendRawTransaction(tx.toHexString()); + } + + public String transferAdmin(Account adminAccount,Address newAdminAddr,Account payerAcct, long gaslimit,long gasprice) throws Exception { + if(adminAccount==null || newAdminAddr == null || payerAcct == null){ + throw new SDKException("parameter should not be null"); + } + if(gaslimit < 0 || gasprice < 0 ){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + Transaction tx = makeTransferAdmin(newAdminAddr,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + sdk.signTx(tx,new Account[][]{{adminAccount}}); + if(!adminAccount.equals(payerAcct)){ + sdk.addSign(tx,payerAcct); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if(b) { + return tx.hash().toHexString(); + } + return null; + } + public String transferAdmin(int M,Account[] accounts,Address newAdminAddr,Account payerAcct, long gaslimit,long gasprice) throws Exception { + if(accounts.length== 0 || newAdminAddr == null || payerAcct == null){ + throw new SDKException("parameter should not be null"); + } + if(accounts.length < M) { + throw new SDKException("the accounts length should not be less than M"); + } + if(gaslimit < 0 || gasprice < 0 ){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + Transaction tx = makeTransferAdmin(newAdminAddr,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + sdk.signTx(tx,new Account[][]{accounts},new int[]{M}); + sdk.addSign(tx,payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if(b) { + return tx.hash().toHexString(); + } + return null; + } + + public Transaction makeTransferAdmin(Address newAdminAddr,String payerAddr, long gaslimit,long gasprice) throws SDKException { + if(newAdminAddr == null || payerAddr == null || payerAddr.equals("")){ + throw new SDKException("parameter should not be null"); + } + if(gaslimit < 0 || gasprice < 0 ){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + List list = new ArrayList(); + Struct struct = new Struct(); + struct.add(newAdminAddr.toArray()); + list.add(struct); + byte[] arg = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"transferAdmin",arg,payerAddr,gaslimit,gasprice); + return tx; + } + + public String acceptAdmin(Account account,Account payerAcct, long gaslimit,long gasprice) throws Exception { + if(account == null || payerAcct == null){ + throw new SDKException("parameter should not be null"); + } + if(gaslimit < 0 || gasprice < 0 ){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + Transaction tx = makeAcceptAdmin(account.getAddressU160(),payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + sdk.signTx(tx,new Account[][]{{account}}); + if(!account.equals(payerAcct)){ + sdk.addSign(tx,payerAcct); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if(b) { + return tx.hash().toHexString(); + } + return null; + } + public String acceptAdmin(Address multiAddr,int M,Account[] accounts,Account payerAcct, long gaslimit,long gasprice) throws Exception { + if(accounts.length== 0 || multiAddr == null || payerAcct == null){ + throw new SDKException("parameter should not be null"); + } + if(accounts.length < M) { + throw new SDKException("the accounts length should not be less than M"); + } + if(gaslimit < 0 || gasprice < 0 ){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + Transaction tx = makeAcceptAdmin(multiAddr,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + sdk.signTx(tx,new Account[][]{accounts},new int[]{M}); + sdk.addSign(tx,payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if(b) { + return tx.hash().toHexString(); + } + return null; + } + public Transaction makeAcceptAdmin(Address multiAddr,String payerAddr, long gaslimit,long gasprice) throws SDKException { + if(multiAddr == null || payerAddr == null || payerAddr.equals("")){ + throw new SDKException("parameter should not be null"); + } + if(gaslimit < 0 || gasprice < 0 ){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + List list = new ArrayList(); + Struct struct = new Struct(); + struct.add(multiAddr.toArray()); + list.add(struct); + byte[] arg = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"transferAdmin",arg,payerAddr,gaslimit,gasprice); + return tx; + } + + + public String getGlobalParam(String[] paramNameList) throws SDKException, ConnectorException, IOException { + if(paramNameList.length == 0) { + throw new SDKException("parameter should not be less than 0"); + } + List list = new ArrayList(); + Struct struct = new Struct(); + struct.add(paramNameList.length); + for (int i = 0; i < paramNameList.length; i++) { + struct.add(paramNameList[i]); + } + list.add(struct); + byte[] arg = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"getGlobalParam",arg,null,0,0); + Object obj = sdk.getConnect().sendRawTransactionPreExec(tx.toHexString()); + String res = ((JSONObject) obj).getString("Result"); + return res; + } + + public String setGlobalParam(Account operatorAccount,Params params, Account payerAcct,long gaslimit,long gasprice) throws Exception { + if(operatorAccount == null || params == null || payerAcct == null){ + throw new SDKException("parameter should not be null"); + } + if(gaslimit < 0 || gasprice < 0 ){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + Transaction tx = makeSetGlobalParam(params,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + sdk.signTx(tx,new Account[][]{{operatorAccount}}); + if(!operatorAccount.equals(payerAcct)){ + sdk.addSign(tx,payerAcct); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if(b) { + return tx.hash().toHexString(); + } + return null; + } + + public String setGlobalParam(int M,Account[] operatorAccounts,Params params, Account payerAcct,long gaslimit,long gasprice) throws Exception { + if(operatorAccounts.length== 0 || params == null || payerAcct == null){ + throw new SDKException("parameter should not be null"); + } + if(operatorAccounts.length < M) { + throw new SDKException("the operatorAccounts length should not be less than M"); + } + if(gaslimit < 0 || gasprice < 0 ){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + Transaction tx = makeSetGlobalParam(params,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + sdk.signTx(tx,new Account[][]{operatorAccounts},new int[]{M}); + sdk.addSign(tx,payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if(b) { + return tx.hash().toHexString(); + } + return null; + } + + public Transaction makeSetGlobalParam(Params params,String payerAddr,long gaslimit,long gasprice) throws SDKException { + if(params == null || payerAddr == null || payerAddr.equals("")){ + throw new SDKException("parameter should not be null"); + } + if(gaslimit < 0 || gasprice < 0 ){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + List list = new ArrayList(); + Struct struct = new Struct(); + struct.add(params.params.length); + for(int i=0;i< params.params.length;i++){ + struct.add(params.params[i].key,params.params[i].value); + } + list.add(struct); + byte[] arg = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"setGlobalParam",arg,payerAddr,gaslimit,gasprice); + return tx; + } + + + public String setOperator(Account adminAccount,Address addr,Account payerAcct,long gaslimit,long gasprice) throws Exception { + if(adminAccount == null || addr == null || payerAcct == null){ + throw new SDKException("parameter should not be null"); + } + if(gaslimit < 0 || gasprice < 0 ){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + Transaction tx = makeSetOperator(addr,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + sdk.signTx(tx,new Account[][]{{adminAccount}}); + if(!adminAccount.equals(payerAcct)){ + sdk.addSign(tx,payerAcct); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if(b) { + return tx.hash().toHexString(); + } + return null; + } + + public String setOperator(int M,Account[] accounts,Address addr,Account payerAcct,long gaslimit,long gasprice) throws Exception { + if(accounts.length == 0 || addr == null || payerAcct == null){ + throw new SDKException("parameter should not be null"); + } + if(accounts.length < M){ + throw new SDKException("accounts length should not be less than M"); + } + if(gaslimit < 0 || gasprice < 0 ){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + Transaction tx = makeSetOperator(addr,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + sdk.signTx(tx,new Account[][]{accounts},new int[]{M}); + sdk.addSign(tx,payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if(b) { + return tx.hash().toHexString(); + } + return null; + } + + public Transaction makeSetOperator(Address addr,String payerAddr,long gaslimit,long gasprice) throws SDKException { + if(addr==null || payerAddr == null || payerAddr.equals("")){ + throw new SDKException("parameter should not be null"); + } + if(gaslimit < 0 || gasprice < 0 ){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + List list = new ArrayList(); + Struct struct = new Struct(); + struct.add(addr.toArray()); + list.add(struct); + byte[] arg = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"transferAdmin",arg,payerAddr,gaslimit,gasprice); + return tx; + } + + public String createSnapshot(Account operatorAccount,Account payerAcct,long gaslimit,long gasprice) throws Exception { + if(operatorAccount==null || payerAcct == null){ + throw new SDKException("parameter should not be null"); + } + if(gaslimit < 0 || gasprice < 0 ){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + Transaction tx = makeCreateSnapshot(payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + sdk.signTx(tx,new Account[][]{{operatorAccount}}); + if(!operatorAccount.equals(payerAcct)){ + sdk.addSign(tx,payerAcct); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if(b) { + return tx.hash().toHexString(); + } + return null; + } + public String createSnapshot(int M,Account[] operatorAccounts,Account payerAcct,long gaslimit,long gasprice) throws Exception { + if(operatorAccounts.length==0 || payerAcct == null){ + throw new SDKException("parameter should not be null"); + } + if(operatorAccounts.length < M){ + throw new SDKException("accounts length should not be less than M"); + } + if(gaslimit < 0 || gasprice < 0 ){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + Transaction tx = makeCreateSnapshot(payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + sdk.signTx(tx,new Account[][]{operatorAccounts},new int[]{M}); + sdk.addSign(tx,payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if(b) { + return tx.hash().toHexString(); + } + return null; + } + public Transaction makeCreateSnapshot(String payerAddr,long gaslimit,long gasprice) throws SDKException { + if(payerAddr == null || payerAddr.equals("")){ + throw new SDKException("parameter should not be null"); + } + if(gaslimit < 0 || gasprice < 0 ){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"createSnapshot",new byte[]{0},payerAddr,gaslimit,gasprice); + return tx; + } +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/nativevm/Governance.java b/src/main/java/com/github/DNAProject/smartcontract/nativevm/Governance.java new file mode 100644 index 0000000..6fc9914 --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/nativevm/Governance.java @@ -0,0 +1,1448 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.smartcontract.nativevm; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.*; +import com.github.DNAProject.core.asset.Sig; +import com.github.DNAProject.core.block.Block; +import com.github.DNAProject.core.governance.*; +import com.github.DNAProject.core.sidechaingovernance.SideChainNodeInfo; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; +import com.github.DNAProject.network.exception.ConnectorException; +import com.github.DNAProject.sdk.exception.SDKException; +import com.github.DNAProject.smartcontract.nativevm.abi.NativeBuildParams; +import com.github.DNAProject.smartcontract.nativevm.abi.Struct; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class Governance { + private DnaSdk sdk; + private final String contractAddress = "0000000000000000000000000000000000000007"; + private final String AUTHORIZE_INFO_POOL = "766f7465496e666f506f6f6c"; + private final String PEER_ATTRIBUTES = "peerAttributes"; + private final String SPLIT_FEE_ADDRESS = "splitFeeAddress"; + private final String TOTAL_STAKE = "totalStake"; + private final String PEER_POOL = "peerPool"; + private final String GLOBAL_PARAM = "globalParam"; + private final String GLOBAL_PARAM2 = "globalParam2"; + private final String SPLIT_CURVE = "splitCurve"; + private final String SIDE_CHAIN_NODE_INFO = "sideChainNodeInfo"; + private final String SIDE_GOVERNANCE_CONTRACT_ADDRESS = "0000000000000000000000000000000000000008"; + private final long[] UNBOUND_GENERATION_AMOUNT = new long[]{5, 4, 3, 3, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + private final int UNBOUND_TIME_INTERVAL = 31536000; + private final long ONT_TOTAL_SUPPLY = 1000000000; + public Governance(DnaSdk sdk) { + this.sdk = sdk; + } + public String getContractAddress() { + return contractAddress; + } + /** + * + * @param account + * @param peerPubkey + * @param initPos + * @param dnaid + * @param dnaidpwd + * @param keyNo + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public String registerCandidate(Account account, String peerPubkey, long initPos, String dnaid,String dnaidpwd,byte[] salt, long keyNo, Account payerAcct, long gaslimit, long gasprice) throws Exception{ +// byte[] params = new RegisterCandidateParam(peerPubkey,account.getAddressU160(),initPos,dnaid.getBytes(),keyNo).toArray(); +// Transaction tx = sdk.vm().makeInvokeCodeTransaction(contractAddress,"registerCandidate",params,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + + List list = new ArrayList(); + list.add(new Struct().add(peerPubkey,account.getAddressU160(),initPos,dnaid.getBytes(),keyNo)); + byte[] args = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"registerCandidate",args,payerAcct.getAddressU160().toBase58(),gaslimit, gasprice); + sdk.signTx(tx,new Account[][]{{account}}); + sdk.addSign(tx,dnaid,dnaidpwd,salt); + if(!account.equals(payerAcct)){ + sdk.addSign(tx,payerAcct); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + + /** + * + * @param account + * @param peerPubkey + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public String unRegisterCandidate(Account account, String peerPubkey,Account payerAcct, long gaslimit, long gasprice) throws Exception{ + + List list = new ArrayList(); + list.add(new Struct().add(peerPubkey,account.getAddressU160())); + byte[] args = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"unRegisterCandidate",args,payerAcct.getAddressU160().toBase58(),gaslimit, gasprice); + sdk.signTx(tx,new Account[][]{{account}}); + if(!account.equals(payerAcct)){ + sdk.addSign(tx,payerAcct); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + + + + public String withdrawGas(Account account,Account payerAcct,long gaslimit,long gasprice) throws Exception { + List list = new ArrayList(); + list.add(new Struct().add(account.getAddressU160())); + byte[] args = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"withdrawOng",args,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + sdk.signTx(tx,new Account[][]{{account}}); + if(!account.equals(payerAcct)){ + sdk.addSign(tx,payerAcct); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + + public String withdrawFee(Account account,Account payerAcct,long gaslimit,long gasprice) throws Exception { + List list = new ArrayList(); + list.add(new Struct().add(account.getAddressU160())); + byte[] args = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"withdrawFee",args,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + sdk.signTx(tx,new Account[][]{{account}}); + if(!account.equals(payerAcct)){ + sdk.addSign(tx,payerAcct); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + + /** + * + * @param peerPubkey + * @return + * @throws ConnectorException + * @throws IOException + */ + public String getPeerInfo(String peerPubkey) throws ConnectorException, IOException { + return (String) getPeerPoolMap(peerPubkey,false); + } + + /** + * + * @return + * @throws ConnectorException + * @throws IOException + */ + public String getPeerInfoAll() throws ConnectorException, IOException { + return (String) getPeerPoolMap(null, false); + } + public Map getPeerPoolMap() throws ConnectorException, IOException { + return (Map) getPeerPoolMap(null,true); + } + public GovernanceView getGovernanceView() throws ConnectorException, IOException, SDKException { + String view = sdk.getConnect().getStorage(Helper.reverse(contractAddress),Helper.toHexString("governanceView".getBytes())); + if(view == null || view.equals("")){ + throw new SDKException(ErrorCode.OtherError("view is null")); + } + GovernanceView governanceView = new GovernanceView(); + ByteArrayInputStream bais = new ByteArrayInputStream(Helper.hexToBytes(view)); + BinaryReader br = new BinaryReader(bais); + governanceView.deserialize(br); + return governanceView; + } + /** + * + * @return + * @throws ConnectorException + * @throws IOException + */ + private Object getPeerPoolMap(String peerPubkey, boolean isResultMap) throws ConnectorException, IOException { + String view = sdk.getConnect().getStorage(Helper.reverse(contractAddress),Helper.toHexString("governanceView".getBytes())); + GovernanceView governanceView = new GovernanceView(); + ByteArrayInputStream bais = new ByteArrayInputStream(Helper.hexToBytes(view)); + BinaryReader br = new BinaryReader(bais); + governanceView.deserialize(br); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + BinaryWriter bw = new BinaryWriter(baos); + bw.writeInt(governanceView.view); + + byte[] viewBytes = baos.toByteArray(); + byte[] peerPoolBytes = "peerPool".getBytes(); + byte[] keyBytes = new byte[peerPoolBytes.length + viewBytes.length]; + System.arraycopy(peerPoolBytes,0,keyBytes,0,peerPoolBytes.length); + System.arraycopy(viewBytes,0,keyBytes,peerPoolBytes.length,viewBytes.length); + String value = sdk.getConnect().getStorage(Helper.reverse(contractAddress),Helper.toHexString(keyBytes)); + ByteArrayInputStream bais2 = new ByteArrayInputStream(Helper.hexToBytes(value)); + BinaryReader reader = new BinaryReader(bais2); + int length = reader.readInt(); + Map peerPoolMap = new HashMap(); + Map peerPoolMap2 = new HashMap(); + for(int i = 0;i < length;i++){ + PeerPoolItem item = new PeerPoolItem(); + item.deserialize(reader); + peerPoolMap.put(item.peerPubkey,item.Json()); + peerPoolMap2.put(item.peerPubkey, item); + } + if(isResultMap){ + return peerPoolMap2; + } + if(peerPubkey != null) { + if(!peerPoolMap.containsKey(peerPubkey)) { + return null; + } + return JSON.toJSONString(peerPoolMap.get(peerPubkey)); + } + return JSON.toJSONString(peerPoolMap); + } + + /** + * + * @param peerPubkey + * @param addr + * @return + */ + public String getAuthorizeInfo(String peerPubkey,Address addr) { + byte[] peerPubkeyPrefix = Helper.hexToBytes(peerPubkey); + byte[] address = addr.toArray(); + byte[] authorizeInfoPool = Helper.hexToBytes(AUTHORIZE_INFO_POOL); + byte[] key = new byte[authorizeInfoPool.length + peerPubkeyPrefix.length + address.length]; + System.arraycopy(authorizeInfoPool,0,key,0,authorizeInfoPool.length); + System.arraycopy(peerPubkeyPrefix,0,key,authorizeInfoPool.length,peerPubkeyPrefix.length); + System.arraycopy(address,0,key,authorizeInfoPool.length + peerPubkeyPrefix.length,address.length); + String res = null; + try { + res = sdk.getConnect().getStorage(Helper.reverse(contractAddress),Helper.toHexString(key)); + if(res !=null && !res.equals("")){ + AuthorizeInfo authorizeInfo = Serializable.from(Helper.hexToBytes(res), AuthorizeInfo.class); + return authorizeInfo.toJson(); + } + } catch (ConnectorException e) { + return null; + } catch (IOException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InstantiationException e) { + e.printStackTrace(); + } + + return null; + } + + /** + * + * @param peerPubkey + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public String approveCandidate(Account adminAccount, String peerPubkey,Account payerAcct,long gaslimit,long gasprice) throws Exception{ +// byte[] params = new ApproveCandidateParam(peerPubkey).toArray(); +// Transaction tx = sdk.vm().makeInvokeCodeTransaction(contractAddress,"approveCandidate",params,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + + List list = new ArrayList(); + list.add(new Struct().add(peerPubkey)); + byte[] args = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"approveCandidate",args,payerAcct.getAddressU160().toBase58(),gaslimit, gasprice); + sdk.signTx(tx,new Account[][]{{adminAccount}}); + if(!adminAccount.equals(payerAcct)) { + sdk.addSign(tx,payerAcct); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + + /** + * + * @param multiAddress + * @param M + * @param accounts + * @param publicKeys + * @param peerPubkey + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public String approveCandidate(Address multiAddress,int M, Account[] accounts,byte[][] publicKeys,String peerPubkey,Account payerAcct,long gaslimit,long gasprice) throws Exception{ + + byte[][] pks = new byte[accounts.length+publicKeys.length][]; + for(int i=0;i 100){ + throw new SDKException(ErrorCode.ParamErr("peerCost is wrong, it should be 0 <= peerCost <= 100")); + } + List list = new ArrayList(); + list.add(new Struct().add(peerPubkey,account.getAddressU160(),peerCost)); + byte[] args = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"setPeerCost",args,payerAcct.getAddressU160().toBase58(),gaslimit, gasprice); + sdk.signTx(tx,new Account[][]{{account}}); + if(!account.equals(payerAcct)){ + sdk.addSign(tx,payerAcct); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + + /** + * + * @param peerPubkey + * @return + * @throws ConnectorException + * @throws IOException + */ + public String getPeerAttributes(String peerPubkey) throws ConnectorException, IOException { + byte[] peerAttributes = PEER_ATTRIBUTES.getBytes(); + byte[] peerPubkeyBytes = Helper.hexToBytes(peerPubkey); + byte[] key = new byte[peerPubkeyBytes.length + peerAttributes.length]; + System.arraycopy(peerAttributes,0, key,0, peerAttributes.length); + System.arraycopy(peerPubkeyBytes,0, key,peerAttributes.length, peerPubkeyBytes.length); + String res = sdk.getConnect().getStorage(Helper.reverse(contractAddress),Helper.toHexString(key)); + if(res== null || res.equals("")){ + PeerAttributes peerAttributes1 = new PeerAttributes(peerPubkey); + return peerAttributes1.toJson(); + } + PeerAttributes peerAttributes2 = new PeerAttributes(); + ByteArrayInputStream bais = new ByteArrayInputStream(Helper.hexToBytes(res)); + BinaryReader reader = new BinaryReader(bais); + peerAttributes2.deserialize(reader); + return peerAttributes2.toJson(); + } + + public String getSplitFeeAddress(String address) throws Exception { + byte[] splitFeeAddressBytes = SPLIT_FEE_ADDRESS.getBytes(); + byte[] addressBytes = Address.decodeBase58(address).toArray(); + byte[] key = new byte[addressBytes.length + splitFeeAddressBytes.length]; + System.arraycopy(splitFeeAddressBytes,0,key,0,splitFeeAddressBytes.length); + System.arraycopy(addressBytes,0,key,splitFeeAddressBytes.length,addressBytes.length); + String res = sdk.getConnect().getStorage(Helper.reverse(contractAddress),Helper.toHexString(key)); + if(res == null || res.equals("")){ + return null; + }else{ + ByteArrayInputStream bais = new ByteArrayInputStream(Helper.hexToBytes(res)); + BinaryReader reader = new BinaryReader(bais); + SplitFeeAddress splitFeeAddress = new SplitFeeAddress(); + splitFeeAddress.deserialize(reader); + return splitFeeAddress.toJson(); + } + } + + public long getPeerUbindOng(String address) throws ConnectorException, IOException, SDKException { + int timestamp0 = 1530316800;//创世块时间戳 + int current_height = sdk.getConnect().getBlockHeight(); + Block block = sdk.getConnect().getBlock(current_height); + int timestamp = block.timestamp - timestamp0; + TotalStake totalStake = getTotalStake(address); + if(totalStake == null){ + return 0; + } + return calcUnbindOng(totalStake.stake,totalStake.timeOffset,timestamp); + } + + public long calcUnbindOng(long balance, int startOffset, int endOffset){ + long amount = 0; + if(startOffset >= endOffset){ + return 0; + } + int unboundDeadLine = unboundDeadLine(); + if(startOffset < unboundDeadLine){ + int ustart = startOffset / UNBOUND_TIME_INTERVAL; + int istart = startOffset % UNBOUND_TIME_INTERVAL; + if(endOffset >= unboundDeadLine){ + endOffset = unboundDeadLine; + } + int uend = endOffset / UNBOUND_TIME_INTERVAL; + int iend = endOffset % UNBOUND_TIME_INTERVAL; + while(ustart < uend){ + amount = (UNBOUND_TIME_INTERVAL - istart) * UNBOUND_GENERATION_AMOUNT[ustart]; + ustart += 1; + istart = 0; + } + amount += (iend - istart) * UNBOUND_GENERATION_AMOUNT[ustart]; + } + return amount * balance; + } + + private int unboundDeadLine(){ + long count = 0; + for(long i: UNBOUND_GENERATION_AMOUNT){ + count += i; + } + count *= UNBOUND_TIME_INTERVAL; + int numInterval = UNBOUND_GENERATION_AMOUNT.length; + return (int) (UNBOUND_TIME_INTERVAL * numInterval - (count - ONT_TOTAL_SUPPLY)); + } + + private TotalStake getTotalStake(String address) throws SDKException, ConnectorException, IOException { + byte[] totalStakeBytes = TOTAL_STAKE.getBytes(); + byte[] addressBytes = Address.decodeBase58(address).toArray(); + byte[] key = new byte[totalStakeBytes.length + addressBytes.length]; + System.arraycopy(totalStakeBytes,0,key,0,totalStakeBytes.length); + System.arraycopy(addressBytes,0,key,totalStakeBytes.length,addressBytes.length); + String res = sdk.getConnect().getStorage(Helper.reverse(contractAddress),Helper.toHexString(key)); + if(res == null){ + return null; + } + TotalStake totalStake = new TotalStake(); + ByteArrayInputStream bais = new ByteArrayInputStream(Helper.hexToBytes(res)); + BinaryReader reader = new BinaryReader(bais); + totalStake.deserialize(reader); + return totalStake; + } + + /** + * + * @param config + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public String updateConfig(Account[] accounts, byte[][] pks,int M,Configuration config,Account payerAcct,long gaslimit,long gasprice) throws Exception{ + List list = new ArrayList(); + list.add(new Struct().add(config.N, config.C, config.K, config.L, config.BlockMsgDelay, + config.HashMsgDelay, config.PeerHandshakeTimeout, config.MaxBlockChangeView)); + byte[] args = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"updateConfig",args,payerAcct.getAddressU160().toBase58(),gaslimit, gasprice); + sdk.signTx(tx, new Account[][]{{payerAcct}}); + for(Account account : accounts){ + sdk.addMultiSign(tx, M,pks,account); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + + public String updateSplitCurve(Account[] accounts, byte[][] pks,int M,SplitCurve curve,Account payerAcct,long gaslimit,long gasprice) throws Exception{ + List list = new ArrayList(); + Struct struct = new Struct(); + struct.add(curve.Yi.length); + for(int i=0;i< curve.Yi.length;i++){ + struct.add(curve.Yi[i]); + } + list.add(struct); + byte[] args = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"updateSplitCurve",args,payerAcct.getAddressU160().toBase58(),gaslimit, gasprice); + sdk.signTx(tx, new Account[][]{{payerAcct}}); + for(Account account : accounts){ + sdk.addMultiSign(tx, M,pks,account); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + + + public String updateGlobalParam1(Account[] accounts,byte[][] pks, int M,GlobalParam1 param1,Account payerAcct,long gaslimit,long gasprice) throws Exception{ + List list = new ArrayList(); + list.add(new Struct().add(param1.candidateFee,param1.minInitStake,param1.candidateNum,param1.posLimit,param1.A, + param1.B,param1.yita, param1.penalty)); + byte[] args = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"updateGlobalParam",args,payerAcct.getAddressU160().toBase58(),gaslimit, gasprice); + sdk.signTx(tx, new Account[][]{{payerAcct}}); + for(Account account : accounts){ + sdk.addMultiSign(tx, M,pks,account); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + public String updateGlobalParam2(Account[] accounts,byte[][] pks, int M,GlobalParam2 param2,Account payerAcct,long gaslimit,long gasprice) throws Exception{ + List list = new ArrayList(); + list.add(new Struct().add(param2.minAuthorizePos,param2.candidateFeeSplitNum, param2.field1,param2.field2,param2.field3,param2.field4,param2.field5,param2.field6)); + byte[] args = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"updateGlobalParam2",args,payerAcct.getAddressU160().toBase58(),gaslimit, gasprice); + sdk.signTx(tx, new Account[][]{{payerAcct}}); + for(Account account : accounts){ + sdk.addMultiSign(tx, M,pks,account); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + + /** + * + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public String callSplit(Account payerAcct,long gaslimit,long gasprice) throws Exception{ +// Transaction tx = sdk.vm().makeInvokeCodeTransaction(contractAddress,"updateConfig",new byte[]{},payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + + Transaction tx = sdk.vm().buildNativeParams(new Address(Helper.hexToBytes(contractAddress)),"callSplit",new byte[]{},payerAcct.getAddressU160().toBase58(),gaslimit, gasprice); + sdk.signTx(tx,new Account[][]{{payerAcct}}); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + //please get data from mainchain + public Configuration getConfiguration() throws ConnectorException, IOException { + String res = sdk.getConnect().getStorage(Helper.reverse(contractAddress), Helper.toHexString("vbftConfig".getBytes())); + if(res == null){ + return null; + } + Configuration configuration = new Configuration(); + ByteArrayInputStream in = new ByteArrayInputStream(Helper.hexToBytes(res)); + BinaryReader reader = new BinaryReader(in); + configuration.deserialize(reader); + return configuration; + } + + public GlobalParam1 getGlobalParam1() throws ConnectorException, IOException { + String res = sdk.getConnect().getStorage(Helper.reverse(contractAddress),Helper.toHexString(GLOBAL_PARAM.getBytes())); + if(res == null || res.equals("")){ + return null; + } + ByteArrayInputStream in = new ByteArrayInputStream(Helper.hexToBytes(res)); + BinaryReader reader = new BinaryReader(in); + GlobalParam1 globalParam1 = new GlobalParam1(); + globalParam1.deserialize(reader); + return globalParam1; + } + public GlobalParam2 getGlobalParam2() throws ConnectorException, IOException { + String res2 = sdk.getConnect().getStorage(Helper.reverse(contractAddress),Helper.toHexString(GLOBAL_PARAM2.getBytes())); + if(res2 != null && !res2.equals("")){ + GlobalParam2 globalParam2 = new GlobalParam2(); + ByteArrayInputStream in2 = new ByteArrayInputStream(Helper.hexToBytes(res2)); + BinaryReader reader2 = new BinaryReader(in2); + globalParam2.deserialize(reader2); + return globalParam2; + } + return null; + } + + public GlobalParam getGlobalParam() throws ConnectorException, IOException { + String res = sdk.getConnect().getStorage(Helper.reverse(contractAddress),Helper.toHexString(GLOBAL_PARAM.getBytes())); + if(res == null || res.equals("")){ + return null; + } + ByteArrayInputStream in = new ByteArrayInputStream(Helper.hexToBytes(res)); + BinaryReader reader = new BinaryReader(in); + GlobalParam1 globalParam1 = new GlobalParam1(); + globalParam1.deserialize(reader); + String res2 = sdk.getConnect().getStorage(Helper.reverse(contractAddress),Helper.toHexString(GLOBAL_PARAM2.getBytes())); + GlobalParam2 globalParam2 = null; + if(res2 != null && !res2.equals("")){ + globalParam2 = new GlobalParam2(); + ByteArrayInputStream in2 = new ByteArrayInputStream(Helper.hexToBytes(res2)); + BinaryReader reader2 = new BinaryReader(in); + globalParam2.deserialize(reader2); + } + GlobalParam param = new GlobalParam(); + if(globalParam2 != null){ + param.candidateFeeSplitNum = globalParam2.candidateFeeSplitNum; + }else { + param.candidateFeeSplitNum = globalParam1.candidateNum; + } + param.A = globalParam1.A; + param.B = globalParam1.B; + param.yita =globalParam1.yita; + return param; + } + public SplitCurve getSplitCurve() throws ConnectorException, IOException { + String res = sdk.getConnect().getStorage(Helper.reverse(contractAddress), Helper.toHexString(SPLIT_CURVE.getBytes())); + SplitCurve curve = new SplitCurve(); + ByteArrayInputStream in = new ByteArrayInputStream(Helper.hexToBytes(res)); + BinaryReader reader = new BinaryReader(in); + curve.deserialize(reader); + return curve; + } + + public InputPeerPoolMapParam getInputPeerPoolMapParam(String sideChainId) throws ConnectorException, IOException, SDKException { + Map peerPoolMap = getPeerPoolMap(); + byte[] sideChainIdBytes = sideChainId.getBytes(); + byte[] sideChainNodeInfoBytes = SIDE_CHAIN_NODE_INFO.getBytes(); + byte[] key = new byte[sideChainIdBytes.length + sideChainNodeInfoBytes.length]; + System.arraycopy(sideChainNodeInfoBytes,0, key,0,sideChainNodeInfoBytes.length); + System.arraycopy(sideChainIdBytes,0, key,sideChainNodeInfoBytes.length,sideChainIdBytes.length); + String resNode = sdk.getConnect().getStorage(Helper.reverse(SIDE_GOVERNANCE_CONTRACT_ADDRESS), Helper.toHexString(key)); + if(resNode == null || resNode.equals("")){ + throw new SDKException(ErrorCode.OtherError("NodeToSideChainParams is null")); + } + SideChainNodeInfo info = new SideChainNodeInfo(); + ByteArrayInputStream in = new ByteArrayInputStream(Helper.hexToBytes(resNode)); + BinaryReader reader = new BinaryReader(in); + info.deserialize(reader); + InputPeerPoolMapParam param = new InputPeerPoolMapParam(peerPoolMap, info.nodeInfoMap); + return param; + } + +} + +class TotalStake implements Serializable{ + public Address address; + public long stake; + public int timeOffset; + public TotalStake(){} + + @Override + public void deserialize(BinaryReader reader) throws IOException { + try { + this.address = reader.readSerializable(Address.class); + this.stake = reader.readLong(); + this.timeOffset = reader.readInt(); + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + @Override + public void serialize(BinaryWriter writer) throws IOException { + + } +} + +class SplitFeeAddress implements Serializable{ + public Address address; + public long amount; + + @Override + public void deserialize(BinaryReader reader) throws IOException { + try{ + this.address = reader.readSerializable(Address.class); + }catch (Exception e){ + e.printStackTrace(); + System.out.println(e); + } + this.amount = reader.readLong(); + + } + + @Override + public void serialize(BinaryWriter writer) throws IOException { + + } + + public String toJson(){ + Map map = new HashMap(); + map.put("address",this.address.toBase58()); + map.put("amount", amount); + return JSON.toJSONString(map); + } +} +class PeerAttributes implements Serializable{ + public String peerPubkey; + public long maxAuthorize; //max authorzie pos this peer can receive + public long t2PeerCost; //old peer cost, active when current view - SetCostView < 2 + public long t1PeerCost; //new peer cost, active when current view - SetCostView >= 2 + public long tPeerCost; //the view when when set new peer cost + public byte[] field1; + public byte[] field2; + public byte[] field3; + public byte[] field4; + + PeerAttributes(){} + + PeerAttributes(String peerPubKey) { + this.peerPubkey = peerPubKey; + this.maxAuthorize = 0; + this.t2PeerCost = 100; + this.t1PeerCost = 100; + this.tPeerCost = 100; + } + + @Override + public void deserialize(BinaryReader reader) throws IOException { + this.peerPubkey = reader.readVarString(); + this.maxAuthorize = reader.readLong(); + this.t2PeerCost = reader.readLong(); + this.t1PeerCost = reader.readLong(); + this.tPeerCost = reader.readLong(); + this.field1 = reader.readVarBytes(); + this.field2 = reader.readVarBytes(); + this.field3 = reader.readVarBytes(); + this.field4 = reader.readVarBytes(); + } + + @Override + public void serialize(BinaryWriter writer) throws IOException { + + } + + public String toJson(){ + return JSON.toJSONString(this); + } +} + + +class RegisterSyncNodeParam implements Serializable { + public String peerPubkey; + public String address; + public long initPos; + public RegisterSyncNodeParam(String peerPubkey,String address,long initPos){ + this.peerPubkey = peerPubkey; + this.address = address; + this.initPos = initPos; + } + @Override + public void deserialize(BinaryReader reader) throws IOException {} + @Override + public void serialize(BinaryWriter writer) throws IOException { + writer.writeVarString(peerPubkey); + writer.writeVarString(address); + writer.writeLong(initPos); + } +} +class ApproveCandidateParam implements Serializable { + public String peerPubkey; + public ApproveCandidateParam(String peerPubkey){ + this.peerPubkey = peerPubkey; + } + @Override + public void deserialize(BinaryReader reader) throws IOException {} + @Override + public void serialize(BinaryWriter writer) throws IOException { + writer.writeVarString(peerPubkey); + } +} +class RejectCandidateParam implements Serializable { + + public String peerPubkey; + RejectCandidateParam(String peerPubkey){ + this.peerPubkey = peerPubkey; + } + + @Override + public void deserialize(BinaryReader reader) throws IOException { + + } + + @Override + public void serialize(BinaryWriter writer) throws IOException { + writer.writeVarString(peerPubkey); + } +} +class RegisterCandidateParam implements Serializable { + public String peerPubkey; + public Address address; + public long initPos; + public byte[] caller; + public long keyNo; + public RegisterCandidateParam(String peerPubkey,Address address,long initPos,byte[] caller,long keyNo){ + this.peerPubkey = peerPubkey; + this.address = address; + this.initPos = initPos; + this.caller = caller; + this.keyNo = keyNo; + } + @Override + public void deserialize(BinaryReader reader) throws IOException {} + @Override + public void serialize(BinaryWriter writer) throws IOException { + writer.writeVarString(peerPubkey); + writer.writeSerializable(address); + writer.writeVarInt(initPos); + writer.writeVarBytes(caller); + writer.writeLong(keyNo); + } +} +class AuthorizeForPeerParam implements Serializable { + public Address address; + public String[] peerPubkeys; + public long[] posList; + public AuthorizeForPeerParam(Address address,String[] peerPubkeys,long[] posList){ + this.address = address; + this.peerPubkeys = peerPubkeys; + this.posList = posList; + } + @Override + public void deserialize(BinaryReader reader) throws IOException{}; + + @Override + public void serialize(BinaryWriter writer) throws IOException { + writer.writeSerializable(address); + writer.writeVarInt(peerPubkeys.length); + for(String peerPubkey: peerPubkeys){ + writer.writeVarString(peerPubkey); + } + writer.writeVarInt(posList.length); + for(long pos: posList){ + writer.writeVarInt(pos); + } + } +} +class WithdrawParam implements Serializable { + public Address address; + public String[] peerPubkeys; + public long[] withdrawList; + public WithdrawParam(Address address,String[] peerPubkeys,long[] withdrawList){ + this.address = address; + this.peerPubkeys = peerPubkeys; + this.withdrawList = withdrawList; + } + @Override + public void deserialize(BinaryReader reader) throws IOException{ + }; + + @Override + public void serialize(BinaryWriter writer) throws IOException { + writer.writeSerializable(address); + writer.writeVarInt(peerPubkeys.length); + for(String peerPubkey : peerPubkeys){ + writer.writeVarString(peerPubkey); + } + writer.writeVarInt(withdrawList.length); + for(long withdraw : withdrawList){ + writer.writeVarInt(withdraw); + } + } +} +class QuitNodeParam implements Serializable { + public String peerPubkey; + public Address address; + public QuitNodeParam(String peerPubkey,Address address){ + this.peerPubkey = peerPubkey; + this.address = address; + } + @Override + public void deserialize(BinaryReader reader) throws IOException {} + @Override + public void serialize(BinaryWriter writer) throws IOException { + writer.writeVarString(peerPubkey); + writer.writeSerializable(address); + } +} +class BlackNodeParam implements Serializable { + public String peerPubkey; + public BlackNodeParam(String peerPubkey){ + this.peerPubkey = peerPubkey; + } + @Override + public void deserialize(BinaryReader reader) throws IOException {} + @Override + public void serialize(BinaryWriter writer) throws IOException { + writer.writeVarString(peerPubkey); + } +} +class WhiteNodeParam implements Serializable { + public String peerPubkey; + public WhiteNodeParam(String peerPubkey){ + this.peerPubkey = peerPubkey; + } + @Override + public void deserialize(BinaryReader reader) throws IOException {} + @Override + public void serialize(BinaryWriter writer) throws IOException { + writer.writeVarString(peerPubkey); + } +} +class AuthorizeCommitDposParam implements Serializable { + public String address; + public long pos; + public AuthorizeCommitDposParam(String address,long pos){ + this.pos = pos; + this.address = address; + } + @Override + public void deserialize(BinaryReader reader) throws IOException {} + @Override + public void serialize(BinaryWriter writer) throws IOException { + writer.writeVarString(address); + writer.writeVarString(String.valueOf(pos)); + } +} +//class Configuration implements Serializable { +// public long N = 7; +// public long C = 2; +// public long K = 7; +// public long L = 112; +// public long blockMsgDelay = 10000; +// public long hashMsgDelay = 10000; +// public long peerHandshakeTimeout = 10; +// public long maxBlockChangeView = 1000; +// @Override +// public void deserialize(BinaryReader reader) throws IOException {} +// @Override +// public void serialize(BinaryWriter writer) throws IOException { +// writer.writeVarInt(N); +// writer.writeVarInt(C); +// writer.writeVarInt(K); +// writer.writeVarInt(L); +// writer.writeVarInt(blockMsgDelay); +// writer.writeVarInt(hashMsgDelay); +// writer.writeVarInt(peerHandshakeTimeout); +// writer.writeVarInt(maxBlockChangeView); +// } +//} +class GovernanceGlobalParam implements Serializable { + public long candidateFee; + public long minInitStake; + public long candidateNum; + public long A; + public long B; + public long Yita; + GovernanceGlobalParam(long candidateFee,long minInitStake,long candidateNum,long A,long B,long Yita){ + this.candidateFee = candidateFee; + this.minInitStake = minInitStake; + this.candidateNum = candidateNum; + this.A = A; + this.B = B; + this.Yita = Yita; + } + + @Override + public void deserialize(BinaryReader reader) throws IOException { + + } + + @Override + public void serialize(BinaryWriter writer) throws IOException { + writer.writeVarInt(candidateFee); + writer.writeVarInt(minInitStake); + writer.writeVarInt(candidateNum); + writer.writeVarInt(A); + writer.writeVarInt(B); + writer.writeVarInt(Yita); + } +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/nativevm/abi/AbiEvent.java b/src/main/java/com/github/DNAProject/smartcontract/nativevm/abi/AbiEvent.java new file mode 100644 index 0000000..9a29d46 --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/nativevm/abi/AbiEvent.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.smartcontract.nativevm.abi; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.sdk.exception.SDKException; + +import java.util.List; + +/** + * smartcode abi event + */ +public class AbiEvent { + public String name; + public String returntype; + public List parameters; + + public String getName() { + return name; + } + + public List getParameters() { + return parameters; + } + public void setParamsValue(Object... objs) throws Exception{ + if(objs.length != parameters.size()){ + throw new SDKException(ErrorCode.ParamError); + } + for (int i = 0; i < objs.length; i++) { + parameters.get(i).setValue(objs[i]); + } + } + public Parameter getParameter(String name) { + for (Parameter e : parameters) { + if (e.getName().equals(name)) { + return e; + } + } + return null; + } + public void clearParamsValue() { + for (Parameter e : parameters) { + e.setValue(null); + } + } + @Override + public String toString() { + return JSON.toJSONString(this); + } +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/nativevm/abi/AbiFunction.java b/src/main/java/com/github/DNAProject/smartcontract/nativevm/abi/AbiFunction.java new file mode 100644 index 0000000..1b3c5f8 --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/nativevm/abi/AbiFunction.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.smartcontract.nativevm.abi; + + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.sdk.exception.SDKException; + +import java.util.List; + +/** + * smartcode abi function + */ +public class AbiFunction { + public String name; + public String returntype; + public List parameters; + + public String getName() { + return name; + } + + public List getParameters() { + return parameters; + } + public void setParamsValue(Object... objs) throws Exception{ + if(objs.length != parameters.size()){ + throw new SDKException(ErrorCode.ParamError); + } + for (int i = 0; i < objs.length; i++) { + parameters.get(i).setValue(objs[i]); + } + } + public Parameter getParameter(String name) { + for (Parameter e : parameters) { + if (e.getName().equals(name)) { + return e; + } + } + return null; + } + public void clearParamsValue() { + for (Parameter e : parameters) { + e.setValue(null); + } + } + @Override + public String toString() { + return JSON.toJSONString(this); + } +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/nativevm/abi/AbiInfo.java b/src/main/java/com/github/DNAProject/smartcontract/nativevm/abi/AbiInfo.java new file mode 100644 index 0000000..52e28c3 --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/nativevm/abi/AbiInfo.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.smartcontract.nativevm.abi; + +import com.alibaba.fastjson.JSON; + +import java.util.List; + +/** + * smartcode abi information + */ +public class AbiInfo { + public String hash; + public String entrypoint; + public List functions; + public List events; + + public String getHash() { + return hash; + } + public void setHash(String hash) { + this.hash = hash; + } + + public String getEntrypoint() { + return entrypoint; + } + public void setEntrypoint(String entrypoint) { + this.entrypoint = entrypoint; + } + + public List getFunctions() { + return functions; + } + public void getFunctions(List functions) { + this.functions = functions; + } + + public List getEvents() { + return events; + } + public void getEvents(List events) { + this.events = events; + } + public AbiFunction getFunction(String name) { + for (AbiFunction e : functions) { + if (e.getName().equals(name)) { + return e; + } + } + return null; + } + public AbiEvent getEvent(String name) { + for (AbiEvent e : events) { + if (e.getName().equals(name)) { + return e; + } + } + return null; + } + public void clearFunctionsParamsValue() { + for (AbiFunction e : functions) { + e.clearParamsValue(); + } + } + public void clearEventsParamsValue() { + for (AbiEvent e : events) { + e.clearParamsValue(); + } + } + public void removeFunctionParamsValue(String name) { + for (AbiFunction e : functions) { + if (e.getName().equals(name)) { + e.clearParamsValue(); + } + } + } + public void removeEventParamsValue(String name) { + for (AbiEvent e : events) { + if (e.getName().equals(name)) { + e.clearParamsValue(); + } + } + } + @Override + public String toString() { + return JSON.toJSONString(this); + } +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/nativevm/abi/NativeBuildParams.java b/src/main/java/com/github/DNAProject/smartcontract/nativevm/abi/NativeBuildParams.java new file mode 100644 index 0000000..bd51961 --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/nativevm/abi/NativeBuildParams.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.smartcontract.nativevm.abi; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.common.*; +import com.github.DNAProject.core.dnaid.Attribute; +import com.github.DNAProject.core.scripts.ScriptBuilder; +import com.github.DNAProject.core.scripts.ScriptOp; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.sdk.exception.SDKException; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.lang.reflect.Array; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +public class NativeBuildParams { + public static byte[] buildParams(Object ...params) throws SDKException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + BinaryWriter bw = new BinaryWriter(baos); + try { + for (Object param : params) { + if(param instanceof Integer){ + bw.writeInt(((Integer) param).intValue()); + }else if(param instanceof byte[]){ + bw.writeVarBytes((byte[])param); + }else if(param instanceof String){ + bw.writeVarString((String) param); + }else if(param instanceof Attribute[]){ + bw.writeSerializableArray((Attribute[])param); + }else if(param instanceof Attribute){ + bw.writeSerializable((Attribute)param); + }else if(param instanceof Address){ + bw.writeSerializable((Address)param); + }else { + throw new SDKException(ErrorCode.WriteVarBytesError); + } + } + } catch (IOException e) { + throw new SDKException(ErrorCode.WriteVarBytesError); + } + return baos.toByteArray(); + } + + private static byte[] createCodeParamsScript(ScriptBuilder builder, List list) { + try { + for (int i = list.size() - 1; i >= 0; i--) { + Object val = list.get(i); + if (val instanceof byte[]) { + builder.emitPushByteArray((byte[]) val); + } else if (val instanceof Boolean) { + builder.emitPushBool((Boolean) val); + } else if (val instanceof Integer) { + builder.emitPushInteger(BigInteger.valueOf((int) val)); + } else if (val instanceof Long) { + builder.emitPushInteger(BigInteger.valueOf((Long) val)); + } else if (val instanceof Address) { + builder.emitPushByteArray(((Address) val).toArray()); + } else if(val instanceof UInt256){ + builder.emitPushByteArray(((UInt256)val).toArray()); + } else if (val instanceof String) { + builder.emitPushByteArray(((String) val).getBytes()); + } else if (val instanceof Struct) { + builder.emitPushInteger(BigInteger.valueOf(0)); + builder.add(ScriptOp.OP_NEWSTRUCT); + builder.add(ScriptOp.OP_TOALTSTACK); + for (int k = 0; k < ((Struct) val).list.size(); k++) { + Object o = ((Struct) val).list.get(k); + List tmpList = new ArrayList(); + tmpList.add(o); + createCodeParamsScript(builder, tmpList); + builder.add(ScriptOp.OP_DUPFROMALTSTACK); + builder.add(ScriptOp.OP_SWAP); + builder.add(ScriptOp.OP_APPEND); + } + builder.add(ScriptOp.OP_FROMALTSTACK); + } else if (val instanceof List) { + List tmp = (List) val; + for (int k = tmp.size() - 1; k >= 0; k--) { + List tmpList = new ArrayList(); + tmpList.add(tmp.get(k)); + createCodeParamsScript(builder,tmpList ); + } + builder.emitPushInteger(new BigInteger(String.valueOf(tmp.size()))); + builder.pushPack(); + } else { + throw new SDKException(ErrorCode.OtherError("not this type")); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return builder.toArray(); + } + /** + * @param list + * @return + */ + public static byte[] createCodeParamsScript(List list) { + ScriptBuilder sb = new ScriptBuilder(); + return createCodeParamsScript(sb,list); + } + public static byte[] serializeAbiFunction( AbiFunction abiFunction) throws Exception { + List list = new ArrayList(); + list.add(abiFunction.getName().getBytes()); + List tmp = new ArrayList(); + for (Parameter obj : abiFunction.getParameters()) { + if ("Byte".equals(obj.getType())) { + tmp.add(JSON.parseObject(obj.getValue(), byte.class)); + } else if ("ByteArray".equals(obj.getType())) { + tmp.add(JSON.parseObject(obj.getValue(), byte[].class)); + } else if ("String".equals(obj.getType())) { + tmp.add(obj.getValue()); + } else if ("Bool".equals(obj.getType())) { + tmp.add(JSON.parseObject(obj.getValue(), boolean.class)); + } else if ("Int".equals(obj.getType())) { + tmp.add(JSON.parseObject(obj.getValue(), Long.class)); + } else if ("Array".equals(obj.getType())) { + tmp.add(JSON.parseObject(obj.getValue(), Array.class)); + } else if ("Struct".equals(obj.getType())) { + //tmp.add(JSON.parseObject(obj.getValue(), Object.class)); + } else if ("Uint256".equals(obj.getType())) { + + } else if ("Address".equals(obj.getType())) { + + } else { + throw new SDKException(ErrorCode.TypeError); + } + } + if(list.size()>0) { + list.add(tmp); + } + byte[] params = createCodeParamsScript(list); + return params; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/smartcontract/nativevm/abi/Parameter.java b/src/main/java/com/github/DNAProject/smartcontract/nativevm/abi/Parameter.java new file mode 100644 index 0000000..7011d2d --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/nativevm/abi/Parameter.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.smartcontract.nativevm.abi; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.sdk.exception.SDKException; + +import java.util.List; + +/** + * + */ +public class Parameter { + public String name; + public String type; + public SubType[] subType; + public String value; + + public String getName() { + return name; + } + + public String getType() { + return type; + } + + public String getValue() { + return value; + } + public SubType[] getSubType() { + return subType; + } + + public boolean setValue(Object value) { + try { + if(value == null) { + this.value = null; + }else if ("Byte".equals(type)) { + byte tmp = (byte) value; + this.value = JSON.toJSONString(tmp); + } else if ("ByteArray".equals(type)) { + byte[] tmp = (byte[]) value; + this.value = JSON.toJSONString(tmp); + } else if ("String".equals(type)) { + this.value = (String) value; + } else if ("Bool".equals(type)) { + boolean tmp = (boolean) value; + this.value = JSON.toJSONString(tmp); + } else if ("Int".equals(type)) { + long tmp = (long)value; + this.value = JSON.toJSONString(tmp); + } else if ("Array".equals(type)) { + List tmp = (List) value; + this.value = JSON.toJSONString(tmp); + } else if ("Uint256".equals(type)) { + } else if ("Address".equals(type)) { + } else if ("Struct".equals(type)) { + Struct tmp = (Struct) value; + for(int i=0;i. + * + */ + +package com.github.DNAProject.smartcontract.nativevm.abi; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.sdk.exception.SDKException; + +import java.util.List; + +public class SubType { + public List parameters; + + public List getParameters() { + return parameters; + } + public void setParamsValue(Object... objs) throws Exception{ + if(objs.length != parameters.size()){ + throw new SDKException(ErrorCode.ParamError); + } + for (int i = 0; i < objs.length; i++) { + parameters.get(i).setValue(objs[i]); + } + } + public Parameter getParameter(String name) { + for (Parameter e : parameters) { + if (e.getName().equals(name)) { + return e; + } + } + return null; + } + public void clearParamsValue() { + for (Parameter e : parameters) { + e.setValue(null); + } + } + @Override + public String toString() { + return JSON.toJSONString(this); + } +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/neovm/ClaimRecord.java b/src/main/java/com/github/DNAProject/smartcontract/neovm/ClaimRecord.java new file mode 100644 index 0000000..25f13a9 --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/neovm/ClaimRecord.java @@ -0,0 +1,224 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.smartcontract.neovm; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Common; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; +import com.github.DNAProject.sdk.exception.SDKException; +import com.github.DNAProject.smartcontract.neovm.abi.AbiFunction; +import com.github.DNAProject.smartcontract.neovm.abi.AbiInfo; +import com.github.DNAProject.smartcontract.neovm.abi.BuildParams; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +public class ClaimRecord { + private DnaSdk sdk; + private String contractAddress = "36bb5c053b6b839c8f6b923fe852f91239b9fccc"; + + private String abi = "{\"hash\":\"0x36bb5c053b6b839c8f6b923fe852f91239b9fccc\",\"entrypoint\":\"Main\",\"functions\":[{\"name\":\"Main\",\"parameters\":[{\"name\":\"operation\",\"type\":\"String\"},{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"Any\"},{\"name\":\"Commit\",\"parameters\":[{\"name\":\"claimId\",\"type\":\"ByteArray\"},{\"name\":\"commiterId\",\"type\":\"ByteArray\"},{\"name\":\"ownerId\",\"type\":\"ByteArray\"}],\"returntype\":\"Boolean\"},{\"name\":\"Revoke\",\"parameters\":[{\"name\":\"claimId\",\"type\":\"ByteArray\"},{\"name\":\"dnaId\",\"type\":\"ByteArray\"}],\"returntype\":\"Boolean\"},{\"name\":\"GetStatus\",\"parameters\":[{\"name\":\"claimId\",\"type\":\"ByteArray\"}],\"returntype\":\"ByteArray\"}],\"events\":[{\"name\":\"ErrorMsg\",\"parameters\":[{\"name\":\"id\",\"type\":\"ByteArray\"},{\"name\":\"error\",\"type\":\"String\"}],\"returntype\":\"Void\"},{\"name\":\"Push\",\"parameters\":[{\"name\":\"id\",\"type\":\"ByteArray\"},{\"name\":\"msg\",\"type\":\"String\"},{\"name\":\"args\",\"type\":\"ByteArray\"}],\"returntype\":\"Void\"}]}"; + + public ClaimRecord(DnaSdk sdk) { + this.sdk = sdk; + } + + public void setContractAddress(String codeHash) { + this.contractAddress = codeHash.replace("0x", ""); + } + + public String getContractAddress() { + return contractAddress; + } + + /** + * + * @param issuerDnaid + * @param password + * @param subjectDnaid + * @param claimId + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public String sendCommit(String issuerDnaid, String password, byte[] salt, String subjectDnaid, String claimId, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if(issuerDnaid==null||issuerDnaid.equals("")||password==null||password.equals("")||subjectDnaid==null||subjectDnaid.equals("") + || claimId==null||claimId.equals("")||payerAcct == null){ + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if(gaslimit < 0 || gasprice < 0){ + throw new SDKException(ErrorCode.ParamErr("gaslimit or gasprice is less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + Transaction tx = makeCommit(issuerDnaid,subjectDnaid,claimId,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + sdk.signTx(tx, issuerDnaid, password,salt); + sdk.addSign(tx,payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + + /** + * + * @param issuerDnaid + * @param subjectDnaid + * @param claimId + * @param payer + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public Transaction makeCommit(String issuerDnaid, String subjectDnaid, String claimId,String payer, long gaslimit, long gasprice) throws Exception { + if(issuerDnaid==null||issuerDnaid.equals("")||subjectDnaid==null||subjectDnaid.equals("")||payer==null||payer.equals("") + || claimId==null||claimId.equals("")){ + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if(gaslimit < 0 || gasprice < 0){ + throw new SDKException(ErrorCode.ParamErr("gaslimit or gasprice is less than 0")); + } + + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + String name = "Commit"; + AbiFunction func = abiinfo.getFunction(name); + func.name = name; + func.setParamsValue(claimId.getBytes(),issuerDnaid.getBytes(),subjectDnaid.getBytes()); + byte[] params = BuildParams.serializeAbiFunction(func); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress), null, params, payer,gaslimit, gasprice); + return tx; + } + + /** + * + * @param issuerDnaid + * @param password + * @param claimId + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public String sendRevoke(String issuerDnaid,String password,byte[] salt, String claimId,Account payerAcct,long gaslimit,long gasprice) throws Exception { + if(issuerDnaid==null||issuerDnaid.equals("")||password==null||password.equals("") + || claimId==null||claimId.equals("")||payerAcct == null){ + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if(gaslimit < 0 || gasprice < 0){ + throw new SDKException(ErrorCode.ParamErr("gaslimit or gasprice is less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + String addr = issuerDnaid.replace(Common.diddna,""); + Transaction tx = makeRevoke(issuerDnaid,claimId,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + sdk.signTx(tx, addr, password,salt); + sdk.addSign(tx,payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + + public Transaction makeRevoke(String issuerDnaid,String claimId,String payer,long gaslimit,long gasprice) throws Exception { + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + String name = "Revoke"; + AbiFunction func = abiinfo.getFunction(name); + func.name = name; + func.setParamsValue(claimId.getBytes(),issuerDnaid.getBytes()); + byte[] params = BuildParams.serializeAbiFunction(func); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress), null, params, payer,gaslimit, gasprice); + return tx; + } + public String sendGetStatus(String claimId) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + if (claimId == null || claimId == ""){ + throw new SDKException(ErrorCode.NullKeyOrValue); + } + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + String name = "GetStatus"; + AbiFunction func = abiinfo.getFunction(name); + func.name = name; + func.setParamsValue(claimId.getBytes()); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + String res = ((JSONObject)obj).getString("Result"); + if(res.equals("")){ + return ""; + } + ByteArrayInputStream bais = new ByteArrayInputStream(Helper.hexToBytes(res)); + BinaryReader br = new BinaryReader(bais); + ClaimTx claimTx = new ClaimTx(); + claimTx.deserialize(br); + if(claimTx.status.length == 0){ + return new String(claimTx.claimId)+"."+"00"+"."+new String(claimTx.issuerDnaId)+"."+new String(claimTx.subjectDnaId); + } + return new String(claimTx.claimId)+"."+Helper.toHexString(claimTx.status)+"."+new String(claimTx.issuerDnaId)+"."+new String(claimTx.subjectDnaId); + } +} + +class ClaimTx implements Serializable { + public byte[] claimId; + public byte[] issuerDnaId; + public byte[] subjectDnaId; + public byte[] status; + ClaimTx(){} + ClaimTx(byte[] claimId,byte[] issuerDnaId,byte[] subjectDnaId,byte[] status){ + this.claimId = claimId; + this.issuerDnaId = issuerDnaId; + this.subjectDnaId = subjectDnaId; + this.status = status; + } + + @Override + public void deserialize(BinaryReader reader) throws IOException { + byte dataType = reader.readByte(); + long length = reader.readVarInt(); + byte dataType2 = reader.readByte(); + this.claimId = reader.readVarBytes(); + byte dataType3 = reader.readByte(); + this.issuerDnaId = reader.readVarBytes(); + byte dataType4 = reader.readByte(); + this.subjectDnaId = reader.readVarBytes(); + byte dataType5 = reader.readByte(); + this.status = reader.readVarBytes(); + } + + @Override + public void serialize(BinaryWriter writer) throws IOException { + + } +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/neovm/Nep5.java b/src/main/java/com/github/DNAProject/smartcontract/neovm/Nep5.java new file mode 100644 index 0000000..e645d73 --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/neovm/Nep5.java @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.smartcontract.neovm; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.smartcontract.neovm.abi.AbiFunction; +import com.github.DNAProject.smartcontract.neovm.abi.AbiInfo; +import com.github.DNAProject.sdk.exception.SDKException; +import com.github.DNAProject.smartcontract.neovm.abi.BuildParams; + +import java.math.BigInteger; + + +/** + * + */ +public class Nep5 { + private DnaSdk sdk; + private String contractAddress = null; + private String nep5abi = "{\"hash\":\"0xd17d91a831c094c1fd8d8634b8cd6fa9fbaedc99\",\"entrypoint\":\"Main\"," + + "\"functions\":[{\"name\":\"Name\",\"parameters\":[],\"returntype\":\"String\"}," + + "{\"name\":\"Symbol\",\"parameters\":[],\"returntype\":\"String\"}," + + "{\"name\":\"Decimals\",\"parameters\":[],\"returntype\":\"Integer\"},{\"name\":\"Main\",\"parameters\":[{\"name\":\"operation\",\"type\":\"String\"}," + + "{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"Any\"}," + + "{\"name\":\"Init\",\"parameters\":[],\"returntype\":\"Boolean\"}," + + "{\"name\":\"TotalSupply\",\"parameters\":[],\"returntype\":\"Integer\"}," + + "{\"name\":\"Transfer\",\"parameters\":[{\"name\":\"from\",\"type\":\"ByteArray\"},{\"name\":\"to\",\"type\":\"ByteArray\"},{\"name\":\"value\",\"type\":\"Integer\"}],\"returntype\":\"Boolean\"}," + + "{\"name\":\"BalanceOf\",\"parameters\":[{\"name\":\"address\",\"type\":\"ByteArray\"}],\"returntype\":\"Integer\"}]," + + "\"events\":[{\"name\":\"transfer\",\"parameters\":[{\"name\":\"arg1\",\"type\":\"ByteArray\"},{\"name\":\"arg2\",\"type\":\"ByteArray\"},{\"name\":\"arg3\",\"type\":\"Integer\"}],\"returntype\":\"Void\"}]}"; + + public Nep5(DnaSdk sdk) { + this.sdk = sdk; + } + + public void setContractAddress(String codeHash) { + this.contractAddress = codeHash.replace("0x", ""); + } + + public String getContractAddress() { + return contractAddress; + } + + public String sendInit(Account acct, Account payerAcct,long gaslimit,long gasprice) throws Exception { + return (String)sendInit(acct,payerAcct,gaslimit,gasprice,false); + } + + public long sendInitPreExec(Account acct, Account payerAcct,long gaslimit,long gasprice) throws Exception { + return (long)sendInit(acct,payerAcct,gaslimit,gasprice,true); + } + + private Object sendInit(Account acct, Account payerAcct,long gaslimit,long gasprice,boolean preExec) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(nep5abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("Init"); + func.name = "init"; + if(preExec) { + byte[] params = BuildParams.serializeAbiFunction(func); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(getContractAddress(), null, params,null,0, 0); + if (acct != null) { + sdk.signTx(tx, new Account[][]{{acct}}); + } + Object obj = sdk.getConnect().sendRawTransactionPreExec(tx.toHexString()); + if (Integer.parseInt(((JSONObject) obj).getString("Result")) != 1){ + throw new SDKException(ErrorCode.OtherError("sendRawTransaction PreExec error: "+ obj)); + } + return ((JSONObject) obj).getLong("Gas"); + } + if(acct == null || payerAcct == null){ + throw new SDKException(ErrorCode.ParamError); + } + Object obj = sdk.neovm().sendTransaction(contractAddress,acct,payerAcct,gaslimit,gasprice,func,preExec); + return obj; + } + + + /** + * + * @param acct + * @param recvAddr + * @param amount + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public String sendTransfer(Account acct, String recvAddr, long amount,Account payerAcct, long gaslimit,long gasprice) throws Exception { + return (String)sendTransfer(acct, recvAddr, amount,payerAcct,gaslimit,gasprice, false); + } + + public long sendTransferPreExec(Account acct, String recvAddr, long amount) throws Exception { + return (long)sendTransfer(acct, recvAddr, amount,acct,0,0, true); + } + + private Object sendTransfer(Account acct, String recvAddr, long amount, Account payerAcct, long gaslimit, long gasprice, boolean preExec) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + if(acct == null || payerAcct == null){ + throw new SDKException(ErrorCode.ParamError); + } + String sendAddr = acct.getAddressU160().toBase58(); + AbiInfo abiinfo = JSON.parseObject(nep5abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("Transfer"); + func.name = "transfer"; + func.setParamsValue(Address.decodeBase58(sendAddr).toArray(), Address.decodeBase58(recvAddr).toArray(), amount); + if(preExec) { + byte[] params = BuildParams.serializeAbiFunction(func); + + Transaction tx = sdk.vm().makeInvokeCodeTransaction(getContractAddress(), null, params,null,0, 0); + sdk.signTx(tx, new Account[][]{{acct}}); + Object obj = sdk.getConnect().sendRawTransactionPreExec(tx.toHexString()); + if (Integer.parseInt(((JSONObject) obj).getString("Result")) != 1){ + throw new SDKException(ErrorCode.OtherError("sendRawTransaction PreExec error: "+ obj)); + } + return ((JSONObject) obj).getLong("Gas"); + } + Object obj = sdk.neovm().sendTransaction(contractAddress,acct,payerAcct,gaslimit,gasprice,func, preExec); + return obj; + } + public Transaction makeTransfer(String sendAddr,String recvAddr, long amount, Account payerAcct, long gaslimit, long gasprice) throws Exception{ + AbiInfo abiinfo = JSON.parseObject(nep5abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("Transfer"); + func.name = "transfer"; + func.setParamsValue(Address.decodeBase58(sendAddr).toArray(), Address.decodeBase58(recvAddr).toArray(), amount); + byte[] params = BuildParams.serializeAbiFunction(func); + String payer = payerAcct.getAddressU160().toBase58(); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(getContractAddress(), null, params, payer,gaslimit, gasprice); + return tx; + } + + public String queryBalanceOf(String addr) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(nep5abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("BalanceOf"); + func.name = "balanceOf"; + func.setParamsValue(Address.decodeBase58(addr).toArray()); + Object obj = sdk.neovm().sendTransaction(contractAddress,null,null,0,0,func, true); + String balance = ((JSONObject) obj).getString("Result"); + if(balance == null || balance.equals("")){ + return BigInteger.ZERO.toString(); + } + return Helper.BigIntFromNeoBytes(Helper.hexToBytes(balance)).toString(); + } + + public String queryTotalSupply() throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(nep5abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("TotalSupply"); + func.name = "totalSupply"; + func.setParamsValue(); + Object obj = sdk.neovm().sendTransaction(contractAddress,null,null,0,0,func, true); + String total = ((JSONObject) obj).getString("Result"); + return Helper.BigIntFromNeoBytes(Helper.hexToBytes(total)).toString(); + } + + public String queryName() throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(nep5abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("Name"); + func.name = "name"; + func.setParamsValue(); + Object obj = sdk.neovm().sendTransaction(contractAddress,null,null,0,0,func, true); + return new String(Helper.hexToBytes(((JSONObject) obj).getString("Result"))); + } + + public String queryDecimals() throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(nep5abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("Decimals"); + func.name = "decimals"; + func.setParamsValue(); + Object obj = sdk.neovm().sendTransaction(contractAddress,null,null,0,0,func, true); + String decimal = ((JSONObject) obj).getString("Result"); + return Helper.BigIntFromNeoBytes(Helper.hexToBytes(decimal)).toString(); + } + + public String querySymbol() throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(nep5abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("Symbol"); + func.name = "symbol"; + func.setParamsValue(); + Object obj = sdk.neovm().sendTransaction(contractAddress,null,null,0,0,func, true); + return new String(Helper.hexToBytes(((JSONObject) obj).getString("Result"))); + } + + +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/neovm/Oep4.java b/src/main/java/com/github/DNAProject/smartcontract/neovm/Oep4.java new file mode 100644 index 0000000..f9dfb09 --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/neovm/Oep4.java @@ -0,0 +1,385 @@ +package com.github.DNAProject.smartcontract.neovm; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.asset.State; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.sdk.exception.SDKException; +import com.github.DNAProject.smartcontract.neovm.abi.AbiFunction; +import com.github.DNAProject.smartcontract.neovm.abi.AbiInfo; +import com.github.DNAProject.smartcontract.neovm.abi.BuildParams; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +public class Oep4 { + private DnaSdk sdk; + private String contractAddress = null; + private String oep4abi = "{\"hash\":\"0xcf409996f7abbf8afd659a298c26cd1239e0c19e\",\"entrypoint\":\"Main\",\"functions\":[" + + "{\"name\":\"Name\",\"parameters\":[],\"returntype\":\"String\"}," + + "{\"name\":\"Symbol\",\"parameters\":[],\"returntype\":\"String\"}," + + "{\"name\":\"Decimals\",\"parameters\":[],\"returntype\":\"Integer\"}," + + "{\"name\":\"Main\",\"parameters\":[{\"name\":\"operation\",\"type\":\"String\"},{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"Any\"}," + + "{\"name\":\"Init\",\"parameters\":[],\"returntype\":\"Boolean\"}," + + "{\"name\":\"Transfer\",\"parameters\":[{\"name\":\"from\",\"type\":\"ByteArray\"},{\"name\":\"to\",\"type\":\"ByteArray\"},{\"name\":\"value\",\"type\":\"Integer\"}],\"returntype\":\"Boolean\"}," + + "{\"name\":\"TransferMulti\",\"parameters\":[{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"Boolean\"}," + + "{\"name\":\"BalanceOf\",\"parameters\":[{\"name\":\"address\",\"type\":\"ByteArray\"}],\"returntype\":\"Integer\"}," + + "{\"name\":\"TotalSupply\",\"parameters\":[],\"returntype\":\"Integer\"}," + + "{\"name\":\"Approve\",\"parameters\":[{\"name\":\"owner\",\"type\":\"ByteArray\"},{\"name\":\"spender\",\"type\":\"ByteArray\"},{\"name\":\"amount\",\"type\":\"Integer\"}],\"returntype\":\"Boolean\"}," + + "{\"name\":\"TransferFrom\",\"parameters\":[{\"name\":\"spender\",\"type\":\"ByteArray\"},{\"name\":\"from\",\"type\":\"ByteArray\"},{\"name\":\"to\",\"type\":\"ByteArray\"},{\"name\":\"amount\",\"type\":\"Integer\"}],\"returntype\":\"Boolean\"}," + + "{\"name\":\"Allowance\",\"parameters\":[{\"name\":\"owner\",\"type\":\"ByteArray\"},{\"name\":\"spender\",\"type\":\"ByteArray\"}],\"returntype\":\"Integer\"}]," + + "\"events\":[{\"name\":\"transfer\",\"parameters\":[{\"name\":\"from\",\"type\":\"ByteArray\"},{\"name\":\"to\",\"type\":\"ByteArray\"},{\"name\":\"value\",\"type\":\"Integer\"}],\"returntype\":\"Void\"}," + + "{\"name\":\"approval\",\"parameters\":[{\"name\":\"onwer\",\"type\":\"ByteArray\"},{\"name\":\"spender\",\"type\":\"ByteArray\"},{\"name\":\"value\",\"type\":\"Integer\"}],\"returntype\":\"Void\"}]}"; + + public Oep4(DnaSdk sdk) { + this.sdk = sdk; + } + + public void setContractAddress(String codeHash) { + this.contractAddress = codeHash.replace("0x", ""); + } + + public String getContractAddress() { + return contractAddress; + } + + public String sendInit(Account acct, Account payerAcct,long gaslimit,long gasprice) throws Exception { + return (String)sendInit(acct,payerAcct,gaslimit,gasprice,false); + } + + public long sendInitPreExec(Account acct, Account payerAcct,long gaslimit,long gasprice) throws Exception { + return (long)sendInit(acct,payerAcct,gaslimit,gasprice,true); + } + + private Object sendInit(Account acct, Account payerAcct,long gaslimit,long gasprice,boolean preExec) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(oep4abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("Init"); + func.name = "init"; + if(preExec) { + byte[] params = BuildParams.serializeAbiFunction(func); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress), null, params,null,0, 0); + if (acct != null) { + sdk.signTx(tx, new Account[][]{{acct}}); + } + Object obj = sdk.getConnect().sendRawTransactionPreExec(tx.toHexString()); + if (Integer.parseInt(((JSONObject) obj).getString("State")) != 1){ + throw new SDKException(ErrorCode.OtherError("sendRawTransaction PreExec error: "+ obj)); + } + return ((JSONObject) obj).getLong("Gas"); + } + if(acct == null || payerAcct == null){ + throw new SDKException(ErrorCode.ParamError); + } + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),acct,payerAcct,gaslimit,gasprice,func,preExec); + return obj; + } + + public String sendTransfer(Account acct, String recvAddr, long amount,Account payerAcct, long gaslimit,long gasprice) throws Exception { + return (String)sendTransfer(acct, recvAddr, amount,payerAcct,gaslimit,gasprice, false); + } + public String sendTransfer(Account acct, String recvAddr, BigInteger amount,Account payerAcct, long gaslimit,long gasprice) throws Exception { + return (String)sendTransfer(acct, recvAddr, amount,payerAcct,gaslimit,gasprice, false); + } + public long sendTransferPreExec(Account acct, String recvAddr, long amount) throws Exception { + return (long)sendTransfer(acct, recvAddr, amount,acct,0,0, true); + } + public Object sendTransfer(Account acct, String recvAddr, BigInteger amount, Account payerAcct, long gaslimit, long gasprice, boolean preExec) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + if(acct == null || payerAcct == null || gaslimit < 0 || gasprice < 0){ + throw new SDKException(ErrorCode.ParamError); + } + String sendAddr = acct.getAddressU160().toBase58(); + List paramList = new ArrayList<>(); + paramList.add("transfer".getBytes()); + List args = new ArrayList(); + args.add(Address.decodeBase58(sendAddr).toArray()); + args.add( Address.decodeBase58(recvAddr).toArray()); + args.add(Helper.BigIntToNeoBytes(amount)); + paramList.add(args); + byte[] params = BuildParams.createCodeParamsScript(paramList); + if(preExec) { + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress), null, params,null,0, 0); + sdk.signTx(tx, new Account[][]{{acct}}); + Object obj = sdk.getConnect().sendRawTransactionPreExec(tx.toHexString()); + if (Integer.parseInt(((JSONObject) obj).getString("Result")) != 1){ + throw new SDKException(ErrorCode.OtherError("sendRawTransaction PreExec error: "+ obj)); + } + return ((JSONObject) obj).getLong("Gas"); + } + String payer = payerAcct.getAddressU160().toBase58(); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress), null, params, payer,gaslimit, gasprice); + sdk.signTx(tx, new Account[][]{{acct}}); + if(!acct.getAddressU160().toBase58().equals(payerAcct.getAddressU160().toBase58())){ + sdk.addSign(tx,payerAcct); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (!b) { + throw new SDKException(ErrorCode.SendRawTxError); + } + return tx.hash().toHexString(); + } + private Object sendTransfer(Account acct, String recvAddr, long amount, Account payerAcct, long gaslimit, long gasprice, boolean preExec) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + if(acct == null || payerAcct == null || gaslimit < 0 || gasprice < 0){ + throw new SDKException(ErrorCode.ParamError); + } + String sendAddr = acct.getAddressU160().toBase58(); + AbiInfo abiinfo = JSON.parseObject(oep4abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("Transfer"); + func.name = "transfer"; + func.setParamsValue(Address.decodeBase58(sendAddr).toArray(), Address.decodeBase58(recvAddr).toArray(), amount); + if(preExec) { + byte[] params = BuildParams.serializeAbiFunction(func); + + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress), null, params,null,0, 0); + sdk.signTx(tx, new Account[][]{{acct}}); + Object obj = sdk.getConnect().sendRawTransactionPreExec(tx.toHexString()); + if (Integer.parseInt(((JSONObject) obj).getString("Result")) != 1){ + throw new SDKException(ErrorCode.OtherError("sendRawTransaction PreExec error: "+ obj)); + } + return ((JSONObject) obj).getLong("Gas"); + } + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),acct,payerAcct,gaslimit,gasprice,func, preExec); + return obj; + } + public Transaction makeTransfer(String sendAddr,String recvAddr, long amount, Account payerAcct, long gaslimit, long gasprice) throws Exception{ + if(sendAddr==null||sendAddr.equals("")||recvAddr == null || recvAddr.equals("")|| amount <=0 || payerAcct==null ||gaslimit < 0 || gasprice<0){ + throw new SDKException(ErrorCode.ParamError); + } + AbiInfo abiinfo = JSON.parseObject(oep4abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("Transfer"); + func.name = "transfer"; + func.setParamsValue(Address.decodeBase58(sendAddr).toArray(), Address.decodeBase58(recvAddr).toArray(), amount); + byte[] params = BuildParams.serializeAbiFunction(func); + String payer = payerAcct.getAddressU160().toBase58(); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress), null, params, payer,gaslimit, gasprice); + return tx; + } + public Transaction makeTransfer(String sendAddr,String recvAddr, long amount, String payer, long gaslimit, long gasprice) throws Exception{ + if(sendAddr==null||sendAddr.equals("")||recvAddr == null || recvAddr.equals("")|| amount <=0 || payer == null || payer.equals("") ||gaslimit < 0 || gasprice<0){ + throw new SDKException(ErrorCode.ParamError); + } + AbiInfo abiinfo = JSON.parseObject(oep4abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("Transfer"); + func.name = "transfer"; + func.setParamsValue(Address.decodeBase58(sendAddr).toArray(), Address.decodeBase58(recvAddr).toArray(), amount); + byte[] params = BuildParams.serializeAbiFunction(func); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress), null, params, payer,gaslimit, gasprice); + return tx; + } + public String sendTransferMulti(Account[] accounts, State[] states,Account payerAcct,long gaslimit, long gasprice) throws Exception { + if(accounts == null || states == null || payerAcct == null){ + throw new SDKException("params should not be null"); + } + if(gaslimit < 0 || gasprice< 0){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + Transaction tx = makeTransferMulti(states,payerAcct,gaslimit,gasprice); + boolean haspayer = false; + for(Account account : accounts){ + if(account.equals(payerAcct)){ + haspayer = true; + } + sdk.addSign(tx, account); + } + if(!haspayer){ + sdk.addSign(tx, payerAcct); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (!b) { + throw new SDKException(ErrorCode.SendRawTxError); + } + return tx.hash().toHexString(); + } + public Transaction makeTransferMulti(State[] states,Account payerAcct,long gaslimit, long gasprice) throws SDKException { + if(states == null || payerAcct == null){ + throw new SDKException("params should not be null"); + } + if(gaslimit < 0 || gasprice< 0){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + List paramList = new ArrayList<>(); + paramList.add("transferMulti".getBytes()); + List tempList = new ArrayList(); + for(State state : states){ + List list = new ArrayList(); + list.add(state.from.toArray()); + list.add(state.to.toArray()); + list.add(state.value); + tempList.add(list); + } + paramList.add(tempList); + byte[] params = BuildParams.createCodeParamsScript(paramList); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress),null,params,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + return tx; + } + + public String sendApprove(Account owner, String spender, long amount,Account payerAcct, long gaslimit,long gasprice) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + if(owner == null || payerAcct == null || gaslimit<0 || gasprice<0){ + throw new SDKException(ErrorCode.ParamError); + } + AbiInfo abiinfo = JSON.parseObject(oep4abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("Approve"); + func.name = "approve"; + func.setParamsValue(owner.getAddressU160().toArray(), Address.decodeBase58(spender).toArray(), amount); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),owner,payerAcct,gaslimit,gasprice,func, false); + return (String) obj; + } + + public Transaction makeApprove(String owner,String spender, long amount, Account payerAcct, long gaslimit, long gasprice) throws Exception{ + if(owner==null||owner.equals("")||spender == null || spender.equals("")|| amount <=0 || payerAcct==null ||gaslimit < 0 || gasprice<0){ + throw new SDKException(ErrorCode.ParamError); + } + AbiInfo abiinfo = JSON.parseObject(oep4abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("Approve"); + func.name = "approve"; + func.setParamsValue(Address.decodeBase58(owner).toArray(), Address.decodeBase58(spender).toArray(), amount); + byte[] params = BuildParams.serializeAbiFunction(func); + String payer = payerAcct.getAddressU160().toBase58(); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress), null, params, payer,gaslimit, gasprice); + return tx; + } + + + public String sendTransferFrom(Account sender, String from,String to, long amount, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + if(sender == null || payerAcct == null || gaslimit<0 || gasprice <0){ + throw new SDKException(ErrorCode.ParamError); + } + AbiInfo abiinfo = JSON.parseObject(oep4abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("TransferFrom"); + func.name = "transferFrom"; + func.setParamsValue(sender.getAddressU160().toArray(), Address.decodeBase58(from).toArray(),Address.decodeBase58(to).toArray(), amount); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),sender,payerAcct,gaslimit,gasprice,func, false); + return (String) obj; + } + + public Transaction makeTransferFrom(String sender, String from,String to, long amount, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if(sender==null||sender.equals("")||from == null || from.equals("")||to== null || to.equals("")|| amount <=0 || payerAcct==null ||gaslimit < 0 + || gasprice<0){ + throw new SDKException(ErrorCode.ParamError); + } + AbiInfo abiinfo = JSON.parseObject(oep4abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("TransferFrom"); + func.name = "transferFrom"; + func.setParamsValue(Address.decodeBase58(sender).toArray(), Address.decodeBase58(from).toArray(),Address.decodeBase58(to).toArray(), amount); + byte[] params = BuildParams.serializeAbiFunction(func); + String payer = payerAcct.getAddressU160().toBase58(); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress), null, params, payer,gaslimit, gasprice); + return tx; + } + + public String queryAllowance(String owner, String spender) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + if(owner == null||owner.equals("")||spender==null||spender.equals("")){ + throw new SDKException(ErrorCode.ParamError); + } + AbiInfo abiinfo = JSON.parseObject(oep4abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("Allowance"); + func.name = "allowance"; + func.setParamsValue(Address.decodeBase58(owner).toArray(), Address.decodeBase58(spender).toArray()); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + String balance = ((JSONObject) obj).getString("Result"); + if(balance == null || balance.equals("")){ + return BigInteger.ZERO.toString(); + } + return Helper.BigIntFromNeoBytes(Helper.hexToBytes(balance)).toString(); + } + + public String queryBalanceOf(String addr) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + if(addr == null||addr.equals("")){ + throw new SDKException(ErrorCode.ParamError); + } + AbiInfo abiinfo = JSON.parseObject(oep4abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("BalanceOf"); + func.name = "balanceOf"; + func.setParamsValue(Address.decodeBase58(addr).toArray()); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + String balance = ((JSONObject) obj).getString("Result"); + if(balance == null || balance.equals("")){ + return BigInteger.ZERO.toString(); + } + return Helper.BigIntFromNeoBytes(Helper.hexToBytes(balance)).toString(); + } + + public String queryTotalSupply() throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(oep4abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("TotalSupply"); + func.name = "totalSupply"; + func.setParamsValue(); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + String total = ((JSONObject) obj).getString("Result"); + if(total.equals("")){ + return BigInteger.ZERO.toString(); + } + return Helper.BigIntFromNeoBytes(Helper.hexToBytes(total)).toString(); + } + + public String queryName() throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(oep4abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("Name"); + func.name = "name"; + func.setParamsValue(); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + return new String(Helper.hexToBytes(((JSONObject) obj).getString("Result"))); + } + + public String queryDecimals() throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(oep4abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("Decimals"); + func.name = "decimals"; + func.setParamsValue(); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + String decimals = ((JSONObject) obj).getString("Result"); + if(decimals.equals("")){ + return BigInteger.ZERO.toString(); + } + return Helper.BigIntFromNeoBytes(Helper.hexToBytes(decimals)).toString(); + } + + public String querySymbol() throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(oep4abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("Symbol"); + func.name = "symbol"; + func.setParamsValue(); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + return new String(Helper.hexToBytes(((JSONObject) obj).getString("Result"))); + } + + +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/neovm/Oep5.java b/src/main/java/com/github/DNAProject/smartcontract/neovm/Oep5.java new file mode 100644 index 0000000..8e01153 --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/neovm/Oep5.java @@ -0,0 +1,276 @@ +package com.github.DNAProject.smartcontract.neovm; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.sdk.exception.SDKException; +import com.github.DNAProject.smartcontract.neovm.abi.AbiFunction; +import com.github.DNAProject.smartcontract.neovm.abi.AbiInfo; +import com.github.DNAProject.smartcontract.neovm.abi.BuildParams; +import com.github.DNAProject.smartcontract.neovm.oep5.Oep5Param; + +import java.util.ArrayList; +import java.util.List; + +public class Oep5 { + private DnaSdk sdk; + private String contractAddress = null; + private String oep5abi = "{\"functions\":[{\"name\":\"Main\",\"parameters\":[{\"name\":\"operation\",\"type\":\"\"},{\"name\":\"args\",\"type\":\"\"}],\"returntype\":\"\"}," + + "{\"name\":\"name\",\"parameters\":[],\"returntype\":\"\"}," + + "{\"name\":\"symbol\",\"parameters\":[],\"returntype\":\"\"}," + + "{\"name\":\"balanceOf\",\"parameters\":[{\"name\":\"owner\",\"type\":\"ByteArray\"}],\"returntype\":\"\"}," + + "{\"name\":\"ownerOf\",\"parameters\":[{\"name\":\"tokenID\",\"type\":\"ByteArray\"}],\"returntype\":\"\"}," + + "{\"name\":\"transfer\",\"parameters\":[{\"name\":\"toAcct\",\"type\":\"ByteArray\"},{\"name\":\"tokenID\",\"type\":\"ByteArray\"}],\"returntype\":\"\"}," + + "{\"name\":\"transferMulti\",\"parameters\":[{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"\"}," + + "{\"name\":\"approve\",\"parameters\":[{\"name\":\"toAcct\",\"type\":\"ByteArray\"},{\"name\":\"tokenID\",\"type\":\"ByteArray\"}],\"returntype\":\"\"}," + + "{\"name\":\"takeOwnership\",\"parameters\":[{\"name\":\"toAcct\",\"type\":\"ByteArray\"},{\"name\":\"tokenID\",\"type\":\"ByteArray\"}],\"returntype\":\"\"}," + + "{\"name\":\"concatkey\",\"parameters\":[{\"name\":\"str1\",\"type\":\"\"},{\"name\":\"str2\",\"type\":\"\"}],\"returntype\":\"\"}," + + "{\"name\":\"init\",\"parameters\":[],\"returntype\":\"\"}," + + "{\"name\":\"totalSupply\",\"parameters\":[],\"returntype\":\"\"}," + + "{\"name\":\"queryTokenIDByIndex\",\"parameters\":[{\"name\":\"idx\",\"type\":\"Integer\"}],\"returntype\":\"\"}," + + "{\"name\":\"queryTokenByID\",\"parameters\":[{\"name\":\"tokenID\",\"type\":\"ByteArray\"}],\"returntype\":\"\"}," + + "{\"name\":\"getApproved\",\"parameters\":[{\"name\":\"tokenID\",\"type\":\"ByteArray\"}],\"returntype\":\"\"}," + + "{\"name\":\"createMultiTokens\",\"parameters\":[],\"returntype\":\"\"}," + + "{\"name\":\"createOneToken\",\"parameters\":[{\"name\":\"name\",\"type\":\"\"},{\"name\":\"url\",\"type\":\"\"},{\"name\":\"type\",\"type\":\"\"}],\"returntype\":\"\"}]}"; + + public Oep5(DnaSdk sdk){ + this.sdk = sdk; + } + public void setContractAddress(String codeHash) { + this.contractAddress = codeHash.replace("0x", ""); + } + + public String getContractAddress() { + return contractAddress; + } + + public String sendInit(Account acct, Account payerAcct, long gaslimit, long gasprice) throws Exception { + return (String)sendInit(acct,payerAcct,gaslimit,gasprice,false); + } + private Object sendInit(Account acct, Account payerAcct,long gaslimit,long gasprice,boolean preExec) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(oep5abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("init"); + if(preExec) { + byte[] params = BuildParams.serializeAbiFunction(func); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress), null, params,null,gaslimit, gasprice); + if (acct != null) { + sdk.signTx(tx, new Account[][]{{acct}}); + } + Object obj = sdk.getConnect().sendRawTransactionPreExec(tx.toHexString()); + if (Integer.parseInt(((JSONObject) obj).getString("Result")) != 1){ + throw new SDKException(ErrorCode.OtherError("sendRawTransaction PreExec error: "+ obj)); + } + return ((JSONObject) obj).getLong("Gas"); + } + if(acct == null || payerAcct == null){ + throw new SDKException(ErrorCode.ParamError); + } + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),acct,payerAcct,gaslimit,gasprice,func,preExec); + return obj; + } + + public String ownerOf(byte[] tokenID) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(oep5abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("ownerOf"); + func.name = "ownerOf"; + func.setParamsValue(tokenID); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + return ((JSONObject) obj).getString("Result"); + } + + public String transfer(Account owner, Oep5Param oep5Transfer, Account payer, long gaslimit, long gasprice) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(oep5abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("transfer"); + func.name = "transfer"; + func.setParamsValue(oep5Transfer.toAcct, oep5Transfer.tokenId); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),owner,payer,gaslimit,gasprice,func, false); + return (String) obj; + } + public String transferMulti(Account[] owners, Oep5Param[] oep5Transfers, Account payer, long gaslimit, long gasprice) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + Transaction tx = makeTransferMulti(oep5Transfers, payer, gaslimit, gasprice); + boolean haspayer = false; + for(Account account : owners){ + if(account.equals(payer)){ + haspayer = true; + } + sdk.addSign(tx, account); + } + if(!haspayer){ + sdk.addSign(tx, payer); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (!b) { + throw new SDKException(ErrorCode.SendRawTxError); + } + return tx.hash().toHexString(); + } + + public Transaction makeTransferMulti(Oep5Param[] oep5Transfers, Account payerAcct, long gaslimit, long gasprice) throws SDKException { + if(oep5Transfers == null || payerAcct == null){ + throw new SDKException("params should not be null"); + } + if(gaslimit < 0 || gasprice< 0){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + List paramList = new ArrayList<>(); + paramList.add("transferMulti".getBytes()); + List tempList = new ArrayList(); + for(Oep5Param oep5Transfer : oep5Transfers){ + List list = new ArrayList(); + list.add(oep5Transfer.toAcct); + list.add(oep5Transfer.tokenId); + tempList.add(list); + } + paramList.add(tempList); + byte[] params = BuildParams.createCodeParamsScript(paramList); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress),null,params,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + return tx; + } + + public String approve(Account owner, Oep5Param oep5Param, Account payer, long gaslimit, long gasprice) throws Exception { + if (owner == null || oep5Param == null || payer == null) { + throw new SDKException("params should not be null"); + } + if(gaslimit < 0 || gasprice< 0){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + AbiInfo abiinfo = JSON.parseObject(oep5abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("approve"); + func.setParamsValue(oep5Param.toAcct, oep5Param.tokenId); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),owner,payer,gaslimit,gasprice,func, false); + return (String) obj; + } + public String takeOwnership(Account owner, Oep5Param oep5Param, Account payer, long gaslimit, long gasprice) throws Exception { + if (owner == null || oep5Param == null || payer == null) { + throw new SDKException("params should not be null"); + } + if(gaslimit < 0 || gasprice< 0){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + AbiInfo abiinfo = JSON.parseObject(oep5abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("takeOwnership"); + func.setParamsValue(oep5Param.toAcct, oep5Param.tokenId); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),owner,payer,gaslimit,gasprice,func, false); + return (String) obj; + } + + public String queryTotalSupply() throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(oep5abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("totalSupply"); + func.setParamsValue(); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + return Helper.BigIntFromNeoBytes(Helper.hexToBytes(((JSONObject) obj).getString("Result"))).toString(); + } + public String queryTokenIDByIndex(String idx) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(oep5abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("queryTokenIDByIndex"); + func.name = "queryTokenIDByIndex"; + func.setParamsValue(idx); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + return ((JSONObject) obj).getString("Result"); + } + public String queryTokenByID(String tokenID) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(oep5abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("queryTokenByID"); + func.setParamsValue(tokenID); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + return ((JSONObject) obj).getString("Result"); + } + public String getApproved(String tokenID) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(oep5abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("getApproved"); + func.name = "getApproved"; + func.setParamsValue(Helper.hexToBytes(tokenID)); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + return ((JSONObject) obj).getString("Result"); + } + public String queryName() throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(oep5abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("name"); + func.name = "name"; + func.setParamsValue(); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + return new String(Helper.hexToBytes(((JSONObject) obj).getString("Result"))); + } + + public String querySymbol() throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(oep5abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("symbol"); + func.name = "symbol"; + func.setParamsValue(); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + return new String(Helper.hexToBytes(((JSONObject) obj).getString("Result"))); + } + + public String queryBalanceOf(String addr) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + if(addr == null||addr.equals("")){ + throw new SDKException(ErrorCode.ParamError); + } + AbiInfo abiinfo = JSON.parseObject(oep5abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("balanceOf"); + func.name = "balanceOf"; + func.setParamsValue(Address.decodeBase58(addr).toArray()); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + String balance = ((JSONObject) obj).getString("Result"); + if(balance.equals("")){ + balance = "00"; + } + return Helper.BigIntFromNeoBytes(Helper.hexToBytes(balance)).toString(); + } + public String queryTokenIDByIndex(int index) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + if(index < 0){ + throw new SDKException(ErrorCode.ParamError); + } + AbiInfo abiinfo = JSON.parseObject(oep5abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("queryTokenIDByIndex"); + func.setParamsValue((long)index); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + String tokenId = ((JSONObject) obj).getString("Result"); + if(tokenId.equals("")){ + tokenId = "00"; + } + return tokenId; + } +} + diff --git a/src/main/java/com/github/DNAProject/smartcontract/neovm/Oep8.java b/src/main/java/com/github/DNAProject/smartcontract/neovm/Oep8.java new file mode 100644 index 0000000..2ea0688 --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/neovm/Oep8.java @@ -0,0 +1,472 @@ +package com.github.DNAProject.smartcontract.neovm; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.smartcontract.neovm.oep8.Oep8State; +import com.github.DNAProject.smartcontract.neovm.oep8.TransferFrom; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.sdk.exception.SDKException; +import com.github.DNAProject.smartcontract.neovm.abi.AbiFunction; +import com.github.DNAProject.smartcontract.neovm.abi.AbiInfo; +import com.github.DNAProject.smartcontract.neovm.abi.BuildParams; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +public class Oep8 { + private DnaSdk sdk; + private String contractAddress = null; + private String oep8abi = "{\"contractHash\":\"a2054b2d84a87190ea3a96e122e0710e95da36f3\",\"functions\":[" + + "{\"name\":\"Revert\",\"parameters\":[{\"name\":\"\",\"type\":\"\"}],\"returntype\":\"\"}," + + "{\"name\":\"Require\",\"parameters\":[{\"name\":\"condition\",\"type\":\"\"}],\"returntype\":\"\"}," + + "{\"name\":\"RequireScriptHash\",\"parameters\":[{\"name\":\"key\",\"type\":\"\"}],\"returntype\":\"\"}," + + "{\"name\":\"RequireWitness\",\"parameters\":[{\"name\":\"witness\",\"type\":\"\"}],\"returntype\":\"\"}," + + "{\"name\":\"Main\",\"parameters\":[{\"name\":\"operation\",\"type\":\"\"},{\"name\":\"args\",\"type\":\"\"}],\"returntype\":\"\"}," + + "{\"name\":\"name\",\"parameters\":[{\"name\":\"tokenId\",\"type\":\"ByteArray\"}],\"returntype\":\"\"}," + + "{\"name\":\"symbol\",\"parameters\":[{\"name\":\"tokenId\",\"type\":\"ByteArray\"}],\"returntype\":\"\"}," + + "{\"name\":\"totalSupply\",\"parameters\":[{\"name\":\"tokenId\",\"type\":\"ByteArray\"}],\"returntype\":\"\"}," + + "{\"name\":\"balanceOf\",\"parameters\":[{\"name\":\"acct\",\"type\":\"ByteArray\"},{\"name\":\"tokenId\",\"type\":\"ByteArray\"}],\"returntype\":\"\"}," + + "{\"name\":\"transfer\",\"parameters\":[{\"name\":\"fromAcct\",\"type\":\"ByteArray\"},{\"name\":\"toAcct\",\"type\":\"ByteArray\"},{\"name\":\"tokenId\",\"type\":\"ByteArray\"},{\"name\":\"amount\",\"type\":\"Integer\"}],\"returntype\":\"\"}," + + "{\"name\":\"transferMulti\",\"parameters\":[{\"name\":\"args\",\"type\":\"\"}],\"returntype\":\"\"}," + + "{\"name\":\"approve\",\"parameters\":[{\"name\":\"owner\",\"type\":\"ByteArray\"},{\"name\":\"spender\",\"type\":\"ByteArray\"},{\"name\":\"tokenId\",\"type\":\"ByteArray\"},{\"name\":\"amount\",\"type\":\"Integer\"}],\"returntype\":\"\"}," + + "{\"name\":\"approveMulti\",\"parameters\":[{\"name\":\"args\",\"type\":\"ByteArray\"}],\"returntype\":\"\"}," + + "{\"name\":\"allowance\",\"parameters\":[{\"name\":\"owner\",\"type\":\"ByteArray\"},{\"name\":\"spender\",\"type\":\"ByteArray\"},{\"name\":\"tokenId\",\"type\":\"ByteArray\"}],\"returntype\":\"\"}," + + "{\"name\":\"transferFrom\",\"parameters\":[{\"name\":\"spender\",\"type\":\"ByteArray\"},{\"name\":\"fromAcct\",\"type\":\"ByteArray\"},{\"name\":\"toAcct\",\"type\":\"ByteArray\"},{\"name\":\"tokenId\",\"type\":\"ByteArray\"},{\"name\":\"amount\",\"type\":\"Integer\"}],\"returntype\":\"\"}," + + "{\"name\":\"transferFromMulti\",\"parameters\":[{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"\"}," + + "{\"name\":\"concatkey\",\"parameters\":[{\"name\":\"str1\",\"type\":\"\"},{\"name\":\"str2\",\"type\":\"\"}],\"returntype\":\"\"}," + + "{\"name\":\"init\",\"parameters\":[],\"returntype\":\"\"}," + + "{\"name\":\"mint\",\"parameters\":[{\"name\":\"tokenId\",\"type\":\"ByteArray\"},{\"name\":\"tokenAmount\",\"type\":\"Integer\"}],\"returntype\":\"\"}," + + "{\"name\":\"createMultiTypeToken\",\"parameters\":[{\"name\":\"\",\"type\":\"Array\"}],\"returntype\":\"\"}," + + "{\"name\":\"totalBalanceOf\",\"parameters\":[{\"name\":\"account\",\"type\":\"ByteArray\"}],\"returntype\":\"\"}," + + "{\"name\":\"balancesOf\",\"parameters\":[{\"name\":\"account\",\"type\":\"ByteArray\"}],\"returntype\":\"\"}," + + "{\"name\":\"compound\",\"parameters\":[{\"name\":\"acct\",\"type\":\"ByteArray\"},{\"name\":\"compoundOneOrAll\",\"type\":\"Integer\"}],\"returntype\":\"\"}," + + "{\"name\":\"checkTokenId\",\"parameters\":[{\"name\":\"tokenId\",\"type\":\"ByteArray\"}],\"returntype\":\"\"}]}"; + public Oep8(DnaSdk sdk) { + this.sdk = sdk; + } + + public void setContractAddress(String codeHash) { + this.contractAddress = codeHash.replace("0x", ""); + } + + public String getContractAddress() { + return contractAddress; + } + + public String sendInit(Account acct, Account payerAcct, long gaslimit, long gasprice) throws Exception { + return (String)sendInit(acct,payerAcct,gaslimit,gasprice,false); + } + + public long sendInitPreExec(Account acct, Account payerAcct,long gaslimit,long gasprice) throws Exception { + return (long)sendInit(acct,payerAcct,gaslimit,gasprice,true); + } + + private Object sendInit(Account acct, Account payerAcct,long gaslimit,long gasprice,boolean preExec) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(oep8abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("init"); + if(preExec) { + byte[] params = BuildParams.serializeAbiFunction(func); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(getContractAddress(), null, params,null,0, 0); + if (acct != null) { + sdk.signTx(tx, new Account[][]{{acct}}); + } + Object obj = sdk.getConnect().sendRawTransactionPreExec(tx.toHexString()); + if (Integer.parseInt(((JSONObject) obj).getString("Result")) != 1){ + throw new SDKException(ErrorCode.OtherError("sendRawTransaction PreExec error: "+ obj)); + } + return ((JSONObject) obj).getLong("Gas"); + } + if(acct == null || payerAcct == null){ + throw new SDKException(ErrorCode.ParamError); + } + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),acct,payerAcct,gaslimit,gasprice,func,preExec); + return obj; + } + + public String sendTransfer(Account acct, String recvAddr, byte[] tokenId, long amount,Account payerAcct, long gaslimit,long gasprice) throws Exception { + return (String)sendTransfer(acct, recvAddr, tokenId, amount,payerAcct,gaslimit,gasprice, false); + } + + public long sendTransferPreExec(Account acct, String recvAddr, byte[] tokenId, long amount) throws Exception { + return (long)sendTransfer(acct, recvAddr, tokenId, amount,acct,0,0, true); + } + + private Object sendTransfer(Account acct, String recvAddr,byte[] tokenId, long amount, Account payerAcct, long gaslimit, long gasprice, boolean preExec) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + if(acct == null || payerAcct == null || gaslimit < 0 || gasprice < 0){ + throw new SDKException(ErrorCode.ParamError); + } + String sendAddr = acct.getAddressU160().toBase58(); + AbiInfo abiinfo = JSON.parseObject(oep8abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("transfer"); + func.setParamsValue(Address.decodeBase58(sendAddr).toArray(), Address.decodeBase58(recvAddr).toArray(), tokenId, amount); + if(preExec) { + byte[] params = BuildParams.serializeAbiFunction(func); + + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress), null, params,null,0, 0); + sdk.signTx(tx, new Account[][]{{acct}}); + Object obj = sdk.getConnect().sendRawTransactionPreExec(tx.toHexString()); + if (Integer.parseInt(((JSONObject) obj).getString("Result")) != 1){ + throw new SDKException(ErrorCode.OtherError("sendRawTransaction PreExec error: "+ obj)); + } + return ((JSONObject) obj).getLong("Gas"); + } + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),acct,payerAcct,gaslimit,gasprice,func, preExec); + return obj; + } + public Transaction makeTransfer(String sendAddr,String recvAddr, byte[] tokenId, long amount, Account payerAcct, long gaslimit, long gasprice) throws Exception{ + if(sendAddr==null||sendAddr.equals("")||recvAddr == null || recvAddr.equals("")|| amount <=0 || payerAcct==null ||gaslimit < 0 || gasprice<0){ + throw new SDKException(ErrorCode.ParamError); + } + AbiInfo abiinfo = JSON.parseObject(oep8abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("transfer"); + func.setParamsValue(Address.decodeBase58(sendAddr).toArray(), Address.decodeBase58(recvAddr).toArray(), tokenId, amount); + byte[] params = BuildParams.serializeAbiFunction(func); + String payer = payerAcct.getAddressU160().toBase58(); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress), null, params, payer,gaslimit, gasprice); + return tx; + } + + public String sendTransferMulti(Account[] accounts, Oep8State[] states, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if(accounts == null || states == null || payerAcct == null){ + throw new SDKException("params should not be null"); + } + if(gaslimit < 0 || gasprice< 0){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + Transaction tx = makeTransferMulti(states,payerAcct,gaslimit,gasprice); + boolean haspayer = false; + for(Account account : accounts){ + if(account.equals(payerAcct)){ + haspayer = true; + } + sdk.addSign(tx, account); + } + if(!haspayer){ + sdk.addSign(tx, payerAcct); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (!b) { + throw new SDKException(ErrorCode.SendRawTxError); + } + return tx.hash().toHexString(); + } + public Transaction makeTransferMulti(Oep8State[] states,Account payerAcct,long gaslimit, long gasprice) throws Exception { + if(states == null || payerAcct == null){ + throw new SDKException("params should not be null"); + } + if(gaslimit < 0 || gasprice< 0){ + throw new SDKException("gaslimit or gasprice should not be less than 0"); + } + List paramList = new ArrayList<>(); + paramList.add("transferMulti".getBytes()); + List tempList = new ArrayList(); + for(Oep8State state : states){ + List list = new ArrayList(); + list.add(state.from); + list.add(state.to); + list.add(state.tokenId); + list.add(state.value); + tempList.add(list); + } + paramList.add(tempList); + byte[] params = BuildParams.createCodeParamsScript(paramList); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress),null,params,payerAcct.getAddressU160().toBase58(),gaslimit,gasprice); + return tx; + } + + public String sendApprove(Account owner, String spender, byte[] tokenId, long amount,Account payerAcct, long gaslimit,long gasprice) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + if(owner == null || payerAcct == null || gaslimit<0 || gasprice<0){ + throw new SDKException(ErrorCode.ParamError); + } + AbiInfo abiinfo = JSON.parseObject(oep8abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("approve"); + func.setParamsValue(owner.getAddressU160().toArray(), Address.decodeBase58(spender).toArray(), tokenId, amount); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),owner,payerAcct,gaslimit,gasprice,func, false); + return (String) obj; + } + + public Transaction makeApprove(String owner,String spender, byte[] tokenId,long amount, Account payerAcct, long gaslimit, long gasprice) throws Exception{ + if(owner==null||owner.equals("")||spender == null || spender.equals("")|| amount <=0 || payerAcct==null ||gaslimit < 0 || gasprice<0){ + throw new SDKException(ErrorCode.ParamError); + } + AbiInfo abiinfo = JSON.parseObject(oep8abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("approve"); + func.setParamsValue(Address.decodeBase58(owner).toArray(), Address.decodeBase58(spender).toArray(), tokenId, amount); + byte[] params = BuildParams.serializeAbiFunction(func); + String payer = payerAcct.getAddressU160().toBase58(); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress), null, params, payer,gaslimit, gasprice); + return tx; + } + + public String sendApproveMulti(Account[] owner, Oep8State[] states,Account payerAcct, long gaslimit,long gasprice) throws Exception { + if(owner==null||owner.equals("")||states == null || payerAcct==null ||gaslimit < 0 || gasprice<0){ + throw new SDKException(ErrorCode.ParamError); + } + Transaction tx = makeApproveMulti(states, payerAcct.getAddressU160().toBase58(), gaslimit, gasprice); + boolean haspayer = false; + for(Account account : owner){ + if(account.equals(payerAcct)){ + haspayer = true; + } + sdk.addSign(tx, account); + } + if(!haspayer){ + sdk.addSign(tx, payerAcct); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (!b) { + throw new SDKException(ErrorCode.SendRawTxError); + } + return tx.hash().toHexString(); + } + + public Transaction makeApproveMulti(Oep8State[] states, String payerAcct, long gaslimit, long gasprice) throws Exception{ + if(states==null|| payerAcct==null ||gaslimit < 0 || gasprice<0){ + throw new SDKException(ErrorCode.ParamError); + } + List paramList = new ArrayList<>(); + paramList.add("approveMulti".getBytes()); + List tempList = new ArrayList(); + for(Oep8State state : states){ + List list = new ArrayList(); + list.add(state.from); + list.add(state.to); + list.add(state.tokenId); + list.add(state.value); + tempList.add(list); + } + paramList.add(tempList); + byte[] params = BuildParams.createCodeParamsScript(paramList); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress), null, params, payerAcct,gaslimit, gasprice); + return tx; + } + + public String sendTransferFromMulti(Account[] sender, TransferFrom[] states, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + if(sender == null || payerAcct == null || gaslimit<0 || gasprice <0){ + throw new SDKException(ErrorCode.ParamError); + } + Transaction tx = makeTransferFromMulti(states, payerAcct.getAddressU160().toBase58(), gaslimit, gasprice); + boolean haspayer = false; + for(Account account : sender){ + if(account.equals(payerAcct)){ + haspayer = true; + } + sdk.addSign(tx, account); + } + if(!haspayer){ + sdk.addSign(tx, payerAcct); + } + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (!b) { + throw new SDKException(ErrorCode.SendRawTxError); + } + return tx.hash().toHexString(); + } + + public Transaction makeTransferFromMulti(TransferFrom[] states, String payerAcct, long gaslimit, long gasprice) throws Exception { + if(states==null|| payerAcct==null ||gaslimit < 0 + || gasprice<0){ + throw new SDKException(ErrorCode.ParamError); + } + List paramList = new ArrayList<>(); + paramList.add("transferFromMulti".getBytes()); + List tempList = new ArrayList(); + for(TransferFrom state : states){ + List list = new ArrayList(); + list.add(state.spender); + list.add(state.from); + list.add(state.to); + list.add(state.tokenId); + list.add(state.value); + tempList.add(list); + } + paramList.add(tempList); + byte[] params = BuildParams.createCodeParamsScript(paramList); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress), null, params, payerAcct,gaslimit, gasprice); + return tx; + } + + public String sendTransferFrom(Account sender, String from,String to, byte[] tokenId, long amount, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + if(sender == null || payerAcct == null || gaslimit<0 || gasprice <0){ + throw new SDKException(ErrorCode.ParamError); + } + AbiInfo abiinfo = JSON.parseObject(oep8abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("transferFrom"); + func.name = "transferFrom"; + func.setParamsValue(sender.getAddressU160().toArray(), Address.decodeBase58(from).toArray(),Address.decodeBase58(to).toArray(), tokenId, amount); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),sender,payerAcct,gaslimit,gasprice,func, false); + return (String) obj; + } + + public Transaction makeTransferFrom(String sender, String from,String to, byte[] tokenId, long amount, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if(sender==null||sender.equals("")||from == null || from.equals("")||to== null || to.equals("")|| amount <=0 || payerAcct==null ||gaslimit < 0 + || gasprice<0){ + throw new SDKException(ErrorCode.ParamError); + } + AbiInfo abiinfo = JSON.parseObject(oep8abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("transferFrom"); + func.name = "transferFrom"; + func.setParamsValue(Address.decodeBase58(sender).toArray(), Address.decodeBase58(from).toArray(),Address.decodeBase58(to).toArray(), tokenId, amount); + byte[] params = BuildParams.serializeAbiFunction(func); + String payer = payerAcct.getAddressU160().toBase58(); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress), null, params, payer,gaslimit, gasprice); + return tx; + } + + public String sendCompound(Account account,long compoundOneOrAll, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + if(account == null || payerAcct == null || gaslimit<0 || gasprice <0){ + throw new SDKException(ErrorCode.ParamError); + } + AbiInfo abiinfo = JSON.parseObject(oep8abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("compound"); + func.setParamsValue(account.getAddressU160().toArray(), compoundOneOrAll); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),account,payerAcct,gaslimit,gasprice,func, false); + return (String) obj; + } + + public String queryAllowance(String owner, String spender, byte[] tokenId) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + if(owner == null||owner.equals("")||spender==null||spender.equals("")){ + throw new SDKException(ErrorCode.ParamError); + } + AbiInfo abiinfo = JSON.parseObject(oep8abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("allowance"); + func.name = "allowance"; + func.setParamsValue(Address.decodeBase58(owner).toArray(), Address.decodeBase58(spender).toArray(), tokenId); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + String balance = ((JSONObject) obj).getString("Result"); + if(balance == null || balance.equals("")){ + return BigInteger.ZERO.toString(); + } + return Helper.BigIntFromNeoBytes(Helper.hexToBytes(balance)).toString(); + } + + public String queryBalanceOf(String addr, byte[] tokenId) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + if(addr == null||addr.equals("")){ + throw new SDKException(ErrorCode.ParamError); + } + AbiInfo abiinfo = JSON.parseObject(oep8abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("balanceOf"); + func.name = "balanceOf"; + func.setParamsValue(Address.decodeBase58(addr).toArray(), tokenId); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + String balance = ((JSONObject) obj).getString("Result"); + if(balance.equals("")){ + balance = BigInteger.ZERO.toString(); + } + return Helper.BigIntFromNeoBytes(Helper.hexToBytes(balance)).toString(); + } + + public String queryTotalSupply(byte[] tokenId) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(oep8abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("totalSupply"); + func.name = "totalSupply"; + func.setParamsValue(tokenId); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + String total = ((JSONObject) obj).getString("Result"); + if(total.equals("")){ + return BigInteger.ZERO.toString(); + } + return Helper.BigIntFromNeoBytes(Helper.hexToBytes(total)).toString(); + } + + public String queryName(byte[] tokenId) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(oep8abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("name"); + func.setParamsValue(tokenId); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + return new String(Helper.hexToBytes(((JSONObject) obj).getString("Result"))); + } + + + public String querySymbol(byte[] tokenId) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(oep8abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("symbol"); + func.name = "symbol"; + func.setParamsValue(tokenId); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + return new String(Helper.hexToBytes(((JSONObject) obj).getString("Result"))); + } + public String balancesOf(String address) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(oep8abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("balancesOf"); + func.setParamsValue(Address.decodeBase58(address).toArray()); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + JSONArray res = ((JSONObject) obj).getJSONArray("Result"); + List resList = new ArrayList(); + for(Object i : res){ + if(!((String)i).equals("")){ + resList.add(Helper.BigIntFromNeoBytes(Helper.hexToBytes((String)i)).toString()); + }else{ + resList.add(BigInteger.ZERO.toString()); + } + } + return JSON.toJSONString(resList); + } + public String totalBalanceOf(String address) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + AbiInfo abiinfo = JSON.parseObject(oep8abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("totalBalanceOf"); + func.setParamsValue(Address.decodeBase58(address).toArray()); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),null,null,0,0,func, true); + String totalBalance = ((JSONObject)obj).getString("Result"); + return Helper.BigIntFromNeoBytes(Helper.hexToBytes(totalBalance)).toString(); + } + public String mint(Account adminAccount,byte[] tokenId, long amount, Account payer, long gaslimit, long gasprice) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + if(adminAccount == null || payer == null || gaslimit<0 || gasprice <0){ + throw new SDKException(ErrorCode.ParamError); + } + AbiInfo abiinfo = JSON.parseObject(oep8abi, AbiInfo.class); + AbiFunction func = abiinfo.getFunction("mint"); + func.setParamsValue(tokenId, amount); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress),adminAccount,payer,gaslimit,gasprice,func, false); + return (String) obj; + } +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/neovm/Record.java b/src/main/java/com/github/DNAProject/smartcontract/neovm/Record.java new file mode 100644 index 0000000..85f98b1 --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/neovm/Record.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.smartcontract.neovm; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.common.Common; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.crypto.KeyType; +import com.github.DNAProject.sdk.exception.SDKException; +import com.github.DNAProject.sdk.info.AccountInfo; +import com.github.DNAProject.smartcontract.neovm.abi.BuildParams; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; + +public class Record { + private DnaSdk sdk; + private String contractAddress = null; + + + public Record(DnaSdk sdk) { + this.sdk = sdk; + } + + public void setContractAddress(String codeHash) { + this.contractAddress = codeHash.replace("0x", ""); + } + + public String getContractAddress() { + return contractAddress; + } + + + public String sendPut(String addr,String password,byte[] salt, String key,String value,long gaslimit,long gas) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + if (key == null || value == null || key == "" || value == ""){ + throw new SDKException(ErrorCode.NullKeyOrValue); + } + addr = addr.replace(Common.diddna,""); + byte[] did = (Common.diddna + addr).getBytes(); + AccountInfo info = sdk.getWalletMgr().getAccountInfo(Common.diddna + addr, password,salt); + byte[] pk = Helper.hexToBytes(info.pubkey); + List list = new ArrayList(); + list.add("Put".getBytes()); + List tmp = new ArrayList(); + tmp.add(key.getBytes()); + tmp.add(JSON.toJSONString(constructRecord(value)).getBytes()); + list.add(tmp); + Transaction tx = makeInvokeTransaction(list,info.addressBase58,gaslimit,gas); + sdk.signTx(tx, addr, password,salt); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + public String sendGet(String addr,String password,byte[] salt, String key) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + if (key == null || key == ""){ + throw new SDKException(ErrorCode.NullKey); + } + byte[] did = (Common.diddna + addr).getBytes(); + AccountInfo info = sdk.getWalletMgr().getAccountInfo(addr, password,salt); + byte[] pk = Helper.hexToBytes(info.pubkey); + List list = new ArrayList(); + list.add("Get".getBytes()); + List tmp = new ArrayList(); + tmp.add(key.getBytes()); + list.add(tmp); + Transaction tx = makeInvokeTransaction(list,null,0,0); + sdk.signTx(tx, addr, password,salt); + Object obj = sdk.getConnect().sendRawTransactionPreExec(tx.toHexString()); + return new String(Helper.hexToBytes((String)obj)); + } + + public Transaction makeInvokeTransaction(List list,String payer,long gaslimit,long gas) throws Exception { + byte[] params = BuildParams.createCodeParamsScript(list); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(contractAddress,null,params, payer,gaslimit,gas); + return tx; + } + + public LinkedHashMap constructRecord(String text) { + LinkedHashMap recordData = new LinkedHashMap(); + LinkedHashMap data = new LinkedHashMap(); + data.put("Algrithem", KeyType.SM2.name()); + data.put("Hash", ""); + data.put("Text", text); + data.put("Signature", ""); + + recordData.put("Data", data); + recordData.put("CAkey", ""); + recordData.put("SeqNo", ""); + recordData.put("Timestamp", 0); + return recordData; + } +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/neovm/abi/AbiEvent.java b/src/main/java/com/github/DNAProject/smartcontract/neovm/abi/AbiEvent.java new file mode 100644 index 0000000..dfb1e23 --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/neovm/abi/AbiEvent.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.smartcontract.neovm.abi; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.sdk.exception.SDKException; +import java.util.List; + +/** + * smartcode abi event + */ +public class AbiEvent { + public String name; + public String returntype; + public List parameters; + + public String getName() { + return name; + } + + public List getParameters() { + return parameters; + } + public void setParamsValue(Object... objs) throws Exception{ + if(objs.length != parameters.size()){ + throw new SDKException(ErrorCode.ParamError); + } + for (int i = 0; i < objs.length; i++) { + parameters.get(i).setValue(objs[i]); + } + } + public Parameter getParameter(String name) { + for (Parameter e : parameters) { + if (e.getName().equals(name)) { + return e; + } + } + return null; + } + public void clearParamsValue() { + for (Parameter e : parameters) { + e.setValue(null); + } + } + @Override + public String toString() { + return JSON.toJSONString(this); + } +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/neovm/abi/AbiFunction.java b/src/main/java/com/github/DNAProject/smartcontract/neovm/abi/AbiFunction.java new file mode 100644 index 0000000..23b504d --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/neovm/abi/AbiFunction.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.smartcontract.neovm.abi; + + +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.sdk.exception.SDKException; +import com.alibaba.fastjson.JSON; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * smartcode abi function + */ +public class AbiFunction { + public String name; + public String returntype; + public List parameters = new ArrayList<>(); + + public AbiFunction() { + } + + public AbiFunction(String name, Parameter... parameters) { + this.name = name; + this.returntype = "String"; + this.parameters = Arrays.asList(parameters); + } + + public String getName() { + return name; + } + + public List getParameters() { + return parameters; + } + + public void setParamsValue(Object... objs) throws Exception{ + if(objs.length != parameters.size()){ + throw new SDKException(ErrorCode.ParamError); + } + for (int i = 0; i < objs.length; i++) { + parameters.get(i).setValue(objs[i]); + } + } + public Parameter getParameter(String name) { + for (Parameter e : parameters) { + if (e.getName().equals(name)) { + return e; + } + } + return null; + } + public void clearParamsValue() { + for (Parameter e : parameters) { + e.setValue(null); + } + } + @Override + public String toString() { + return JSON.toJSONString(this); + } +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/neovm/abi/AbiInfo.java b/src/main/java/com/github/DNAProject/smartcontract/neovm/abi/AbiInfo.java new file mode 100644 index 0000000..e42260e --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/neovm/abi/AbiInfo.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.smartcontract.neovm.abi; + +import com.alibaba.fastjson.JSON; +import java.util.List; + +/** + * smartcode abi information + */ +public class AbiInfo { + public String hash; + public String entrypoint; + public List functions; + public List events; + + public String getHash() { + return hash; + } + public void setHash(String hash) { + this.hash = hash; + } + + public String getEntrypoint() { + return entrypoint; + } + public void setEntrypoint(String entrypoint) { + this.entrypoint = entrypoint; + } + + public List getFunctions() { + return functions; + } + public void getFunctions(List functions) { + this.functions = functions; + } + + public List getEvents() { + return events; + } + public void getEvents(List events) { + this.events = events; + } + public AbiFunction getFunction(String name) { + for (AbiFunction e : functions) { + if (e.getName().equals(name)) { + return e; + } + } + return null; + } + public AbiEvent getEvent(String name) { + for (AbiEvent e : events) { + if (e.getName().equals(name)) { + return e; + } + } + return null; + } + public void clearFunctionsParamsValue() { + for (AbiFunction e : functions) { + e.clearParamsValue(); + } + } + public void clearEventsParamsValue() { + for (AbiEvent e : events) { + e.clearParamsValue(); + } + } + public void removeFunctionParamsValue(String name) { + for (AbiFunction e : functions) { + if (e.getName().equals(name)) { + e.clearParamsValue(); + } + } + } + public void removeEventParamsValue(String name) { + for (AbiEvent e : events) { + if (e.getName().equals(name)) { + e.clearParamsValue(); + } + } + } + @Override + public String toString() { + return JSON.toJSONString(this); + } +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/neovm/abi/BuildParams.java b/src/main/java/com/github/DNAProject/smartcontract/neovm/abi/BuildParams.java new file mode 100644 index 0000000..fb644e6 --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/neovm/abi/BuildParams.java @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.smartcontract.neovm.abi; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.common.Address; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.scripts.ScriptBuilder; +import com.github.DNAProject.core.scripts.ScriptOp; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.sdk.exception.SDKException; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; +import java.util.*; + +public class BuildParams { + public enum Type { + ByteArrayType(0x00), + BooleanType(0x01), + IntegerType(0x02), + InterfaceType(0x40), + ArrayType(0x80), + StructType(0x81), + MapType(0x82); + private byte type; + + private Type(int t) { + this.type = (byte)t; + } + public byte getValue(){ + return type; + } + } + /** + * @param builder + * @param list + * @return + */ + private static byte[] createCodeParamsScript(ScriptBuilder builder, List list) { + try { + for (int i = list.size() - 1; i >= 0; i--) { + Object val = list.get(i); + if (val instanceof byte[]) { + builder.emitPushByteArray((byte[]) val); + } else if (val instanceof Address) { + builder.emitPushByteArray(((Address) val).toArray()); + } else if (val instanceof String) { + builder.emitPushByteArray(((String) val).getBytes()); + } else if (val instanceof Boolean) { + builder.emitPushBool((Boolean) val); + } else if(val instanceof Integer){ + builder.emitPushByteArray(Helper.BigIntToNeoBytes(BigInteger.valueOf((int)val))); + } else if (val instanceof Long) { + builder.emitPushByteArray(Helper.BigIntToNeoBytes(BigInteger.valueOf((long)val))); + } else if(val instanceof Map){ + pushMap(builder,val); +// byte[] bys = getMapBytes(val); +// builder.emitPushByteArray(bys); + } else if(val instanceof Struct){ + pushStruct(builder,val); +// byte[] bys = getStructBytes(val); +// builder.emitPushByteArray(bys); + } else if (val instanceof List) { + List tmp = (List) val; + createCodeParamsScript(builder, tmp); + builder.emitPushInteger(new BigInteger(String.valueOf(tmp.size()))); + builder.pushPack(); + + } else { + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return builder.toArray(); + } + public static Object deserializeItem(byte[] mBytes){ + ByteArrayInputStream ms = new ByteArrayInputStream(mBytes); + BinaryReader reader = new BinaryReader(ms); + return deserializeItem(reader); + } + public static Object deserializeItem(BinaryReader reader){ + try { + byte t = reader.readByte(); + if (t == Type.ByteArrayType.getValue()) { + return reader.readVarBytes(); + }else if (t == Type.BooleanType.getValue()) { + return reader.readBoolean(); + } else if (t == Type.IntegerType.getValue()) { + long v = Helper.BigIntFromNeoBytes(reader.readVarBytes()).longValue(); + return v; + } else if (t == Type.ArrayType.getValue() || t == Type.StructType.getValue()) { + int count = (int)reader.readVarInt(); + List list = new ArrayList(); + for (int i = count; i > 0; i--) { + Object ele = deserializeItem(reader); + if(ele instanceof byte[]){ + ele = new String((byte[])ele); + } + list.add(ele); + count--; + } + return list; + } else if (t == Type.MapType.getValue()) { + int count = (int)reader.readVarInt(); + Map map = new HashMap(); + for (int i = count; i > 0; i--) { + byte[] key = (byte[])deserializeItem(reader); + Object value = deserializeItem(reader); + if(value instanceof byte[]){ + value = Helper.toHexString((byte[])value); + } else if(value instanceof Long){ + if((Long)value == 0){ + value = "00"; + }else { + value = Helper.toHexString(Helper.BigIntToNeoBytes(BigInteger.valueOf((long) value))); + } + } + map.put(new String(key),value); + count--; + } + return map; + } else { + throw new SDKException(ErrorCode.ParamError); + } + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + public static void pushParam(ScriptBuilder sb,Object eValue){ + try { + if (eValue instanceof byte[]) { + sb.emitPushByteArray((byte[]) eValue); + } else if (eValue instanceof String) { + sb.emitPushByteArray(((String) eValue).getBytes()); + } else if (eValue instanceof Boolean) { + sb.emitPushBool((Boolean) eValue); + sb.add(ScriptOp.OP_PUSH0); + sb.add(ScriptOp.OP_BOOLOR); + } else if (eValue instanceof Map) { + pushMap(sb,eValue); + } else if (eValue instanceof Struct) { + List list = (List) ((Struct) eValue).list; + for (int i = list.size() - 1; i >= 0; i--) { + Object val = list.get(i); + pushParam(sb,val); + } + sb.emitPushInteger(new BigInteger(String.valueOf(list.size()))); + sb.pushPack(); + } else if (eValue instanceof List) { + List list = (List) eValue; + for (int i = list.size() - 1; i >= 0; i--) { + Object val = list.get(i); + pushParam(sb,val); + } + sb.emitPushInteger(new BigInteger(String.valueOf(list.size()))); + sb.pushPack(); + } else if (eValue instanceof Integer) { + sb.emitPushByteArray(Helper.BigIntToNeoBytes(BigInteger.valueOf((Integer) eValue))); + sb.add(ScriptOp.OP_PUSH0); + sb.add(ScriptOp.OP_ADD); + } else if (eValue instanceof Long) { + sb.emitPushByteArray(Helper.BigIntToNeoBytes(BigInteger.valueOf((Long) eValue))); + sb.add(ScriptOp.OP_PUSH0); + sb.add(ScriptOp.OP_ADD); + } else { + throw new SDKException(ErrorCode.ParamError); + } + }catch (SDKException e) { + e.printStackTrace(); + } + } + public static void pushStruct(ScriptBuilder sb,Object val) { + Struct struct = (Struct) val; + sb.add(ScriptOp.OP_NEWSTRUCT); + sb.add(ScriptOp.OP_TOALTSTACK); + for (int i =0;i < struct.list.size();i++) { + pushParam(sb, struct.list.get(i)); + sb.add(ScriptOp.OP_DUPFROMALTSTACK); + sb.add(ScriptOp.OP_SWAP); + sb.add(ScriptOp.OP_APPEND); + } + sb.add(ScriptOp.OP_FROMALTSTACK); + } + public static void pushMap(ScriptBuilder sb,Object val) { + Map map = (Map) val; + sb.add(ScriptOp.OP_NEWMAP); + sb.add(ScriptOp.OP_TOALTSTACK); + for (Map.Entry e : map.entrySet()) { + sb.add(ScriptOp.OP_DUPFROMALTSTACK); + pushParam(sb, e.getKey()); + pushParam(sb, e.getValue()); + sb.add(ScriptOp.OP_SETITEM); + } + sb.add(ScriptOp.OP_FROMALTSTACK); + } + public static void serializeStackItem(BinaryWriter bw,Object eValue){ + try { + if(eValue instanceof byte[]){ + bw.writeByte(Type.ByteArrayType.getValue()); + bw.writeVarBytes((byte[]) eValue); + } else if(eValue instanceof String){ + bw.writeByte(Type.ByteArrayType.getValue()); + bw.writeVarBytes(((String) eValue).getBytes()); + } else if (eValue instanceof Boolean) { + bw.writeByte(Type.BooleanType.getValue()); + bw.writeBoolean((Boolean) eValue); + } else if (eValue instanceof Map) { + bw.write(getMapBytes(eValue)); + } else if (eValue instanceof Struct) { + bw.writeVarBytes(getStructBytes(eValue)); + } else if (eValue instanceof List) { + List tmp = (List) eValue; + bw.writeByte(Type.ArrayType.getValue()); + bw.writeVarInt(tmp.size()); + for (int i = 0; i < tmp.size(); i++) { + serializeStackItem(bw, tmp.get(i)); + } + }else if(eValue instanceof Integer){ + bw.writeByte(Type.IntegerType.getValue()); + bw.writeVarBytes(Helper.BigIntToNeoBytes(BigInteger.valueOf((Integer) eValue))); + } else if(eValue instanceof Long){ + bw.writeByte(Type.IntegerType.getValue()); + bw.writeVarBytes(Helper.BigIntToNeoBytes(BigInteger.valueOf((Long) eValue))); + } else { + throw new SDKException(ErrorCode.ParamError); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + public static byte[] getStructBytes(Object val){ + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + BinaryWriter bw = new BinaryWriter(baos); + try { + List list = ((Struct)val).list; + bw.writeByte(Type.StructType.getValue()); + bw.writeVarInt(list.size()); + for (int i = 0; i < list.size(); i++) { + Object eValue = list.get(i); + serializeStackItem(bw,eValue); + } + } catch (Exception e) { + e.printStackTrace(); + } + return baos.toByteArray(); + } + public static byte[] getMapBytes(Object val){ + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + BinaryWriter bw = new BinaryWriter(baos); + try { + Map map = (Map)val; + bw.writeByte(Type.MapType.getValue()); + bw.writeVarInt(map.size()); + for(Map.Entry e:map.entrySet()){ + bw.writeByte(Type.ByteArrayType.getValue()); + bw.writeVarBytes(((String) e.getKey()).getBytes()); + Object eValue = e.getValue(); + serializeStackItem(bw,eValue); + } + bw.flush(); + } catch (Exception e) { + e.printStackTrace(); + } + return baos.toByteArray(); + } + /** + * @param list + * @return + */ + public static byte[] createCodeParamsScript(List list) { + ScriptBuilder sb = new ScriptBuilder(); + try { + createCodeParamsScript(sb, list); + } catch (Exception e) { + e.printStackTrace(); + } + return sb.toArray(); + } + + /** + * @param abiFunction + * @return + * @throws Exception + */ + public static byte[] serializeAbiFunction( AbiFunction abiFunction) throws Exception { + List list = new ArrayList(); + list.add(abiFunction.getName().getBytes()); + List tmp = new ArrayList(); + for (Parameter obj : abiFunction.getParameters()) { + if ("ByteArray".equals(obj.getType())) { + tmp.add(JSON.parseObject(obj.getValue(), byte[].class)); + } else if ("String".equals(obj.getType())) { + tmp.add(obj.getValue()); + } else if ("Boolean".equals(obj.getType())) { + tmp.add(JSON.parseObject(obj.getValue(), boolean.class)); + } else if ("Integer".equals(obj.getType())) { + tmp.add(JSON.parseObject(obj.getValue(), Long.class)); + } else if ("Array".equals(obj.getType())) { + List l = JSON.parseObject(obj.getValue(), List.class); + l = listConvert(l); + tmp.add(l); + } else if ("InteropInterface".equals(obj.getType())) { + tmp.add(JSON.parseObject(obj.getValue(), Object.class)); + } else if ("Void".equals(obj.getType())) { + + } else if ("Map".equals(obj.getType())) { + tmp.add(JSON.parseObject(obj.getValue(), Map.class)); + } else if ("Struct".equals(obj.getType())) { + tmp.add(JSON.parseObject(obj.getValue(), Struct.class)); + } else { + throw new SDKException(ErrorCode.TypeError); + } + } + if(list.size()>0) { + list.add(tmp); + } + byte[] params = createCodeParamsScript(list); + return params; + } + private static List listConvert(List l){ + for(int i = 0; i < l.size();i++){ + if(l.get(i) instanceof String) { + if (l.get(i) instanceof String) { + l.set(i, Base64.getDecoder().decode((String) l.get(i))); + } + }else if (l.get(i) instanceof List) { + l.set(i,listConvert((List)l.get(i))); + } + } + return l; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/smartcontract/neovm/abi/Parameter.java b/src/main/java/com/github/DNAProject/smartcontract/neovm/abi/Parameter.java new file mode 100644 index 0000000..c8f05c4 --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/neovm/abi/Parameter.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.smartcontract.neovm.abi; + +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.sdk.exception.SDKException; +import com.alibaba.fastjson.JSON; + +import java.util.List; +import java.util.Map; + +/** + * + */ +public class Parameter { + + public enum Type { ByteArray, String, Boolean, Integer, Array, InteropInterface, Void, Main, Struct } + + public String name; + public String type; + public String value; + + public Parameter(String name, Type type, Object value) { + this.name = name; + this.type = type.name(); + setValue(value); + } + + public Parameter() { + } + + public String getName() { + return name; + } + + public String getType() { + return type; + } + + public String getValue() { + return value; + } + + public boolean setValue(Object value) { + try { + if(value == null) { + this.value = null; + }else if ("ByteArray".equals(type)) { + byte[] tmp = (byte[]) value; + this.value = JSON.toJSONString(tmp); + } else if ("String".equals(type)) { + this.value = (String) value; + } else if ("Boolean".equals(type)) { + boolean tmp = (boolean) value; + this.value = JSON.toJSONString(tmp); + } else if ("Integer".equals(type)) { + long tmp = (long)value; + this.value = JSON.toJSONString(tmp); + } else if ("Array".equals(type)) { + List tmp = (List) value; + for (int i = 0; i < tmp.size(); i++) { + if(tmp.get(i) instanceof String){ + tmp.set(i,((String) tmp.get(i)).getBytes()); + } + } + this.value = JSON.toJSONString(tmp); + } else if ("InteropInterface".equals(type)) { + Object tmp = (Object) value; + this.value = JSON.toJSONString(tmp); + } else if ("Void".equals(type)) { + } else if ("Map".equals(type)) { + Map tmp = (Map) value; + this.value = JSON.toJSONString(tmp); + } else if ("Struct".equals(type)) { + Struct tmp = (Struct) value; + this.value = JSON.toJSONString(tmp); + } else { + throw new SDKException(ErrorCode.TypeError); + } + return true; + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + + @Override + public String toString() { + return JSON.toJSONString(this); + } +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/neovm/abi/Struct.java b/src/main/java/com/github/DNAProject/smartcontract/neovm/abi/Struct.java new file mode 100644 index 0000000..f89118a --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/neovm/abi/Struct.java @@ -0,0 +1,18 @@ +package com.github.DNAProject.smartcontract.neovm.abi; + +import java.util.ArrayList; +import java.util.List; + + +public class Struct { + public List list = new ArrayList(); + public Struct(){ + + } + public Struct add(Object... objs){ + for(int i=0;i Date: Fri, 3 Jan 2020 19:40:51 +0800 Subject: [PATCH 08/18] add network file --- .../github/DNAProject/merkle/TreeHasher.java | 116 +++++ .../network/connect/AbstractConnector.java | 26 ++ .../network/connect/IConnector.java | 59 +++ .../network/exception/ConnectorException.java | 33 ++ .../network/exception/RestfulException.java | 32 ++ .../network/exception/RpcException.java | 34 ++ .../DNAProject/network/rest/Interfaces.java | 269 ++++++++++++ .../DNAProject/network/rest/RestClient.java | 322 ++++++++++++++ .../github/DNAProject/network/rest/http.java | 222 ++++++++++ .../network/websocket/MsgQueue.java | 50 +++ .../DNAProject/network/websocket/Result.java | 32 ++ .../network/websocket/WebsocketClient.java | 415 ++++++++++++++++++ 12 files changed, 1610 insertions(+) create mode 100644 src/main/java/com/github/DNAProject/merkle/TreeHasher.java create mode 100644 src/main/java/com/github/DNAProject/network/connect/AbstractConnector.java create mode 100644 src/main/java/com/github/DNAProject/network/connect/IConnector.java create mode 100644 src/main/java/com/github/DNAProject/network/exception/ConnectorException.java create mode 100644 src/main/java/com/github/DNAProject/network/exception/RestfulException.java create mode 100644 src/main/java/com/github/DNAProject/network/exception/RpcException.java create mode 100644 src/main/java/com/github/DNAProject/network/rest/Interfaces.java create mode 100644 src/main/java/com/github/DNAProject/network/rest/RestClient.java create mode 100644 src/main/java/com/github/DNAProject/network/rest/http.java create mode 100644 src/main/java/com/github/DNAProject/network/websocket/MsgQueue.java create mode 100644 src/main/java/com/github/DNAProject/network/websocket/Result.java create mode 100644 src/main/java/com/github/DNAProject/network/websocket/WebsocketClient.java diff --git a/src/main/java/com/github/DNAProject/merkle/TreeHasher.java b/src/main/java/com/github/DNAProject/merkle/TreeHasher.java new file mode 100644 index 0000000..3039f3f --- /dev/null +++ b/src/main/java/com/github/DNAProject/merkle/TreeHasher.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.merkle; + +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.common.UInt256; +import com.github.DNAProject.crypto.Digest; +import com.github.DNAProject.sdk.exception.SDKException; + +import java.util.Arrays; + +public class TreeHasher { + public UInt256 hash_empty(){ + return new UInt256(); + } + public UInt256 hash_leaf(byte[] data) { + byte[] tmp = Helper.addBytes(new byte[]{0},data); + return new UInt256(Digest.sha256(tmp)); + } + public UInt256 hash_children(UInt256 left, UInt256 right ){ + byte[] data = Helper.addBytes(new byte[]{1},left.toArray()); + data = Helper.addBytes(data,right.toArray()); + return new UInt256(Digest.sha256(data)); + } + public long countBit(long num ) { + long count = 0; + while(num != 0) { + num &= (num - 1); + count += 1; + } + return count; + } + public UInt256 HashFullTreeWithLeafHash(UInt256[] leaves ) throws Exception { + long length =leaves.length; + Obj obj = _hash_full(leaves, 0, length); + + if(obj.hashes.length != countBit(length) ){ + throw new SDKException(ErrorCode.AsserFailedHashFullTree); + } + return obj.root_hash; + } + public UInt256 HashFullTree(byte[][] leaves) throws Exception { + int length = leaves.length; + UInt256[] leafhashes = new UInt256[length]; + for (int i=0; i< length;i++) { + leafhashes[i] = hash_leaf(leaves[i]); + } + Obj obj = _hash_full(leafhashes, 0, length); + + if (obj.hashes.length != countBit(length)) { + throw new Exception(ErrorCode.AsserFailedHashFullTree); + } + return obj.root_hash; + } + + public Obj _hash_full(UInt256[] leaves,long l_idx,long r_idx ) throws Exception { + long width = r_idx - l_idx; + if (width == 0 ){ + return new Obj(hash_empty(),null); + } else if (width == 1) { + UInt256 leaf_hash = leaves[(int)l_idx]; + return new Obj(leaf_hash,new UInt256[]{leaf_hash}); + } else { + int split_width = 1 << (countBit(width-1) - 1); + Obj lObj = _hash_full(leaves, l_idx, l_idx+split_width); + if (lObj.hashes.length != 1 ){ + throw new Exception(ErrorCode.LeftTreeFull); + } + Obj rObj = _hash_full(leaves, l_idx+split_width, r_idx); + UInt256 root_hash = hash_children(lObj.root_hash, rObj.root_hash); + UInt256[] hashes = null; + if (split_width * 2 == width) { + hashes = new UInt256[]{root_hash}; + } else { + hashes = Arrays.copyOf(lObj.hashes, lObj.hashes.length + rObj.hashes.length); + System.arraycopy(rObj.hashes, 0, hashes, lObj.hashes.length, rObj.hashes.length); + } + return new Obj(root_hash, hashes); + } + } + public UInt256 _hash_fold(UInt256[] hashes){ + int l = hashes.length; + UInt256 accum = hashes[l-1]; + for(int i=l-2;i>=0;i--){ + accum = hash_children(hashes[i],accum); + } + return accum; + } + class Obj{ + public UInt256 root_hash; + public UInt256[] hashes; + public Obj(UInt256 root_hash,UInt256[] hashes){ + this.root_hash = root_hash; + this.hashes = hashes; + } + } +} + diff --git a/src/main/java/com/github/DNAProject/network/connect/AbstractConnector.java b/src/main/java/com/github/DNAProject/network/connect/AbstractConnector.java new file mode 100644 index 0000000..8168d48 --- /dev/null +++ b/src/main/java/com/github/DNAProject/network/connect/AbstractConnector.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.network.connect; + + +public abstract class AbstractConnector implements IConnector { + + +} diff --git a/src/main/java/com/github/DNAProject/network/connect/IConnector.java b/src/main/java/com/github/DNAProject/network/connect/IConnector.java new file mode 100644 index 0000000..58e9f7f --- /dev/null +++ b/src/main/java/com/github/DNAProject/network/connect/IConnector.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.network.connect; + +import java.io.IOException; +import com.github.DNAProject.core.block.Block; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.network.exception.ConnectorException; + +public interface IConnector { + + String getUrl(); + Object sendRawTransaction(boolean preExec, String userid, String hexData) throws ConnectorException, IOException; + Object sendRawTransaction(String hexData) throws ConnectorException, IOException; + Transaction getRawTransaction(String txhash) throws ConnectorException, IOException; + Object getRawTransactionJson(String txhash) throws ConnectorException, IOException; + int getNodeCount() throws ConnectorException, IOException; + int getBlockHeight() throws ConnectorException, IOException; + Block getBlock(int height) throws ConnectorException, IOException; + Block getBlock(String hash) throws ConnectorException, IOException ; + Object getBlockJson(int height) throws ConnectorException, IOException; + Object getBlockJson(String hash) throws ConnectorException, IOException; + + Object getBalance(String address) throws ConnectorException, IOException; + + Object getContract(String hash) throws ConnectorException, IOException; + Object getContractJson(String hash) throws ConnectorException, IOException; + Object getSmartCodeEvent(int height) throws ConnectorException, IOException; + Object getSmartCodeEvent(String hash) throws ConnectorException, IOException; + int getBlockHeightByTxHash(String hash) throws ConnectorException, IOException; + + String getStorage(String codehash, String key) throws ConnectorException, IOException; + Object getMerkleProof(String hash) throws ConnectorException, IOException; + String getAllowance(String asset, String from, String to) throws ConnectorException, IOException; + Object getMemPoolTxCount() throws ConnectorException, IOException; + Object getMemPoolTxState(String hash) throws ConnectorException, IOException; + String getVersion() throws ConnectorException, IOException; + String getGrantOng(String address) throws ConnectorException, IOException; + int getNetworkId() throws ConnectorException, IOException; + Object getNodeSyncStatus() throws ConnectorException, IOException; + String getSideChainData(String sideChainID) throws ConnectorException, IOException; +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/network/exception/ConnectorException.java b/src/main/java/com/github/DNAProject/network/exception/ConnectorException.java new file mode 100644 index 0000000..80864b3 --- /dev/null +++ b/src/main/java/com/github/DNAProject/network/exception/ConnectorException.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.network.exception; + + +public class ConnectorException extends Exception { + private static final long serialVersionUID = 1110342144692879043L; + + public ConnectorException(String message) { + super(message); + } + + public ConnectorException(String message, Throwable ex) { + super(message, ex); + } +} diff --git a/src/main/java/com/github/DNAProject/network/exception/RestfulException.java b/src/main/java/com/github/DNAProject/network/exception/RestfulException.java new file mode 100644 index 0000000..511d17a --- /dev/null +++ b/src/main/java/com/github/DNAProject/network/exception/RestfulException.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.network.exception; + +public class RestfulException extends ConnectorException { + private static final long serialVersionUID = -8558006777817318117L; + + public RestfulException(String message) { + super(message); + } + + public RestfulException(String message, Throwable ex) { + super(message, ex); + } +} diff --git a/src/main/java/com/github/DNAProject/network/exception/RpcException.java b/src/main/java/com/github/DNAProject/network/exception/RpcException.java new file mode 100644 index 0000000..73a98c4 --- /dev/null +++ b/src/main/java/com/github/DNAProject/network/exception/RpcException.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.network.exception; + +/** + * + */ +public class RpcException extends ConnectorException { + private static final long serialVersionUID = -8558006777817318117L; + + public final int code; + + public RpcException(int code,String message) { + super(message); + this.code = code; + } +} diff --git a/src/main/java/com/github/DNAProject/network/rest/Interfaces.java b/src/main/java/com/github/DNAProject/network/rest/Interfaces.java new file mode 100644 index 0000000..0eaa041 --- /dev/null +++ b/src/main/java/com/github/DNAProject/network/rest/Interfaces.java @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.network.rest; + + +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.network.exception.RestfulException; + +import java.util.HashMap; +import java.util.Map; + +/** + * + */ +class Interfaces { + private String url; + + public Interfaces(String url) { + this.url = url; + } + + public String getUrl() { + return url; + } + + public String sendTransaction(boolean preExec, String userid, String action, String version, String data) throws RestfulException { + Map params = new HashMap(); + if (userid != null) { + params.put("userid", userid); + } + if (preExec) { + params.put("preExec", "1"); + } + Map body = new HashMap(); + body.put("Action", action); + body.put("Version", version); + body.put("Data", data); + try { + return http.post(url + UrlConsts.Url_send_transaction, params, body); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr(url), e); + + } + } + + public String getTransaction(String txhash, boolean raw) throws RestfulException { + Map params = new HashMap(); + if (raw) { + params.put("raw", "1"); + } + try { + return http.get(url + UrlConsts.Url_get_transaction + txhash, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + + public String getNodeCount() throws RestfulException { + Map params = new HashMap(); + try { + return http.get(url + UrlConsts.Url_get_node_count, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + + public String getBlockHeight() throws RestfulException { + Map params = new HashMap(); + try { + return http.get(url + UrlConsts.Url_get_block_height, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + + public String getBlock(int height, String raw) throws RestfulException { + Map params = new HashMap(); + params.put("raw", raw); + try { + return http.get(url + UrlConsts.Url_get_block_by_height + height, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + + public String getBlock(String hash, String raw) throws RestfulException { + Map params = new HashMap(); + params.put("raw", raw); + try { + return http.get(url + UrlConsts.Url_get_block_by_hash + hash, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + + public String getContract(String hash) throws RestfulException { + Map params = new HashMap(); + params.put("raw", "1"); + try { + return http.get(url + UrlConsts.Url_get_contract_state + hash, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + + public String getContractJson(String hash) throws RestfulException { + Map params = new HashMap(); + try { + return http.get(url + UrlConsts.Url_get_contract_state + hash, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + + public String getSmartCodeEvent(int height) throws RestfulException { + Map params = new HashMap(); + try { + return http.get(url + UrlConsts.Url_get_smartcodeevent_txs_by_height + height, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + + public String getSmartCodeEvent(String hash) throws RestfulException { + Map params = new HashMap(); + try { + return http.get(url + UrlConsts.Url_get_smartcodeevent_by_txhash + hash, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + + public String getBlockHeightByTxHash(String hash) throws RestfulException { + Map params = new HashMap(); + try { + return http.get(url + UrlConsts.Url_get_block_height_by_txhash + hash, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + + public String getStorage(String codehash, String key) throws RestfulException { + Map params = new HashMap(); + try { + return http.get(url + UrlConsts.Url_get_storage + codehash + "/" + key, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + + public String getMerkleProof(String hash) throws RestfulException { + Map params = new HashMap(); + try { + return http.get(url + UrlConsts.Url_get_merkleproof + hash, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + public String getMemPoolTxCount() throws RestfulException { + Map params = new HashMap(); + try { + return http.get(url + UrlConsts.Url_get_mem_pool_tx_count, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + public String getMemPoolTxState(String hash) throws RestfulException { + Map params = new HashMap(); + try { + return http.get(url + UrlConsts.Url_get_mem_pool_tx_state + hash, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + public String getBalance(String address) throws RestfulException { + Map params = new HashMap(); + try { + return http.get(url + UrlConsts.Url_get_account_balance + address, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + + public String getTransactionJson(String txhash) throws RestfulException { + Map params = new HashMap(); + try { + return http.get(url + UrlConsts.Url_get_transaction + txhash, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + + public String getBlockJson(int height) throws RestfulException { + Map params = new HashMap(); + try { + return http.get(url + UrlConsts.Url_get_block_by_height + height, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + + public String getBlockJson(String hash) throws RestfulException { + Map params = new HashMap(); + try { + return http.get(url + UrlConsts.Url_get_block_by_hash + hash, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + + public String getAllowance(String asset, String from, String to) throws RestfulException { + Map params = new HashMap(); + try { + return http.get(url + UrlConsts.Url_get_allowance + asset + "/" + from + "/" + to, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + public String getVersion() throws RestfulException { + Map params = new HashMap(); + try { + return http.get(url + UrlConsts.Url_get_version, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + public String getGrantOng(String address) throws RestfulException { + Map params = new HashMap(); + try { + return http.get(url + UrlConsts.Url_get_grant_ong+ "/" +address, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + public String getNetworkId() throws RestfulException { + Map params = new HashMap(); + try { + return http.get(url + UrlConsts.Url_get_networkid, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + public String getNodeSyncStatus() throws RestfulException { + Map params = new HashMap(); + try { + return http.get(url + UrlConsts.Url_get_syncstatus, params); + } catch (Exception e) { + throw new RestfulException(ErrorCode.ConnectUrlErr + url, e); + } + } + +} diff --git a/src/main/java/com/github/DNAProject/network/rest/RestClient.java b/src/main/java/com/github/DNAProject/network/rest/RestClient.java new file mode 100644 index 0000000..0bb9c74 --- /dev/null +++ b/src/main/java/com/github/DNAProject/network/rest/RestClient.java @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.network.rest; + +import java.io.IOException; + +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.block.Block; +import com.github.DNAProject.io.Serializable; +import com.github.DNAProject.network.connect.AbstractConnector; +import com.github.DNAProject.network.exception.ConnectorException; +import com.github.DNAProject.core.transaction.Transaction; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.network.exception.RestfulException; + +public class RestClient extends AbstractConnector { + private Interfaces api; + private String version = "v1.0.0", action = "sendrawtransaction"; + + public RestClient(String restUrl) { + api = new Interfaces(restUrl); + } + + @Override + public String getUrl() { + return api.getUrl(); + } + + @Override + public String sendRawTransaction(String hexData) throws RestfulException { + String rs = api.sendTransaction(false, null, action, version, hexData); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return rs; + } + throw new RestfulException(to(rr)); + } + + @Override + public String sendRawTransaction(boolean preExec, String userid, String hexData) throws RestfulException { + String rs = api.sendTransaction(preExec, userid, action, version, hexData); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return rs; + } + throw new RestfulException(to(rr)); + } + + @Override + public Transaction getRawTransaction(String txhash) throws RestfulException { + String rs = api.getTransaction(txhash, true); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + try { + return Transaction.deserializeFrom(Helper.hexToBytes((String) rr.Result)); + } catch (IOException e) { + throw new RestfulException(ErrorCode.TxDeserializeError, e); + } + } + throw new RestfulException(to(rr)); + } + + @Override + public int getNodeCount() throws RestfulException { + String rs = api.getNodeCount(); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return (int) rr.Result; + } + throw new RestfulException(to(rr)); + + } + + @Override + public int getBlockHeight() throws RestfulException { + String rs = api.getBlockHeight(); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return (int) rr.Result; + } + throw new RestfulException(to(rr)); + + } + + @Override + public Block getBlock(int height) throws RestfulException { + String rs = api.getBlock(height, "1"); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + try { + return Serializable.from(Helper.hexToBytes((String) rr.Result), Block.class); + } catch (InstantiationException | IllegalAccessException e) { + throw new RestfulException(ErrorCode.BlockDeserializeError, e); + } + } + throw new RestfulException(to(rr)); + } + + + @Override + public Block getBlock(String hash) throws RestfulException { + String rs = api.getBlock(hash, "1"); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error != 0) { + throw new RestfulException(to(rr)); + } + try { + return Serializable.from(Helper.hexToBytes((String) rr.Result), Block.class); + } catch (InstantiationException | IllegalAccessException e) { + throw new RestfulException(ErrorCode.BlockDeserializeError, e); + } + } + + @Override + public Object getBalance(String address) throws RestfulException { + String rs = api.getBalance(address); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return rr.Result; + } + throw new RestfulException(to(rr)); + } + + @Override + public Object getRawTransactionJson(String txhash) throws RestfulException,IOException { + String rs = api.getTransaction(txhash, true); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return JSON.toJSONString(Transaction.deserializeFrom(Helper.hexToBytes((String) rr.Result)).json()); + } + throw new RestfulException(to(rr)); + } + + @Override + public Object getBlockJson(int height) throws RestfulException { + String rs = api.getBlock(height, "0"); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return rr.Result; + } + throw new RestfulException(to(rr)); + } + + @Override + public Object getBlockJson(String hash) throws RestfulException { + String rs = api.getBlock(hash, "0"); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return rr.Result; + } + throw new RestfulException(to(rr)); + + } + + @Override + public Object getContract(String hash) throws RestfulException { + String rs = api.getContract(hash); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return rr.Result; + } + throw new RestfulException(to(rr)); + } + + @Override + public Object getContractJson(String hash) throws RestfulException { + String rs = api.getContractJson(hash); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return rr.Result; + } + throw new RestfulException(to(rr)); + } + + @Override + public Object getSmartCodeEvent(int height) throws ConnectorException, IOException { + String rs = api.getSmartCodeEvent(height); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return rr.Result; + } + throw new RestfulException(to(rr)); + + } + + @Override + public Object getSmartCodeEvent(String hash) throws ConnectorException, IOException { + String rs = api.getSmartCodeEvent(hash); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return rr.Result; + } + throw new RestfulException(to(rr)); + } + + @Override + public int getBlockHeightByTxHash(String hash) throws ConnectorException, IOException { + String rs = api.getBlockHeightByTxHash(hash); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return (int)rr.Result; + } + throw new RestfulException(to(rr)); + } + + @Override + public String getStorage(String codehash,String key) throws ConnectorException, IOException { + String rs = api.getStorage(codehash,key); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return (String)rr.Result; + } + throw new RestfulException(to(rr)); + } + @Override + public Object getMerkleProof(String hash) throws ConnectorException, IOException{ + String rs = api.getMerkleProof(hash); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return rr.Result; + } + throw new RestfulException(to(rr)); + } + @Override + public String getAllowance(String asset,String from,String to) throws ConnectorException, IOException{ + String rs = api.getAllowance(asset,from,to); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return (String)rr.Result; + } + throw new RestfulException(to(rr)); + } + @Override + public Object getMemPoolTxCount() throws ConnectorException, IOException{ + String rs = api.getMemPoolTxCount(); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return rr.Result; + } + throw new RestfulException(to(rr)); + } + + @Override + public Object getMemPoolTxState(String hash) throws ConnectorException, IOException{ + String rs = api.getMemPoolTxState(hash); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return rr.Result; + } + throw new RestfulException(to(rr)); + } + @Override + public String getVersion() throws ConnectorException, IOException{ + String rs = api.getVersion(); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return (String)rr.Result; + } + throw new RestfulException(to(rr)); + } + + @Override + public String getGrantOng(String address) throws ConnectorException, IOException { + String rs = api.getGrantOng(address); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return (String)rr.Result; + } + throw new RestfulException(to(rr)); + } + + @Override + public int getNetworkId() throws ConnectorException, IOException { + String rs = api.getNetworkId(); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return (int)rr.Result; + } + throw new RestfulException(to(rr)); + } + @Override + public Object getNodeSyncStatus() throws ConnectorException, IOException { + String rs = api.getNodeSyncStatus(); + Result rr = JSON.parseObject(rs, Result.class); + if (rr.Error == 0) { + return rr.Result; + } + throw new RestfulException(to(rr)); + } + + @Override + public String getSideChainData(String sideChainID) throws ConnectorException, IOException { + return null; + } + + private String to(Result rr) { + return JSON.toJSONString(rr); + } +} + + + + diff --git a/src/main/java/com/github/DNAProject/network/rest/http.java b/src/main/java/com/github/DNAProject/network/rest/http.java new file mode 100644 index 0000000..fab37fb --- /dev/null +++ b/src/main/java/com/github/DNAProject/network/rest/http.java @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.network.rest; +import java.io.BufferedReader; +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLEncoder; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.Map; +import java.util.Map.Entry; + +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; + +import com.alibaba.fastjson.JSON; + +public class http { + private static final String DEFAULT_CHARSET = "UTF-8"; + + public static String post(String url,Map header, String body, boolean https) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException { + URL u = new URL(url); + HttpURLConnection http = (HttpURLConnection) u.openConnection(); + http.setConnectTimeout(10000); + http.setReadTimeout(10000); + http.setRequestMethod("POST"); + http.setRequestProperty("Content-Type","application/json"); + if(header != null) { + for (Entry e : header.entrySet()) { + http.setRequestProperty(e.getKey(), (String) e.getValue()); + } + } + if(https) { + SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); + sslContext.init(null, new TrustManager[]{new X509()}, new SecureRandom()); + SSLSocketFactory ssf = sslContext.getSocketFactory(); + ((HttpsURLConnection)http).setSSLSocketFactory(ssf); + } + http.setDoOutput(true); + http.setDoInput(true); + http.connect(); + try (OutputStream out = http.getOutputStream()) { + out.write(body.getBytes(DEFAULT_CHARSET)); + out.flush(); + } + StringBuilder sb = new StringBuilder(); + try (InputStream is = http.getInputStream()) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, DEFAULT_CHARSET))) { + String str = null; + while((str = reader.readLine()) != null) { + sb.append(str); + str = null; + } + } + } + if (http != null) { + http.disconnect(); + } + return sb.toString(); + } + public static String post(String url, String body, boolean https) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException { + return post(url,null,body,https); + } + public static String delete(String url, String body, boolean https) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException { + URL u = new URL(url); + HttpURLConnection http = (HttpURLConnection) u.openConnection(); + http.setConnectTimeout(10000); + http.setReadTimeout(10000); + http.setRequestMethod("DELETE"); + http.setRequestProperty("Content-Type","application/json"); + if(https) { + SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); + sslContext.init(null, new TrustManager[]{new X509()}, new SecureRandom()); + SSLSocketFactory ssf = sslContext.getSocketFactory(); + ((HttpsURLConnection)http).setSSLSocketFactory(ssf); + } + http.setDoOutput(true); + http.setDoInput(true); + http.connect(); + try (OutputStream out = http.getOutputStream()) { + out.write(body.getBytes(DEFAULT_CHARSET)); + out.flush(); + } + StringBuilder sb = new StringBuilder(); + try (InputStream is = http.getInputStream()) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, DEFAULT_CHARSET))) { + String str = null; + while((str = reader.readLine()) != null) { + sb.append(str); + str = null; + } + } + } + if (http != null) { + http.disconnect(); + } + return sb.toString(); + } + + public static String delete(String url, Map params, Map body) throws Exception { + if(url.startsWith("https")){ + return delete(url+cvtParams(params), JSON.toJSONString(body),true); + }else{ + return delete(url+cvtParams(params), JSON.toJSONString(body), false); + } + } + + public static String post(String url, Map params, Map body) throws Exception { + System.out.println(String.format("POST url=%s,%s,%s", url,JSON.toJSONString(params),JSON.toJSONString(body))); + if(url.startsWith("https")){ + return post(url+cvtParams(params), JSON.toJSONString(body), true); + }else{ + return post(url+cvtParams(params), JSON.toJSONString(body), false); + } + } + + private static String get(String url ,boolean https) throws Exception { + URL u = new URL(url); + HttpURLConnection http = (HttpURLConnection) u.openConnection(); + http.setConnectTimeout(20000); + http.setReadTimeout(20000); + http.setRequestMethod("GET"); + http.setRequestProperty("Content-Type","application/json"); + if(https) { + SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE"); + sslContext.init(null, new TrustManager[]{new X509()}, new SecureRandom()); + SSLSocketFactory ssf = sslContext.getSocketFactory(); + ((HttpsURLConnection)http).setSSLSocketFactory(ssf); + } + http.setDoOutput(true); + http.setDoInput(true); + http.connect(); + StringBuilder sb = new StringBuilder(); + try (InputStream is = http.getInputStream()) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(is, DEFAULT_CHARSET))) { + String str = null; + while((str = reader.readLine()) != null) { + sb.append(str); + str = null; + } + } + } + if (http != null) { + http.disconnect(); + } + return sb.toString(); + } + private static String get(String url) throws Exception { + System.out.println(String.format(" GET url=%s, params=%s", url, null)); + if(url.startsWith("https")){ + return get(url, true); + }else{ + return get(url, false); + } + } + + public static String get(String url, Map params) throws Exception { + if(url.startsWith("https")){ + return get(url+cvtParams(params), true); + }else{ + return get(url+cvtParams(params), false); + } + } + + + private static String cvtParams( Map params){ + if (params == null || params.isEmpty()) { + return ""; + } + StringBuilder sb = new StringBuilder(); + for (Entry entry : params.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + try { + value = value == null ? value:URLEncoder.encode(value, DEFAULT_CHARSET); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + sb.append("&").append(key).append("=").append(value); + } + return "?"+sb.toString().substring(1); + } + + /** + * + * @param objs + * @throws IOException + */ + private static void close(Closeable... objs) throws IOException { + if(objs != null && objs.length > 0) { + Arrays.stream(objs).forEach(p -> {try {p.close(); } catch(Exception e){}}); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/network/websocket/MsgQueue.java b/src/main/java/com/github/DNAProject/network/websocket/MsgQueue.java new file mode 100644 index 0000000..4920054 --- /dev/null +++ b/src/main/java/com/github/DNAProject/network/websocket/MsgQueue.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.network.websocket; + +import com.alibaba.fastjson.JSON; + +import java.util.*; + +/** + * + */ +public class MsgQueue { + + private static Set resultSet = new HashSet(); + public static void addResult(Result obj) { + resultSet.add(JSON.toJSONString(obj)); + } + public static Set getResultSet(){ + Set rt = new HashSet(); + rt.addAll(resultSet); + return rt; + } + + public static void removeResult(String ele){ + resultSet.remove(ele); + } + public static void clear(){ + resultSet.clear(); + } + public static int size() { + return resultSet.size(); + } +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/network/websocket/Result.java b/src/main/java/com/github/DNAProject/network/websocket/Result.java new file mode 100644 index 0000000..33d22dc --- /dev/null +++ b/src/main/java/com/github/DNAProject/network/websocket/Result.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.network.websocket; + +/** + * + */ +public class Result { + public String Action; + public long Error; + public String Desc; + public Object Result; + public String Version; + public Object Id; +} diff --git a/src/main/java/com/github/DNAProject/network/websocket/WebsocketClient.java b/src/main/java/com/github/DNAProject/network/websocket/WebsocketClient.java new file mode 100644 index 0000000..656e358 --- /dev/null +++ b/src/main/java/com/github/DNAProject/network/websocket/WebsocketClient.java @@ -0,0 +1,415 @@ +/* + * Copyright (C) 2018 The DNA Authors + * This file is part of The DNA library. + * + * The DNA is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The DNA is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The DNA. If not, see . + * + */ + +package com.github.DNAProject.network.websocket; + +import com.alibaba.fastjson.JSON; +import com.github.DNAProject.core.block.Block; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.network.connect.AbstractConnector; +import com.github.DNAProject.network.exception.ConnectorException; +import okhttp3.*; + +import java.io.IOException; +import java.util.*; + +/** + * + */ +public class WebsocketClient extends AbstractConnector { + private WebSocket mWebSocket = null; + private Object lock; + private boolean logFlag; + private long reqId = 0; + public static String wsUrl = ""; + private WebsocketClient wsClient = null; + + public WebsocketClient(String url,Object lock) { + wsUrl = url; + this.lock = lock; + wsClient = this; + } + + + public void setLog(boolean b) { + logFlag = b; + } + + public void startWebsocketThread(boolean log) { + this.logFlag = log; + Thread thread = new Thread( + new Runnable() { + @Override + public void run() { + wsClient.wsStart(); + } + }); + thread.start(); + } + @Override + public String getUrl(){ + return wsUrl; + } + + public void sendHeartBeat() { + Map map = new HashMap<>(); + map.put("Action", "heartbeat"); + map.put("Version", "V1.0.0"); + map.put("Id", generateReqId()); + mWebSocket.send(JSON.toJSONString(map)); + } + public void sendSubscribe(Map map) { + map.put("Action", "subscribe"); + map.put("Version", "V1.0.0"); + map.put("Id", generateReqId()); + mWebSocket.send(JSON.toJSONString(map)); + } + public void send(Map map) { + mWebSocket.send(JSON.toJSONString(map)); + } + public void setReqId(long reqId){ + this.reqId = reqId; + } + private long generateReqId(){ + if(reqId == 0) { + return new Random().nextInt() & Integer.MAX_VALUE; + } + return reqId; + } + @Override + public Object sendRawTransaction(boolean preExec,String userid,String hexData) throws ConnectorException, IOException{ + Map map = new HashMap<>(); + map.put("Action", "sendrawtransaction"); + map.put("Version", "1.0.0"); + map.put("Data", hexData); + map.put("Id", generateReqId()); + if(preExec){ + map.put("PreExec", "1"); + } + mWebSocket.send(JSON.toJSONString(map)); + if(preExec){ + return "0"; + } + return ""; + } + @Override + public Object sendRawTransaction(String hexData) throws ConnectorException, IOException{ + Map map = new HashMap<>(); + map.put("Action", "sendrawtransaction"); + map.put("Version", "1.0.0"); + map.put("Data", hexData); + map.put("Id", generateReqId()); + mWebSocket.send(JSON.toJSONString(map)); + return ""; + } + @Override + public Transaction getRawTransaction(String txhash) throws ConnectorException, IOException{ + Map map = new HashMap<>(); + map.put("Action", "gettransaction"); + map.put("Version", "1.0.0"); + map.put("Hash", txhash); + map.put("Raw", "1"); + map.put("Id", generateReqId()); + mWebSocket.send(JSON.toJSONString(map)); + return null; + } + @Override + public Object getRawTransactionJson(String txhash) throws ConnectorException, IOException{ + Map map = new HashMap<>(); + map.put("Action", "gettransaction"); + map.put("Version", "1.0.0"); + map.put("Hash", txhash); + map.put("Raw", "0"); + map.put("Id", generateReqId()); + mWebSocket.send(JSON.toJSONString(map)); + return null; + } + @Override + public int getNodeCount() throws ConnectorException, IOException{ + Map map = new HashMap<>(); + map.put("Action", "getconnectioncount"); + map.put("Version", "1.0.0"); + map.put("Id", generateReqId()); + mWebSocket.send(JSON.toJSONString(map)); + return 0; + } + @Override + public int getBlockHeight() throws ConnectorException, IOException{ + Map map = new HashMap<>(); + map.put("Action", "getblockheight"); + map.put("Version", "1.0.0"); + map.put("Id", generateReqId()); + mWebSocket.send(JSON.toJSONString(map)); + return 0; + } + @Override + public Block getBlock(int height) throws ConnectorException, IOException{ + Map map = new HashMap<>(); + map.put("Action", "getblockbyheight"); + map.put("Version", "1.0.0"); + map.put("Height",height); + map.put("Raw","1"); + map.put("Id", generateReqId()); + mWebSocket.send(JSON.toJSONString(map)); + return null; + } + @Override + public Block getBlock(String hash) throws ConnectorException, IOException{ + Map map = new HashMap<>(); + map.put("Action", "getblockbyhash"); + map.put("Version", "1.0.0"); + map.put("Hash",hash); + map.put("Raw","1"); + map.put("Id", generateReqId()); + mWebSocket.send(JSON.toJSONString(map)); + return null; + } + @Override + public Block getBlockJson(int height) throws ConnectorException, IOException{ + Map map = new HashMap<>(); + map.put("Action", "getblockbyheight"); + map.put("Version", "1.0.0"); + map.put("Height",height); + map.put("Id", generateReqId()); + mWebSocket.send(JSON.toJSONString(map)); + return null; + } + @Override + public Block getBlockJson(String hash) throws ConnectorException, IOException{ + Map map = new HashMap<>(); + map.put("Action", "getblockbyhash"); + map.put("Version", "1.0.0"); + map.put("Hash",hash); + map.put("Id", generateReqId()); + mWebSocket.send(JSON.toJSONString(map)); + return null; + } + @Override + public Object getBalance(String address) throws ConnectorException, IOException{ + Map map = new HashMap<>(); + map.put("Action", "getbalance"); + map.put("Version", "1.0.0"); + map.put("Addr",address); + map.put("Id", generateReqId()); + mWebSocket.send(JSON.toJSONString(map)); + return null; + } + @Override + public Object getContract(String hash) throws ConnectorException, IOException{ + Map map = new HashMap<>(); + map.put("Action", "getcontract"); + map.put("Version", "1.0.0"); + map.put("Raw","1"); + map.put("Hash", hash); + map.put("Id", generateReqId()); + return mWebSocket.send(JSON.toJSONString(map)); + } + @Override + public Object getContractJson(String hash) throws ConnectorException, IOException{ + Map map = new HashMap<>(); + map.put("Action", "getcontract"); + map.put("Version", "1.0.0"); + map.put("Raw","0"); + map.put("Hash", hash); + map.put("Id", generateReqId()); + return mWebSocket.send(JSON.toJSONString(map)); + } + @Override + public Object getSmartCodeEvent(int height) throws ConnectorException, IOException{ + Map map = new HashMap<>(); + map.put("Action", "getsmartcodeeventbyheight"); + map.put("Version", "1.0.0"); + map.put("Height", height); + map.put("Id", generateReqId()); + return mWebSocket.send(JSON.toJSONString(map)); + } + @Override + public Object getSmartCodeEvent(String hash) throws ConnectorException, IOException{ + Map map = new HashMap<>(); + map.put("Action", "getsmartcodeeventbyhash"); + map.put("Version", "1.0.0"); + map.put("Hash", hash); + return mWebSocket.send(JSON.toJSONString(map)); + } + @Override + public int getBlockHeightByTxHash(String hash) throws ConnectorException, IOException{ + Map map = new HashMap<>(); + map.put("Action", "getblockheightbytxhash"); + map.put("Version", "1.0.0"); + map.put("Hash", hash); + map.put("Id", generateReqId()); + mWebSocket.send(JSON.toJSONString(map)); + return 0; + } + + @Override + public String getStorage(String codehash, String key) throws ConnectorException, IOException { + Map map = new HashMap<>(); + map.put("Action", "getstorage"); + map.put("Version", "1.0.0"); + map.put("Hash", codehash); + map.put("Key", key); + map.put("Id", generateReqId()); + mWebSocket.send(JSON.toJSONString(map)); + return ""; + } + @Override + public Object getMerkleProof(String hash) throws ConnectorException, IOException{ + Map map = new HashMap<>(); + map.put("Action", "getmerkleproof"); + map.put("Version", "1.0.0"); + map.put("Hash", hash); + map.put("Id", generateReqId()); + mWebSocket.send(JSON.toJSONString(map)); + return ""; + } + @Override + public String getAllowance(String asset,String from,String to) throws ConnectorException, IOException{ + Map map = new HashMap<>(); + map.put("Action", "getallowance"); + map.put("Version", "1.0.0"); + map.put("Asset", asset); + map.put("From", from); + map.put("To", to); + map.put("Id", generateReqId()); + mWebSocket.send(JSON.toJSONString(map)); + return ""; + } + @Override + public Object getMemPoolTxCount() throws ConnectorException, IOException{ + Map map = new HashMap<>(); + map.put("Action", "getmempooltxcount"); + map.put("Version", "1.0.0"); + map.put("Id", generateReqId()); + mWebSocket.send(JSON.toJSONString(map)); + return ""; + } + @Override + public Object getMemPoolTxState(String hash) throws ConnectorException, IOException{ + Map map = new HashMap<>(); + map.put("Action", "getmempooltxstate"); + map.put("Version", "1.0.0"); + map.put("Hash", hash); + map.put("Id", generateReqId()); + mWebSocket.send(JSON.toJSONString(map)); + return ""; + } + @Override + public String getVersion() throws ConnectorException, IOException{ + Map map = new HashMap<>(); + map.put("Action", "getversion"); + map.put("Version", "1.0.0"); + map.put("Id", generateReqId()); + mWebSocket.send(JSON.toJSONString(map)); + return ""; + } + + @Override + public String getGrantOng(String address) throws ConnectorException, IOException { + Map map = new HashMap<>(); + map.put("Action", "getgrantong"); + map.put("Version", "1.0.0"); + map.put("Id", generateReqId()); + map.put("Addr", address); + mWebSocket.send(JSON.toJSONString(map)); + return ""; + } + + @Override + public int getNetworkId() throws ConnectorException, IOException { + Map map = new HashMap<>(); + map.put("Action", "getnetworkid"); + map.put("Version", "1.0.0"); + map.put("Id", generateReqId()); + mWebSocket.send(JSON.toJSONString(map)); + return 0; + } + @Override + public Object getNodeSyncStatus() throws ConnectorException, IOException { + Map map = new HashMap<>(); + map.put("Action", "getsyncstatus"); + map.put("Version", "1.0.0"); + map.put("Id", generateReqId()); + mWebSocket.send(JSON.toJSONString(map)); + return 0; + } + @Override + public String getSideChainData(String sideChainID) throws ConnectorException, IOException { + return null; + } + + public void wsStart() { + //request = new Request.Builder().url(WS_URL).build(); + String httpUrl = null; + if (wsUrl.contains("wss")) { + httpUrl = "https://" + wsUrl.split("://")[1]; + } else { + httpUrl = "http://" + wsUrl.split("://")[1]; + } + Request request = new Request.Builder().url(wsUrl).addHeader("Origin", httpUrl).build(); + OkHttpClient mClient = new OkHttpClient.Builder().build(); + mWebSocket = mClient.newWebSocket(request, new WebSocketListener() { + @Override + public void onOpen(WebSocket webSocket, Response response) { + System.out.println("opened websocket connection"); + sendHeartBeat(); + new Timer().schedule(new TimerTask() { + @Override + public void run() { + sendHeartBeat(); + } + }, 1000, 30000); + } + + @Override + public void onMessage(WebSocket webSocket, String s) { + if (logFlag) { + System.out.println("websoket onMessage:" + s); + } + Result result = JSON.parseObject(s, Result.class); + try { + synchronized (lock) { + MsgQueue.addResult(result); + lock.notify(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Override + public void onClosing(WebSocket webSocket, int code, String reason) { + System.out.println(reason); + } + + @Override + public void onClosed(WebSocket webSocket, int code, String reason) { + System.out.println("close:" + reason); + } + + @Override + public void onFailure(WebSocket webSocket, Throwable t, Response response) { + System.out.println("onFailure:" + response); + wsStart(); + } + }); + + } +} + From 80116f39a0097157639cc26b120d307d6e035ef3 Mon Sep 17 00:00:00 2001 From: xizho10 Date: Fri, 3 Jan 2020 20:56:47 +0800 Subject: [PATCH 09/18] update iml file --- DNA-java-sdk.iml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/DNA-java-sdk.iml b/DNA-java-sdk.iml index 7c55cc4..a0a6490 100644 --- a/DNA-java-sdk.iml +++ b/DNA-java-sdk.iml @@ -1,12 +1,5 @@ - - - - - - - @@ -15,9 +8,8 @@ - - + From b68de8a66f780917007f5c4a965c13eabc871b62 Mon Sep 17 00:00:00 2001 From: xizho10 Date: Fri, 3 Jan 2020 21:01:30 +0800 Subject: [PATCH 10/18] update pom file --- DNA-java-sdk.iml | 1 - pom.xml | 5 ----- 2 files changed, 6 deletions(-) diff --git a/DNA-java-sdk.iml b/DNA-java-sdk.iml index a0a6490..da3733c 100644 --- a/DNA-java-sdk.iml +++ b/DNA-java-sdk.iml @@ -25,6 +25,5 @@ - \ No newline at end of file diff --git a/pom.xml b/pom.xml index bea1770..f0c86f3 100644 --- a/pom.xml +++ b/pom.xml @@ -103,11 +103,6 @@ test - - org.fusesource.leveldbjni - leveldbjni-all - 1.8 - From ddfa93a9f78dec965bd4aa03490996f0471f7010 Mon Sep 17 00:00:00 2001 From: SheldonZhao Date: Fri, 3 Jan 2020 21:27:22 +0800 Subject: [PATCH 11/18] add maven plugin --- DNA-java-sdk.iml | 29 --------------------- pom.xml | 66 ++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 58 insertions(+), 37 deletions(-) delete mode 100644 DNA-java-sdk.iml diff --git a/DNA-java-sdk.iml b/DNA-java-sdk.iml deleted file mode 100644 index da3733c..0000000 --- a/DNA-java-sdk.iml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/pom.xml b/pom.xml index f0c86f3..a990376 100644 --- a/pom.xml +++ b/pom.xml @@ -47,7 +47,7 @@ - hellomyworld + sheldonzhao messixaviinsta0303@163.com DNA-java-sdk @@ -107,6 +107,17 @@ + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.7 + true + + ossrh + https://oss.sonatype.org/ + true + + org.apache.maven.plugins maven-compiler-plugin @@ -122,31 +133,70 @@ **/ConnectMgrTest.java - **/GasAssetTxTest.java + **/OntAssetTxTest.java **/MerkleVerifierTest.java - **/NativeDnaIdTxTest.java - **/GasTest.java + **/NativeOntIdTxTest.java + **/OngTest.java **/NeoVmTest.java **/AuthTest.java - **/WasmVmTest.java - org.apache.maven.plugins maven-source-plugin - 3.0.1 + 2.2.1 attach-sources - verify jar-no-fork + + org.apache.maven.plugins + maven-javadoc-plugin + + -Xdoclint:none + + 2.9.1 + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + + + + + java8-doclint-disabled + + [1.8,) + + + -Xdoclint:none + + + \ No newline at end of file From 2802c5d01d259dab3b9c2766a0035988eb17ad98 Mon Sep 17 00:00:00 2001 From: SheldonZhao Date: Fri, 3 Jan 2020 21:50:20 +0800 Subject: [PATCH 12/18] add maven plugin --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a990376..06a8a0f 100644 --- a/pom.xml +++ b/pom.xml @@ -113,7 +113,7 @@ 1.6.7 true - ossrh + DNA-java-sdk-release https://oss.sonatype.org/ true From a8d70a86b0eacc3074c71d4d1e26c28a9cb0c089 Mon Sep 17 00:00:00 2001 From: xizho10 Date: Fri, 3 Jan 2020 22:11:25 +0800 Subject: [PATCH 13/18] fix test code --- pom.xml | 6 +++--- .../com/github/DNAProject/sdk/manager/GasAssetTxTest.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 06a8a0f..d931869 100644 --- a/pom.xml +++ b/pom.xml @@ -133,10 +133,10 @@ **/ConnectMgrTest.java - **/OntAssetTxTest.java + **/GasAssetTxTest.java **/MerkleVerifierTest.java - **/NativeOntIdTxTest.java - **/OngTest.java + **/NativeDnaIdTxTest.java + **/GasTest.java **/NeoVmTest.java **/AuthTest.java diff --git a/src/test/java/com/github/DNAProject/sdk/manager/GasAssetTxTest.java b/src/test/java/com/github/DNAProject/sdk/manager/GasAssetTxTest.java index 86b7d7e..24be4e0 100644 --- a/src/test/java/com/github/DNAProject/sdk/manager/GasAssetTxTest.java +++ b/src/test/java/com/github/DNAProject/sdk/manager/GasAssetTxTest.java @@ -20,7 +20,7 @@ public class GasAssetTxTest { Account info2 = null; Account info3 = null; String password = "111111"; - String wallet = "OntAssetTxTest.json"; + String wallet = "GasAssetTxTest.json"; Account payer; @Before From 25fda15f400b6c9cbc3627458b7d27271538b6cc Mon Sep 17 00:00:00 2001 From: xizho10 Date: Fri, 3 Jan 2020 22:40:12 +0800 Subject: [PATCH 14/18] update pom file --- DNA-java-sdk.iml | 29 +++++++++++++++++++++++++++++ pom.xml | 32 ++++++++++++++++---------------- 2 files changed, 45 insertions(+), 16 deletions(-) create mode 100644 DNA-java-sdk.iml diff --git a/DNA-java-sdk.iml b/DNA-java-sdk.iml new file mode 100644 index 0000000..da3733c --- /dev/null +++ b/DNA-java-sdk.iml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index d931869..85db965 100644 --- a/pom.xml +++ b/pom.xml @@ -155,22 +155,22 @@ - - org.apache.maven.plugins - maven-javadoc-plugin - - -Xdoclint:none - - 2.9.1 - - - attach-javadocs - - jar - - - - + + + + + + + + + + + + + + + + org.apache.maven.plugins maven-gpg-plugin From 479ea4b584d847a0bf4f3866b1571ac8bd823cce Mon Sep 17 00:00:00 2001 From: xizho10 Date: Thu, 19 Mar 2020 23:23:18 +0800 Subject: [PATCH 15/18] fix getPrikeyFromMnemonicCodesStrBip44 bug --- src/main/java/com/github/DNAProject/crypto/MnemonicCode.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/github/DNAProject/crypto/MnemonicCode.java b/src/main/java/com/github/DNAProject/crypto/MnemonicCode.java index cfb4533..27fc85d 100644 --- a/src/main/java/com/github/DNAProject/crypto/MnemonicCode.java +++ b/src/main/java/com/github/DNAProject/crypto/MnemonicCode.java @@ -59,7 +59,7 @@ public static byte[] getPrikeyFromMnemonicCodesStrBip44(String mnemonicCodesStr) } byte[] seed = MnemonicCode.getSeedFromMnemonicCodesStr(mnemonicCodesStr); HdPrivateKey key = HdPrivateKey.fromSeed(seed,"Nist256p1 seed".getBytes(StandardCharsets.UTF_8), Bitcoin.MAIN_NET); - HdPrivateKey child = key.fromPath(); + HdPrivateKey child = key.fromPath().cKDpriv(0).cKDpriv(0); byte[] p = child.toByteArray(); byte[] tmp = new byte[32]; System.arraycopy(p, 46, tmp, 0, 32); From dd6e3c9ff91dc7dce970fed136744595b795bfba Mon Sep 17 00:00:00 2001 From: leej1012 Date: Wed, 4 Aug 2021 16:37:44 +0800 Subject: [PATCH 16/18] Add DnaId2 and CredentialRecord --- .../java/com/github/DNAProject/dnaid/ALG.java | 62 ++ .../DNAProject/dnaid/CredentialStatus.java | 19 + .../dnaid/CredentialStatusType.java | 6 + .../com/github/DNAProject/dnaid/DnaId2.java | 675 ++++++++++++++++++ .../github/DNAProject/dnaid/DnaIdPubKey.java | 8 + .../github/DNAProject/dnaid/DnaIdSigner.java | 19 + .../com/github/DNAProject/dnaid/Proof.java | 58 ++ .../github/DNAProject/dnaid/ProofPurpose.java | 6 + .../github/DNAProject/dnaid/PubKeyType.java | 50 ++ .../DNAProject/dnaid/PubKeyTypeFactory.java | 25 + .../com/github/DNAProject/dnaid/README.md | 641 +++++++++++++++++ .../github/DNAProject/dnaid/SignRequest.java | 26 + .../com/github/DNAProject/dnaid/Util.java | 51 ++ .../dnaid/VerifiableCredential.java | 87 +++ .../dnaid/VerifiablePresentation.java | 64 ++ .../DNAProject/dnaid/jwt/JWTCredential.java | 120 ++++ .../DNAProject/dnaid/jwt/JWTHeader.java | 34 + .../DNAProject/dnaid/jwt/JWTPayload.java | 81 +++ .../github/DNAProject/dnaid/jwt/JWTVC.java | 55 ++ .../github/DNAProject/dnaid/jwt/JWTVP.java | 47 ++ .../DNAProject/smartcontract/NeoVm.java | 27 + .../smartcontract/neovm/CredentialRecord.java | 350 +++++++++ .../smartcontract/neovm/abi/Parameter.java | 2 +- .../DNAProject/credential/CredentialTest.java | 301 ++++++++ .../DNAProject/credential/credentialTest.json | 1 + 25 files changed, 2814 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/github/DNAProject/dnaid/ALG.java create mode 100644 src/main/java/com/github/DNAProject/dnaid/CredentialStatus.java create mode 100644 src/main/java/com/github/DNAProject/dnaid/CredentialStatusType.java create mode 100644 src/main/java/com/github/DNAProject/dnaid/DnaId2.java create mode 100644 src/main/java/com/github/DNAProject/dnaid/DnaIdPubKey.java create mode 100644 src/main/java/com/github/DNAProject/dnaid/DnaIdSigner.java create mode 100644 src/main/java/com/github/DNAProject/dnaid/Proof.java create mode 100644 src/main/java/com/github/DNAProject/dnaid/ProofPurpose.java create mode 100644 src/main/java/com/github/DNAProject/dnaid/PubKeyType.java create mode 100644 src/main/java/com/github/DNAProject/dnaid/PubKeyTypeFactory.java create mode 100644 src/main/java/com/github/DNAProject/dnaid/README.md create mode 100644 src/main/java/com/github/DNAProject/dnaid/SignRequest.java create mode 100644 src/main/java/com/github/DNAProject/dnaid/Util.java create mode 100644 src/main/java/com/github/DNAProject/dnaid/VerifiableCredential.java create mode 100644 src/main/java/com/github/DNAProject/dnaid/VerifiablePresentation.java create mode 100644 src/main/java/com/github/DNAProject/dnaid/jwt/JWTCredential.java create mode 100644 src/main/java/com/github/DNAProject/dnaid/jwt/JWTHeader.java create mode 100644 src/main/java/com/github/DNAProject/dnaid/jwt/JWTPayload.java create mode 100644 src/main/java/com/github/DNAProject/dnaid/jwt/JWTVC.java create mode 100644 src/main/java/com/github/DNAProject/dnaid/jwt/JWTVP.java create mode 100644 src/main/java/com/github/DNAProject/smartcontract/neovm/CredentialRecord.java create mode 100644 src/test/java/com/github/DNAProject/credential/CredentialTest.java create mode 100644 src/test/java/com/github/DNAProject/credential/credentialTest.json diff --git a/src/main/java/com/github/DNAProject/dnaid/ALG.java b/src/main/java/com/github/DNAProject/dnaid/ALG.java new file mode 100644 index 0000000..f2abc3d --- /dev/null +++ b/src/main/java/com/github/DNAProject/dnaid/ALG.java @@ -0,0 +1,62 @@ +package com.github.DNAProject.dnaid; + +// EcdsaSecp224r1VerificationKey2019 ES224 ECDSA P-224 SHA-224 +// EcdsaSecp256r1VerificationKey2019 ES256 ECDSA P-256 SHA-256 +// EcdsaSecp384r1VerificationKey2019 ES384 ECDSA P-384 SHA-384 +// EcdsaSecp521r1VerificationKey2019 ES512 ECDSA P-521 SHA-512 +// EcdsaSecp256k1VerificationKey2019 ES256K ECDSA secp256k1 SHA-256 +// Ed25519VerificationKey2018 EdDSA EDDSA Curve25519 SHA-256 +// SM2VerificationKey2019 SM SM2 SM2P256V1 SM3 +public enum ALG { + ES224, ES256, ES384, ES512, ES256K, EdDSA, SM; + + public static final String TYPE_ECDSA = "ECDSA"; + public static final String TYPE_EDDSA = "EDDSA"; + public static final String TYPE_SM2 = "SM2"; + + public static final String CURVE_P224 = "P-224"; + public static final String CURVE_P256 = "P-256"; + public static final String CURVE_P384 = "P-384"; + public static final String CURVE_P521 = "P-521"; + public static final String CURVE_secp256k1 = "secp256k1"; + public static final String CURVE_Curve25519 = "Curve25519"; + public static final String CURVE_SM2P256V1 = "SM2P256V1"; + + public static final String HASH_224 = "SHA-224"; + public static final String HASH_256 = "SHA-256"; + public static final String HASH_384 = "SHA-384"; + public static final String HASH_512 = "SHA-512"; + public static final String HASH_SM3 = "SM3"; + + private PubKeyType pubKeyType; + + ALG() { + } + + public void setProofPubKeyType(PubKeyType pubKeyType) { + this.pubKeyType = pubKeyType; + } + + public PubKeyType proofPubKeyType() { + return pubKeyType; + } + +// public byte[] hash(byte[] msg) throws Exception { +// switch (this) { +// case ES224: +// return Digest.sha224(msg); +// case ES256: +// case ES256K: +// case EdDSA: +// return Digest.sha256(msg); +// case ES384: +// return Digest.sha384(msg); +// case ES512: +// return Digest.sha512(msg); +// case SM: +// return Digest.sm3(msg); +// default: +// throw new SDKException("unsupport hash method"); +// } +// } +} diff --git a/src/main/java/com/github/DNAProject/dnaid/CredentialStatus.java b/src/main/java/com/github/DNAProject/dnaid/CredentialStatus.java new file mode 100644 index 0000000..e1cecd3 --- /dev/null +++ b/src/main/java/com/github/DNAProject/dnaid/CredentialStatus.java @@ -0,0 +1,19 @@ +package com.github.DNAProject.dnaid; + + +import com.alibaba.fastjson.annotation.JSONType; + +@JSONType(orders = {"id", "type"}) +public class CredentialStatus { + + public String id; // should be CredentialRecord contract address + public CredentialStatusType type; + + public CredentialStatus() { + } + + public CredentialStatus(String scriptHash, CredentialStatusType type) { + this.id = scriptHash; + this.type = type; + } +} \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/dnaid/CredentialStatusType.java b/src/main/java/com/github/DNAProject/dnaid/CredentialStatusType.java new file mode 100644 index 0000000..1009a7f --- /dev/null +++ b/src/main/java/com/github/DNAProject/dnaid/CredentialStatusType.java @@ -0,0 +1,6 @@ +package com.github.DNAProject.dnaid; + +public enum CredentialStatusType { + AttestContract, + RevocationList +} diff --git a/src/main/java/com/github/DNAProject/dnaid/DnaId2.java b/src/main/java/com/github/DNAProject/dnaid/DnaId2.java new file mode 100644 index 0000000..5c2d8bc --- /dev/null +++ b/src/main/java/com/github/DNAProject/dnaid/DnaId2.java @@ -0,0 +1,675 @@ +package com.github.DNAProject.dnaid; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.dnaid.jwt.JWTCredential; +import com.github.DNAProject.dnaid.jwt.JWTHeader; +import com.github.DNAProject.dnaid.jwt.JWTPayload; +import com.github.DNAProject.sdk.exception.SDKException; +import com.github.DNAProject.smartcontract.nativevm.DnaId; +import com.github.DNAProject.smartcontract.neovm.CredentialRecord; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; + +public class DnaId2 { + public static final String CRED_DEFAULT_CONTEXT1 = "https://www.w3.org/2018/credentials/v1"; + public static final String CRED_DEFAULT_CONTEXT2 = "https://dnaid.ont.io/credentials/v1"; + + public static final String CRED_DEFAULT_TYPE = "VerifiableCredential"; + + public static final String PRESENTATION_DEFAULT_TYPE = "VerifiablePresentation"; + + public static final String CRED_COMMITTED = "01"; + public static final String CRED_REVOKED = "00"; + public static final String CRED_NOT_EXIST = "02"; + + private DnaIdSigner signer; + private CredentialRecord credRecord; + private DnaId dnaIdContract; + + public DnaIdSigner getSigner() { + return signer; + } + + public void setDnaIdAndSigner(DnaIdSigner signer) { + this.signer = signer; + } + + + // which index that signer public key corresponding in dnaId keys set + private int signerPubKeyIndex; + + public CredentialRecord getCredRecord() { + return credRecord; + } + + public void setCredRecord(CredentialRecord credRecord) { + this.credRecord = credRecord; + } + + public DnaId getDnaIdContract() { + return dnaIdContract; + } + + public void setDnaIdContract(DnaId dnaIdContract) { + this.dnaIdContract = dnaIdContract; + } + + public DnaId2(String dnaId, Account signer, CredentialRecord credRecord, DnaId dnaIdContract) throws Exception { + this.credRecord = credRecord; + this.dnaIdContract = dnaIdContract; + if (dnaId != null && !"".equals(dnaId) && signer != null) { + DnaIdPubKey pubKey = querySignerPubKey(dnaId, Helper.toHexString(signer.serializePublicKey())); + this.signer = new DnaIdSigner(dnaId, pubKey, signer); + } + } + + public void updateDnaIdAndSigner(String dnaId, Account signer) throws Exception { + DnaIdPubKey pubKey = querySignerPubKey(dnaId, Helper.toHexString(signer.serializePublicKey())); + this.signer = new DnaIdSigner(dnaId, pubKey, signer); + } + + private DnaIdPubKey querySignerPubKey(String dnaId, String hexPubKey) throws Exception { + String allPubKeysJson = dnaIdContract.sendGetPublicKeys(dnaId); + JSONArray allPubKeys = JSONArray.parseArray(allPubKeysJson); + String signerPubKey = hexPubKey.toLowerCase(); + for (Object pubKeyObj : allPubKeys) { + JSONObject pubKey = (JSONObject) pubKeyObj; + String publicKeyHex = pubKey.getString("publicKeyHex"); + String id = pubKey.getString("id"); + if (publicKeyHex == null) { + publicKeyHex = pubKey.getString("Value"); + id = pubKey.getString("PubKeyId"); + } + + String lowerCasePubKey = publicKeyHex.toLowerCase(); + if (signerPubKey.equals(lowerCasePubKey)) { + DnaIdPubKey dnaIdPubKey = new DnaIdPubKey(); + dnaIdPubKey.publicKeyHex = publicKeyHex; + dnaIdPubKey.id = id; + dnaIdPubKey.type = PubKeyType.EcdsaSecp256r1VerificationKey2019; + return dnaIdPubKey; + } + } + throw new SDKException("signer not found in dnaId"); + } + + public SignRequest genSignReq(Object credentialSubject, ProofPurpose proofPurpose, + boolean hasSignature) throws Exception { + if (hasSignature) { + Date current = new Date(); + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + formatter.setTimeZone(TimeZone.getTimeZone("UTC")); + Proof proof = new Proof(signer.pubKey.id, formatter.format(current), signer.pubKey.type, proofPurpose); + SignRequest signReq = new SignRequest(credentialSubject, signer.dnaId, proof); + proof.fillHexSignature(signer.signer, signReq.genNeedSignData()); + return signReq; + } else { + return new SignRequest(credentialSubject, signer.dnaId, null); + } + } + + public boolean verifySignReq(SignRequest req) throws Exception { + return verifyDnaIdSignature(req.dnaId, req.genNeedSignData(), req.proof.parseHexSignature()); + } + + public VerifiableCredential createCred(String[] context, String[] type, Object issuer, + Object credentialSubject, Date expiration, + CredentialStatusType credentialStatusType, + ProofPurpose proofPurpose) throws Exception { + if (credentialStatusType == CredentialStatusType.RevocationList) { + throw new SDKException("unsupported CredentialStatusType"); + } + VerifiableCredential credential = genCredentialWithoutSig(context, type, issuer, credentialSubject, + expiration, credentialStatusType, proofPurpose); + // generate proof + byte[] needSignData = credential.genNeedSignData(); + credential.proof.fillHexSignature(signer.signer, needSignData); + return credential; + } + + public String createJWTCred(String[] context, String[] type, Object issuer, Object credentialSubject, + Date expiration, CredentialStatusType statusType, ProofPurpose purpose) + throws Exception { + if (statusType == CredentialStatusType.RevocationList) { + throw new SDKException("unsupported CredentialStatusType"); + } + JWTHeader header = new JWTHeader(signer.pubKey.type.getAlg(), this.signer.pubKey.id); + JWTPayload payload = new JWTPayload(genCredentialWithoutSig(context, type, issuer, credentialSubject, + expiration, statusType, purpose)); // use default proof purpose + JWTCredential jwtCred = new JWTCredential(header, payload, signer.signer); + return jwtCred.toString(); + } + + private VerifiableCredential genCredentialWithoutSig(String[] context, String[] type, Object issuer, + Object credentialSubject, Date expiration, + CredentialStatusType statusType, ProofPurpose purpose) + throws Exception { + VerifiableCredential credential = new VerifiableCredential(); + ArrayList wholeContext = new ArrayList<>(); + wholeContext.add(CRED_DEFAULT_CONTEXT1); + wholeContext.add(CRED_DEFAULT_CONTEXT2); + if (context != null) { + wholeContext.addAll(Arrays.asList(context)); + } + credential.context = new String[]{}; + credential.context = wholeContext.toArray(credential.context); + ArrayList wholeType = new ArrayList<>(); + wholeType.add(CRED_DEFAULT_TYPE); + if (type != null) { + wholeType.addAll(Arrays.asList(type)); + } + credential.type = new String[]{}; + credential.type = wholeType.toArray(credential.type); + credential.credentialSubject = credentialSubject; + String issuerId = Util.fetchId(issuer); + if (!signer.dnaId.equals(issuerId)) { + throw new SDKException(String.format("param issuer %s vs self signer %s", issuerId, signer.dnaId)); + } + credential.issuer = issuer; + credential.credentialStatus = new CredentialStatus(credRecord.getContractAddress(), statusType); + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + formatter.setTimeZone(TimeZone.getTimeZone("UTC")); + Date current = new Date(); + credential.issuanceDate = formatter.format(current); + if (expiration != null) { + // check expiration + if (expiration.before(current)) { + throw new SDKException("cred expired"); + } + credential.expirationDate = formatter.format(expiration); + } + credential.proof = new Proof(signer.pubKey.id, credential.issuanceDate, signer.pubKey.type, purpose); + return credential; + } + + // self dnaId is issuer + // fetch index from cred.proof + // use self signer and payer to sign tx + // When multi-threaded calls are made, they need to be locked externally. + // The function itself does not provide asynchronous locks. + public String commitCred(VerifiableCredential cred, String ownerDnaId, Account payer, + long gasLimit, long gasPrice, DnaSdk sdk) throws Exception { + Transaction tx = credRecord.makeCommit2(signer.dnaId, ownerDnaId, cred.id, + Util.getIndexFromPubKeyURI(cred.proof.verificationMethod), payer.getAddressU160().toBase58(), + gasLimit, gasPrice); + sdk.addSign(tx, signer.signer); + sdk.addSign(tx, payer); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return ""; + } + + + public String commitCredById(String credId, String ownerDnaId, Account payer, + long gasLimit, long gasPrice, DnaSdk sdk) throws Exception { + Transaction tx = credRecord.makeCommit2(signer.dnaId, ownerDnaId, credId, + Util.getIndexFromPubKeyURI(signer.pubKey.id), payer.getAddressU160().toBase58(), + gasLimit, gasPrice); + sdk.addSign(tx, signer.signer); + sdk.addSign(tx, payer); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return ""; + } + + // @param cred: jwt format cred + public String commitCred(String cred, String ownerDnaId, Account payer, + long gasLimit, long gasPrice, DnaSdk sdk) throws Exception { + JWTCredential jwtCred = JWTCredential.deserializeToJWTCred(cred); + Transaction tx = credRecord.makeCommit2(signer.dnaId, ownerDnaId, jwtCred.payload.jti, + Util.getIndexFromPubKeyURI(jwtCred.header.kid), payer.getAddressU160().toBase58(), + gasLimit, gasPrice); + sdk.addSign(tx, signer.signer); + sdk.addSign(tx, payer); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return ""; + } + + public boolean verifyCred(String[] credibleDnaIds, VerifiableCredential cred) throws Exception { + if (!verifyCredDnaIdCredible(credibleDnaIds, cred)) { + return false; + } + if (!verifyCredDate(cred)) { + return false; + } + if (cred.proof == null) { + return false; + } + if (!verifyCredSignature(cred)) { + return false; + } + return verifyCredNotRevoked(cred); + } + + public boolean verifyJWTCred(String[] credibleDnaIds, String cred) throws Exception { + JWTCredential jwtCred = JWTCredential.deserializeToJWTCred(cred); + if (jwtCred.payload.vc == null) { + throw new SDKException("cred vc doesn't exist"); + } + if (!verifyJWTCredDnaIdCredible(credibleDnaIds, jwtCred)) { + return false; + } + if (!verifyJWTCredDate(jwtCred)) { + return false; + } + if (!verifyJWTCredSignature(jwtCred)) { + return false; + } + return verifyJWTCredNotRevoked(jwtCred); + } + + public boolean verifyCredDnaIdCredible(String[] credibleDnaIds, VerifiableCredential cred) { + // insure proof is generated by issuer + if (!cred.proof.verificationMethod.startsWith(cred.fetchIssuerDnaId())) { + return false; + } + for (String dnaId : + credibleDnaIds) { + // check dnaId equals + if (cred.proof.verificationMethod.startsWith(dnaId)) { + return true; + } + } + return false; + } + + public boolean verifyJWTCredDnaIdCredible(String[] credibleDnaIds, String cred) throws Exception { + JWTCredential jwtCred = JWTCredential.deserializeToJWTCred(cred); + return verifyJWTCredDnaIdCredible(credibleDnaIds, jwtCred); + } + + private boolean verifyJWTCredDnaIdCredible(String[] credibleDnaIds, JWTCredential jwtCred) { + for (String dnaId : + credibleDnaIds) { + // check dnaId equals + if (jwtCred.payload.iss.startsWith(dnaId)) { + return true; + } + } + return false; + } + + public boolean verifyCredDate(VerifiableCredential cred) throws Exception { + DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + formatter.setTimeZone(TimeZone.getTimeZone("UTC")); + Date current = new Date(); + if (cred.expirationDate != null && !cred.expirationDate.isEmpty()) { + Date expiration = formatter.parse(cred.expirationDate); + if (expiration.before(current)) { + return false; + } + } + if (cred.issuanceDate != null && !cred.issuanceDate.isEmpty()) { + Date issuanceDate = formatter.parse(cred.issuanceDate); + return issuanceDate.before(current); + } + return true; + } + + public boolean verifyCredExp(VerifiableCredential cred) throws Exception { + DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + formatter.setTimeZone(TimeZone.getTimeZone("UTC")); + Date current = new Date(); + if (cred.expirationDate != null && !cred.expirationDate.isEmpty()) { + Date expiration = formatter.parse(cred.expirationDate); + return expiration.after(current); + } + return true; + } + + public boolean verifyCredIssuanceDate(VerifiableCredential cred) throws Exception { + DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + formatter.setTimeZone(TimeZone.getTimeZone("UTC")); + Date current = new Date(); + if (cred.issuanceDate != null && !cred.issuanceDate.isEmpty()) { + Date issuanceDate = formatter.parse(cred.issuanceDate); + return issuanceDate.before(current); + } + return true; + } + + public boolean verifyJWTCredDate(String cred) throws Exception { + JWTCredential jwtCred = JWTCredential.deserializeToJWTCred(cred); + return verifyJWTCredDate(jwtCred); + } + + public boolean verifyJWTCredExp(String cred) throws Exception { + JWTCredential jwtCred = JWTCredential.deserializeToJWTCred(cred); + return verifyJWTCredExp(jwtCred); + } + + public boolean verifyJWTCredIssuanceDate(String cred) throws Exception { + JWTCredential jwtCred = JWTCredential.deserializeToJWTCred(cred); + return verifyJWTCredIssuanceDate(jwtCred); + } + + private boolean verifyJWTCredDate(JWTCredential jwtCred) { + return verifyJWTCredExp(jwtCred) && verifyJWTCredIssuanceDate(jwtCred); + } + + // if jwtCred.payload.exp < 0, consider it is invalid + private boolean verifyJWTCredExp(JWTCredential jwtCred) { + return jwtCred.payload.exp == 0 || jwtCred.payload.exp > System.currentTimeMillis() / 1000; + } + + private boolean verifyJWTCredIssuanceDate(JWTCredential jwtCred) { + long current = System.currentTimeMillis() / 1000; + if (jwtCred.payload.iat < 0 || jwtCred.payload.nbf < 0) { + return false; + } + if (current < jwtCred.payload.nbf) { + return false; + } + return current >= jwtCred.payload.iat; + } + + public boolean verifyCredSignature(VerifiableCredential cred) throws Exception { + return verifyPubKeyIdSignature(cred.fetchIssuerDnaId(), cred.proof.verificationMethod, + cred.genNeedSignData(), cred.proof.parseHexSignature()); + } + + public boolean verifyJWTCredSignature(String cred) throws Exception { + JWTCredential jwtCred = JWTCredential.deserializeToJWTCred(cred); + return verifyJWTCredSignature(jwtCred); + } + + private boolean verifyJWTCredSignature(JWTCredential jwtCred) throws Exception { + byte[] needSignData = jwtCred.genNeedSignData(); + byte[] signature = jwtCred.parseSignature(); + return verifyPubKeyIdSignature(jwtCred.payload.iss, jwtCred.header.kid, needSignData, signature); + } + + public boolean verifyCredNotRevoked(VerifiableCredential cred) throws Exception { + switch (cred.credentialStatus.type) { + case AttestContract: + String defaultContractAddr = this.credRecord.getContractAddress(); + this.credRecord.setContractAddress(cred.credentialStatus.id); + boolean notRevoked = CRED_COMMITTED.equals(this.credRecord.sendGetStatus2(cred.id)); + this.credRecord.setContractAddress(defaultContractAddr); + return notRevoked; + case RevocationList: // TODO: verify this + return false; + default: + return false; + } + } + + public boolean verifyJWTCredNotRevoked(String cred) throws Exception { + JWTCredential jwtCred = JWTCredential.deserializeToJWTCred(cred); + if (jwtCred.payload.vc == null) { + throw new SDKException("cred vc doesn't exist"); + } + return verifyJWTCredNotRevoked(jwtCred); + } + + private boolean verifyJWTCredNotRevoked(JWTCredential jwtCred) throws Exception { + switch (jwtCred.payload.vc.credentialStatus.type) { + case AttestContract: + String defaultContractAddr = this.credRecord.getContractAddress(); + this.credRecord.setContractAddress(jwtCred.payload.vc.credentialStatus.id); + boolean notRevoked = CRED_COMMITTED.equals(this.credRecord.sendGetStatus2(jwtCred.payload.jti)); + this.credRecord.setContractAddress(defaultContractAddr); + return notRevoked; + case RevocationList: + return false; + default: + return false; + } + } + + public VerifiablePresentation createPresentation(VerifiableCredential[] creds, String[] context, + String[] type, List challenge, + List domain, Object holder, + DnaIdSigner[] otherSigners, ProofPurpose proofPurpose) + throws Exception { + VerifiablePresentation presentation = genPresentationWithoutProof(creds, context, type, holder); + Date current = new Date(); + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + formatter.setTimeZone(TimeZone.getTimeZone("UTC")); + String currentTimeStamp = formatter.format(current); + ArrayList proofs = new ArrayList<>(); + ArrayList signers = new ArrayList<>(); + signers.add(signer); + if (otherSigners != null) { + signers.addAll(Arrays.asList(otherSigners)); + } + for (int i = 0; i < signers.size(); i++) { + DnaIdSigner signer = signers.get(i); + Proof p = new Proof(signer.pubKey.id, currentTimeStamp, signer.pubKey.type, proofPurpose, + challenge.get(i), domain.get(i)); + proofs.add(p); + } + presentation.proof = new Proof[]{}; + presentation.proof = proofs.toArray(presentation.proof); + for (int i = 0; i < proofs.size(); i++) { + Proof p = proofs.get(i); + byte[] needSignData = presentation.genNeedSignData(p); + p.fillHexSignature(signers.get(i).signer, needSignData); + } + presentation.proof = proofs.toArray(presentation.proof); + return presentation; + } + + // creds: jwt cred array + public String createJWTPresentation(String[] creds, String[] context, String[] type, Object holder, + String challenge, Object domain, ProofPurpose purpose) + throws Exception { + JWTHeader header = new JWTHeader(signer.pubKey.type.getAlg(), this.signer.pubKey.id); + VerifiableCredential[] credentials = new VerifiableCredential[creds.length]; + // check creds + for (int i = 0; i < creds.length; i++) { + JWTCredential jwtCred = JWTCredential.deserializeToJWTCred(creds[i]); + credentials[i] = VerifiableCredential.deserializeFromJWT(jwtCred); + } + DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + formatter.setTimeZone(TimeZone.getTimeZone("UTC")); + String created = formatter.format(new Date()); + Proof proof = new Proof(signer.pubKey.id, created, signer.pubKey.type, purpose, challenge, domain); + JWTPayload payload = new JWTPayload(genPresentationWithoutProof(credentials, context, type, holder), proof); + JWTCredential jwtCred = new JWTCredential(header, payload, signer.signer); + return jwtCred.toString(); + } + + // creds: old version jwt cred array + public String createPresentationFromOldCred(String[] creds, String[] context, String[] type, Object holder, + String challenge, Object domain, ProofPurpose purpose) + throws Exception { + JWTHeader header = new JWTHeader(signer.pubKey.type.getAlg(), this.signer.pubKey.id); + + DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + formatter.setTimeZone(TimeZone.getTimeZone("UTC")); + String created = formatter.format(new Date()); + Proof proof = new Proof(signer.pubKey.id, created, signer.pubKey.type, purpose, challenge, domain); + JWTPayload payload = new JWTPayload(genPresentationWithoutProof(null, context, type, holder), proof); + payload.vp.verifiableCredential = creds; + JWTCredential jwtCred = new JWTCredential(header, payload, signer.signer); + return jwtCred.toString(); + } + + private VerifiablePresentation genPresentationWithoutProof(VerifiableCredential[] creds, String[] context, + String[] type, Object holder) { + VerifiablePresentation presentation = new VerifiablePresentation(); + ArrayList wholeContext = new ArrayList<>(); + wholeContext.add(CRED_DEFAULT_CONTEXT1); + wholeContext.add(CRED_DEFAULT_CONTEXT2); + if (context != null) { + wholeContext.addAll(Arrays.asList(context)); + } + presentation.context = new String[]{}; + presentation.context = wholeContext.toArray(presentation.context); + ArrayList wholeType = new ArrayList<>(); + wholeType.add(PRESENTATION_DEFAULT_TYPE); + if (type != null) { + wholeType.addAll(Arrays.asList(type)); + } + presentation.type = new String[]{}; + presentation.type = wholeType.toArray(presentation.type); + presentation.verifiableCredential = creds; + presentation.holder = holder; + return presentation; + } + + public boolean verifyPresentationProof(VerifiablePresentation presentation, int proofIndex) throws Exception { + if (proofIndex >= presentation.proof.length) { + throw new SDKException(String.format("proof index %d out of bound %d", + proofIndex, presentation.proof.length)); + } + Proof proof = presentation.proof[proofIndex]; + // verify presentation proof + byte[] needSignData = presentation.genNeedSignData(proof); + return verifyPubKeyIdSignature(proof.verificationMethod, needSignData, proof.parseHexSignature()); + } + + public boolean verifyJWTPresentation(String[] credibleDnaIds, String presentation) throws Exception { + JWTCredential jwtCred = JWTCredential.deserializeToJWTCred(presentation); + if (jwtCred.payload.vp == null) { + throw new SDKException("invalid presentation"); + } + // check each payload.vc( VerifiableCredential ) + for (String vc : jwtCred.payload.vp.verifiableCredential) { + if (!verifyJWTCred(credibleDnaIds, vc)) { + return false; + } + } + // check jws + byte[] needSignData = jwtCred.genNeedSignData(); + byte[] signature = jwtCred.parseSignature(); + return verifyPubKeyIdSignature(jwtCred.header.kid, needSignData, signature); + } + + // issuer revoke cred + // When multi-threaded calls are made, they need to be locked externally. + // The function itself does not provide asynchronous locks. + public String revokeCred(VerifiableCredential cred, Account payer, + long gasLimit, long gasPrice, DnaSdk sdk) throws Exception { + if (cred.credentialStatus.type != CredentialStatusType.AttestContract) { + throw new SDKException(String.format("not support cred type %s", cred.credentialStatus.type)); + } + String defaultContractAddr = this.credRecord.getContractAddress(); + this.credRecord.setContractAddress(cred.credentialStatus.id); + Transaction tx = this.credRecord.makeRevoke2(signer.dnaId, cred.id, + Util.getIndexFromPubKeyURI(cred.proof.verificationMethod), + payer.getAddressU160().toBase58(), gasLimit, gasPrice); + sdk.addSign(tx, signer.signer); + sdk.addSign(tx, payer); + this.credRecord.setContractAddress(defaultContractAddr); + if (sdk.getConnect().sendRawTransaction(tx.toHexString())) { + return tx.hash().toHexString(); + } + return ""; + } + + + // owner revoke cred by cred id + // When multi-threaded calls are made, they need to be locked externally. + // The function itself does not provide asynchronous locks. + public String revokeCredById(String credId, Account payer, long gasLimit, long gasPrice, + DnaSdk sdk) throws Exception { + Transaction tx = this.credRecord.makeRevoke2(signer.dnaId, credId, + Util.getIndexFromPubKeyURI(signer.pubKey.id), payer.getAddressU160().toBase58(), gasLimit, gasPrice); + sdk.addSign(tx, signer.signer); + sdk.addSign(tx, payer); + if (sdk.getConnect().sendRawTransaction(tx.toHexString())) { + return tx.hash().toHexString(); + } + return ""; + } + + // owner revoke JWT cred + // When multi-threaded calls are made, they need to be locked externally. + // The function itself does not provide asynchronous locks. + public String revokeJWTCred(String cred, Account payer, long gasLimit, long gasPrice, + DnaSdk sdk) throws Exception { + JWTCredential jwtCred = JWTCredential.deserializeToJWTCred(cred); + Transaction tx = this.credRecord.makeRevoke2(signer.dnaId, jwtCred.payload.jti, + Util.getIndexFromPubKeyURI(signer.pubKey.id), payer.getAddressU160().toBase58(), gasLimit, gasPrice); + sdk.addSign(tx, signer.signer); + sdk.addSign(tx, payer); + if (sdk.getConnect().sendRawTransaction(tx.toHexString())) { + return tx.hash().toHexString(); + } + return ""; + } + + public String removeCredById(String credId, Account payer, long gasLimit, long gasPrice, DnaSdk sdk) + throws Exception { + Transaction tx = this.credRecord.makeRemove2(signer.dnaId, credId, + Util.getIndexFromPubKeyURI(signer.pubKey.id), payer.getAddressU160().toBase58(), gasLimit, gasPrice); + sdk.addSign(tx, signer.signer); + sdk.addSign(tx, payer); + if (sdk.getConnect().sendRawTransaction(tx.toHexString())) { + return tx.hash().toHexString(); + } + return ""; + } + + public String removeJWTCred(String cred, Account payer, long gasLimit, long gasPrice, + DnaSdk sdk) throws Exception { + JWTCredential jwtCred = JWTCredential.deserializeToJWTCred(cred); + Transaction tx = this.credRecord.makeRemove2(signer.dnaId, jwtCred.payload.jti, + Util.getIndexFromPubKeyURI(signer.pubKey.id), payer.getAddressU160().toBase58(), gasLimit, gasPrice); + sdk.addSign(tx, signer.signer); + sdk.addSign(tx, payer); + if (sdk.getConnect().sendRawTransaction(tx.toHexString())) { + return tx.hash().toHexString(); + } + return ""; + } + + public boolean verifyPubKeyIdSignature(String dnaId, String pubKeyId, byte[] needSignData, + byte[] signature) throws Exception { + if (!pubKeyId.startsWith(dnaId)) { + return false; + } + return verifyPubKeyIdSignature(pubKeyId, needSignData, signature); + } + + public boolean verifyPubKeyIdSignature(String pubKeyId, byte[] needSignData, + byte[] signature) throws Exception { + String dnaId = Util.getDnaIdFromPubKeyURI(pubKeyId); + String allPubKeysJson = dnaIdContract.sendGetPublicKeys(dnaId); + JSONArray allPubKeys = JSONArray.parseArray(allPubKeysJson); + for (Object pubKeyObj : allPubKeys) { + JSONObject pubKey = (JSONObject) pubKeyObj; + String publicKeyHex = pubKey.getString("publicKeyHex"); + String id = pubKey.getString("id"); + if (publicKeyHex == null) { + publicKeyHex = pubKey.getString("Value"); + id = pubKey.getString("PubKeyId"); + } + if (id.equals(pubKeyId)) { + Account account = new Account(false, Helper.hexToBytes(publicKeyHex)); + return account.verifySignature(needSignData, signature); + } + } + return false; + } + + public boolean verifyDnaIdSignature(String dnaId, byte[] needSignData, byte[] signature) throws Exception { + String allPubKeysJson = dnaIdContract.sendGetPublicKeys(dnaId); + ArrayList allPubKeys = new ArrayList<>(JSON.parseArray(allPubKeysJson, DnaIdPubKey.class)); + for (DnaIdPubKey pubKey : + allPubKeys) { + Account account = new Account(false, Helper.hexToBytes(pubKey.publicKeyHex)); + if (account.verifySignature(needSignData, signature)) { + return true; + } + } + return false; + } +} diff --git a/src/main/java/com/github/DNAProject/dnaid/DnaIdPubKey.java b/src/main/java/com/github/DNAProject/dnaid/DnaIdPubKey.java new file mode 100644 index 0000000..07f3e9f --- /dev/null +++ b/src/main/java/com/github/DNAProject/dnaid/DnaIdPubKey.java @@ -0,0 +1,8 @@ +package com.github.DNAProject.dnaid; + +public class DnaIdPubKey { + public String id; // pubkey URI + public PubKeyType type; // pubkey type, for example: EcdsaSecp256r1VerificationKey2019 + public String controller; + public String publicKeyHex; +} diff --git a/src/main/java/com/github/DNAProject/dnaid/DnaIdSigner.java b/src/main/java/com/github/DNAProject/dnaid/DnaIdSigner.java new file mode 100644 index 0000000..2042ea1 --- /dev/null +++ b/src/main/java/com/github/DNAProject/dnaid/DnaIdSigner.java @@ -0,0 +1,19 @@ +package com.github.DNAProject.dnaid; + +import com.github.DNAProject.account.Account; + +public class DnaIdSigner { + String dnaId; + DnaIdPubKey pubKey; + Account signer; + + public DnaIdSigner(String dnaId, DnaIdPubKey pubKey, Account signer) { + this.dnaId = dnaId; + this.pubKey = pubKey; + this.signer = signer; + } + +// public byte[] hash(byte[] msg) throws Exception { +// return pubKey.type.getAlg().hash(msg); +// } +} diff --git a/src/main/java/com/github/DNAProject/dnaid/Proof.java b/src/main/java/com/github/DNAProject/dnaid/Proof.java new file mode 100644 index 0000000..0689313 --- /dev/null +++ b/src/main/java/com/github/DNAProject/dnaid/Proof.java @@ -0,0 +1,58 @@ +package com.github.DNAProject.dnaid; + +import com.alibaba.fastjson.annotation.JSONType; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Helper; + +@JSONType(orders = {"type", "created", "challenge", "domain", "proofPurpose", "verificationMethod", "hex", "jws"}) +public class Proof { + public PubKeyType type; + public String created; // time stamp + public String challenge; + public Object domain; + public ProofPurpose proofPurpose; + public String verificationMethod; // pubkey uri + public String hex; + public String jws; + + public Proof() { + } + + public Proof(String publicKeyURI, String created, PubKeyType type, ProofPurpose proofPurpose) { + this.type = type; + this.created = created; + if (proofPurpose == null) { + proofPurpose = ProofPurpose.assertionMethod; + } + this.proofPurpose = proofPurpose; + this.verificationMethod = publicKeyURI; + } + + public Proof(String publicKeyURI, String created, PubKeyType type, ProofPurpose proofPurpose, + String challenge, Object domain) { + this(publicKeyURI, created, type, proofPurpose); + this.challenge = challenge; + this.domain = domain; + } + + public Proof genNeedSignProof() { + return new Proof(verificationMethod, created, type, proofPurpose, challenge, domain); + } + + public Proof genJWTProof() { + Proof proof = new Proof(); + proof.created = created; + proof.proofPurpose = proofPurpose; + proof.hex = hex; + return proof; + } + + public void fillHexSignature(Account account, byte[] needSignData) throws Exception { + byte[] sig = account.generateSignature(needSignData, account.getSignatureScheme(), null); + hex = Helper.toHexString(sig); + } + + public byte[] parseHexSignature() { + return Helper.hexToBytes(hex); + } +} diff --git a/src/main/java/com/github/DNAProject/dnaid/ProofPurpose.java b/src/main/java/com/github/DNAProject/dnaid/ProofPurpose.java new file mode 100644 index 0000000..c20bf28 --- /dev/null +++ b/src/main/java/com/github/DNAProject/dnaid/ProofPurpose.java @@ -0,0 +1,6 @@ +package com.github.DNAProject.dnaid; + +public enum ProofPurpose { + assertionMethod +} +// TODO: authentication diff --git a/src/main/java/com/github/DNAProject/dnaid/PubKeyType.java b/src/main/java/com/github/DNAProject/dnaid/PubKeyType.java new file mode 100644 index 0000000..f04b15d --- /dev/null +++ b/src/main/java/com/github/DNAProject/dnaid/PubKeyType.java @@ -0,0 +1,50 @@ +package com.github.DNAProject.dnaid; + +import com.github.DNAProject.crypto.SignatureScheme; + +public enum PubKeyType { + EcdsaSecp224r1VerificationKey2019(ALG.ES224, ALG.TYPE_ECDSA, ALG.CURVE_P224, ALG.HASH_224, SignatureScheme.SHA224WITHECDSA), + EcdsaSecp256r1VerificationKey2019(ALG.ES256, ALG.TYPE_ECDSA, ALG.CURVE_P256, ALG.HASH_256, SignatureScheme.SHA256WITHECDSA), + EcdsaSecp384r1VerificationKey2019(ALG.ES384, ALG.TYPE_ECDSA, ALG.CURVE_P384, ALG.HASH_384, SignatureScheme.SHA384WITHECDSA), + EcdsaSecp521r1VerificationKey2019(ALG.ES512, ALG.TYPE_ECDSA, ALG.CURVE_P521, ALG.HASH_512, SignatureScheme.SHA512WITHECDSA), + EcdsaSecp256k1VerificationKey2019(ALG.ES256K, ALG.TYPE_ECDSA, ALG.CURVE_secp256k1, ALG.HASH_256, SignatureScheme.SHA256WITHECDSA), + Ed25519VerificationKey2018(ALG.EdDSA, ALG.TYPE_EDDSA, ALG.CURVE_Curve25519, ALG.HASH_256, null), + SM2VerificationKey2019(ALG.SM, ALG.TYPE_SM2, ALG.CURVE_SM2P256V1, ALG.HASH_SM3, SignatureScheme.SM3WITHSM2); + + private ALG alg; + private String algType; + private String curve; + private String hashMethod; + private SignatureScheme signatureScheme; + + PubKeyType(ALG alg, String algType, String curve, String hashMethod, SignatureScheme scheme) { + this.alg = alg; + this.algType = algType; + this.curve = curve; + this.hashMethod = hashMethod; + this.signatureScheme = scheme; + + // inject self to alg pub key type + alg.setProofPubKeyType(this); + } + + public ALG getAlg() { + return alg; + } + + public String getAlgType() { + return algType; + } + + public String getCurve() { + return curve; + } + + public String getHashMethod() { + return hashMethod; + } + + public SignatureScheme getSignatureScheme() { + return signatureScheme; + } +} diff --git a/src/main/java/com/github/DNAProject/dnaid/PubKeyTypeFactory.java b/src/main/java/com/github/DNAProject/dnaid/PubKeyTypeFactory.java new file mode 100644 index 0000000..f54dfdc --- /dev/null +++ b/src/main/java/com/github/DNAProject/dnaid/PubKeyTypeFactory.java @@ -0,0 +1,25 @@ +package com.github.DNAProject.dnaid; + +import com.github.DNAProject.sdk.exception.SDKException; + +public class PubKeyTypeFactory { + public static PubKeyType genPubKeyType(String pubKeyType) throws Exception { + if ("EcdsaSecp224r1VerificationKey2019".equals(pubKeyType)) { + return PubKeyType.EcdsaSecp224r1VerificationKey2019; + } else if ("EcdsaSecp256r1Signature2019".equals(pubKeyType)) { + return PubKeyType.EcdsaSecp256r1VerificationKey2019; + } else if ("EcdsaSecp384r1VerificationKey2019".equals(pubKeyType)) { + return PubKeyType.EcdsaSecp384r1VerificationKey2019; + } else if ("EcdsaSecp521r1VerificationKey2019".equals(pubKeyType)) { + return PubKeyType.EcdsaSecp521r1VerificationKey2019; + } else if ("EcdsaSecp256k1VerificationKey2019".equals(pubKeyType)) { + return PubKeyType.EcdsaSecp256k1VerificationKey2019; + } else if ("Ed25519VerificationKey2018".equals(pubKeyType)) { + return PubKeyType.Ed25519VerificationKey2018; + } else if ("SM2VerificationKey2019".equals(pubKeyType)) { + return PubKeyType.SM2VerificationKey2019; + } else { + throw new SDKException("un support pub key type"); + } + } +} diff --git a/src/main/java/com/github/DNAProject/dnaid/README.md b/src/main/java/com/github/DNAProject/dnaid/README.md new file mode 100644 index 0000000..2e1edff --- /dev/null +++ b/src/main/java/com/github/DNAProject/dnaid/README.md @@ -0,0 +1,641 @@ +# Ontology Verifiable Credential 2.0 Java SDK + +## Role + +owner: credential owner, who hold some credentials and create presentation; + +issuer: credential issuer, who issue credential; + +verifier: credential verifier, who verify credential and presentation. + +## Class Specification + +There are two formats of verifiable credential, `JSON-LD` and `JWT`. + +Refer: https://www.w3.org/TR/vc-data-model/#basic-concepts +Refer: https://www.w3.org/TR/vc-data-model/#json-web-token + +### JSON-LD Format + +#### CredentialStatus + +[code](./VerifiableCredential.java#L30) + +Refer: https://www.w3.org/TR/vc-data-model/#status + +There are two type credential status now, `AttestContract` and `RevocationList`. + +If `CredentialStatus.type` equals `AttestContract`, `CredentialStatus.id` should be `CredentialRecord` contract address. + +#### VerifiableCredential + +[code](./VerifiableCredential.java) + +Refer: https://www.w3.org/TR/vc-data-model/#basic-concepts + +VerifiableCredential.issuer: issuer ontId. + +#### Proof + +[code](./Proof.java) + +Refer: https://www.w3.org/TR/vc-data-model/#proofs-signatures + +Proof.type: an instance of `PubKeyType`; + +ProofPurpose: only use `assertionMethod` at currently; + +Proof.verificationMethod: pubkey uri, like:`did:ont:AVe4zVZzteo6HoLpdBwpKNtDXLjJBzB9fv#keys-2`; + +Proof.hex: hex-encoded ontology signature; + +Proof.jws: jws-encoded ontology signature; + +#### VerifiablePresentation + +[code](./VerifiablePresentation.java) + +Refer: https://www.w3.org/TR/vc-data-model/#presentations-0 + +VerifiablePresentation.holder: maybe an ontId of String type or an object that has "id" attribute and "id" must be ontId. + +### JWT Format + +#### JWTCredential + +[code](./jwt/JWTCredential.java) + +The verifiable credential with JWT format. + +#### JWTHeader + +[code](./jwt/JWTHeader.java) + +Refer: https://www.w3.org/TR/vc-data-model/#example-30-jwt-header-of-a-jwt-based-verifiable-presentation-non-normative + +The JWT header. + +#### JWTPayload + +[code](./jwt/JWTPayload.java) + +Refer: https://www.w3.org/TR/vc-data-model/#example-31-jwt-payload-of-a-jwt-based-verifiable-presentation-non-normative + +The JWT payload. + +#### JWTVC + +[code](./jwt/JWTVC.java) + +Refer: https://www.w3.org/TR/vc-data-model/#json-web-token-extensions + +The all attributes of `VerifiableCredential` that not contained in JWT payload should be defined in `JWTVC`. + +#### JWTVP + +[code](./jwt/JWTVP.java) + +Refer: https://www.w3.org/TR/vc-data-model/#json-web-token-extensions + +The all attributes of `VerifiablePresentation` that not contained in JWT payload should be defined in `JWTVP`. + +### Util Class + +There are some utility class. + +#### SignRequest + +[code](./SignRequest.java) + +Credential owner send `SignRequest` to issuer to create credential. + +#### OntIdPubKey + +[code](./OntIdPubKey.java) + +It's a utility class, represent one public key of ontId. + +#### OntIdSigner + +[code](./OntIdSigner.java) + +It's a utility class, represent ontId signer. + +#### PubKeyType + +[code](./PubKeyType.java) + +OntId controller pubkey type. + +#### ALG + +[code](./jwt/ALG.java) + +Defined `jwt.header.alg`. Each `PubKeyType` has a corresponding `ALG`, each ALG has {algorithm type, curve type, hash method}. + +The corresponding relationship is as follows: + +| PubKeyType | ALG | Algorithm | Curve | Hash Method | +|------------|-----|-----------|-------|-------------| +| EcdsaSecp224r1VerificationKey2019 | ES224 | ECDSA | P-224 | SHA-224 | +| EcdsaSecp256r1VerificationKey2019 | ES256 | ECDSA | P-256 | SHA-256 | +| EcdsaSecp384r1VerificationKey2019 | ES384 | ECDSA | P-384 | SHA-384 | +| EcdsaSecp521r1VerificationKey2019 | ES512 | ECDSA | P-521 | SHA-512 | +| EcdsaSecp256k1VerificationKey2019 | ES256K | ECDSA | secp256k1 | SHA-256 | +| Ed25519VerificationKey2018 | EdDSA | EDDSA | Curve25519 | SHA-256 | +| SM2VerificationKey2019 | SM | SM2 | SM2P256V1 | SM3 | + +#### Util + +[code](./Util.java) + +Providing some static method. + +### SDK + +The OntId2 class is Ontology Verifiable Credential 2.0 protocol SDK class. + +#### OntId2 + +[code](./OntId2.java) + +It's ONTID2 SDK class, all Ontology Verifiable Credential 2.0 function should entry from here. + +OntId2.CredentialRecord: credential record contract; + +OntId2.OntId: ontId contract. + +## API + +There are many interfaces to use Ontology Verifiable Credential 2.0 protocol. + +### Constructor and Updater + +1. **public OntId2(String ontId, Account signer, CredentialRecord credRecord, OntId ontIdContract)** + + Generate OntId2 object. + + If `ontId` not empty and `signer` not null, there will query `OntIdPubKey` from ontology chain and use it as self signer. + + So owner and issuer should set `ontId` and `signer` while create OntId2 object, and verifier may not set those. + +2. **public void updateOntIdAndSigner(String ontId, Account signer)** + + Update `ontId` and `signer` account. + +### GenSignRequest and VerifySignRequest + +1. **public SignRequest genSignReq(Object credentialSubject, ProofPurpose proofPurpose, boolean hasSignature)** + + * generate `SignRequest` object, calculate its' hash; + * if hasSignature, use self `signer` to sign hash; + * return SignRequest object. + +2. **public boolean verifySignReq(SignRequest req)** + + * use `req.ontId` to verify `req.signature` of `req`. + +### Create Credential + +Issuer create credential. + +1. **public VerifiableCredential createCred(String[] context, String[] type, Object issuer, + Object credentialSubject, Date expiration, + CredentialStatusType credentialStatusType, + ProofPurpose proofPurpose)** + + comment: + + * create VerifiableCredential object; + * check `expiration`; + * check `issuer` equals self signer ontId; + * generate `Proof`. + + param: + + * context: refer w3c definition; + * type: refer w3c definition; + * issuer: maybe an ontId of String type or an object that has "id" attribute and "id" must be ontId; + * credentialSubject: refer w3c definition; + * expiration: refer w3c definition; + * credentialStatusType: only use `AttestContract` and `RevocationList` at current; + * proofPurpose: only use `assertionMethod` at current; + + return: `VerifiableCredential` + +2. **public String createJWTCred(String[] context, String[] type, Object issuer, Object credentialSubject, + Date expiration, CredentialStatusType statusType, ProofPurpose purpose)** + + comment: + + * parse params to JWT header and payload; + * generate jws. + + param: same with above. + + return: JWT credential. + +### Commit Credential + +Issuer commit credential hash to ontology chain. + +1. **public String commitCred(VerifiableCredential cred, String ownerOntId, Account payer, long gasLimit, + long gasPrice, OntSdk sdk)** + + comment: issuer invoke this method to commit a verifiable credential(JSON-LD) to ontology chain, issuer should use self + ontId to sign this transaction. + + param: + + * cred: a instance of verifiable credential; + * ownerOntId: ontId of credential owner; + * payer: transaction payer; + * gasLimit & gasPrice: transaction gas limit and price; + * sdk: a instance of OntSdk. + + return: transaction hash. + +2. **public String commitCred(String cred, String ownerOntId, Account payer, + long gasLimit, long gasPrice, OntSdk sdk)** + + comment: issuer invoke this method to commit a verifiable credential(JWT) to ontology chain, issuer should use self + ontId to sign this transaction. + + param: `cred` is JWT verifiable credential, the others params are same with the former. + +3. **public String commitCredById(String credId, String ownerOntId, Account payer, + long gasLimit, long gasPrice, OntSdk sdk)** + + comment: commit a credential to ontology chain. + + param: `credId` is identification of credential, others param are same with above. + +### Verify Credential + +Verifier could verify credential. + +The process consists of 4 aspects: `verifyCredOntIdCredible`, `verifyCredNotExpired`, `verifyCredSignature`, `verifyCredNotRevoked`. + +1. **public boolean verifyCred(String[] credibleOntIds, VerifiableCredential cred)** + + comment: Verify credential from four aspects. + + param: + + * credibleOntIds: credible ONTID list, similar to trust certificate; + * cred: instance of `VerifiableCredential`. + + return: boolean value of whether credential valid or invalid. + +2. **public boolean verifyJWTCred(String[] credibleOntIds, String cred)** + + comment: verify JWT credential; + + param: + + * credibleOntIds: credible ONTID list, similar to trust certificate; + * cred: `cred` is JWT format of verifiable credential. + + return: boolean value of whether credential valid or invalid. + +#### Verify Credential OntId Is Credible + +1. **public boolean verifyCredOntIdCredible(String[] credibleOntIds, VerifiableCredential cred)** + + comment: + + * check `cred.proof.verificationMethod` is `cred.issuer`; + * check `cred.proof.verificationMethod` is existed in `credibleOntIds`. + + param: + + * credibleOntIds: credible ONTID list, similar to trust certificate; + * cred: a instance of `VerifiableCredential`. + + return: boolean. + +2. **public boolean verifyJWTCredOntIdCredible(String[] credibleOntIds, String cred)** + + comment: verify `cred.payload.iss` existed in credibleOntIds. + + param: `cred` is JWT format of verifiable credential. + + return: boolean. + +#### Verify Credential Not Expired + +1. **public boolean verifyCredDate(VerifiableCredential cred)** + + comment: check credential not expired, check credential issuance date before current. + + param: `cred` is an instance of `VerifiableCredential`. + + return: boolean. + +2. **public boolean verifyJWTCredDate(String cred)** + + comment: check `cred.payload.exp` not expired, check `cred.payload.iat` and `cred.payload.nbf` before current. + + param: `cred` is JWT format of verifiable credential. + + return: boolean. + +#### Verify Credential Signature Is Valid + +1. **public boolean verifyCredSignature(VerifiableCredential cred)** + + comment: + + * check `cred.proof.verificationMethod` is `cred.issuer`; + * use `cred.proof.verificationMethod` as public key to verify `cred.proof`. + + param: `cred` is an instance of `VerifiableCredential`. + + return: boolean. + +2. **public boolean verifyJWTCredSignature(String cred)** + + comment: verify JWT credential signature valid. + + param: `cred` is JWT format of verifiable credential. + + return: value. + +#### Verify Credential Has Not Been Revoked + +1. **public boolean verifyCredNotRevoked(VerifiableCredential cred)** + + comment: + + * query status of credential from `CredentialRecord` contract that identified by `cred.credentialStatus.id` if + `cred.credentialStatus.type == AttestContract`; + * check status equals `01`. + + param: + + * cred: a instance of `VerifiableCredential`. + + return: boolean. + +2. **public boolean verifyJWTCredNotRevoked(String cred)** + + comment: + + * deserialize `cred` to `JWTCredential` instance; + * query status of credential from `CredentialRecord` contract that identified by `cred.credentialStatus.id` if + `cred.credentialStatus.type == AttestContract`; + * check status equals `01`. + + param: `cred` is JWT format of verifiable credential. + + return: boolean value. + +### Create Presentation + +Refer: https://www.w3.org/TR/vc-data-model/#presentations-0. + +Owner could create presentation by using one or multi `VerifiableCredential`. + +1. **public VerifiablePresentation createPresentation(VerifiableCredential[] creds, String[] context, + String[] type, List`<`String`>` challenge, + List`<`Object`>` domain, Object holder, + OntIdSigner[] otherSigners, ProofPurpose proofPurpose)** + + comment: + + * create `VerifiablePresentation` object; + * use self signer to generate first proof; + * use `otherSigners` to generate other proofs. + + param: + + * creds: array instance of verifiable credential; + * context: refer w3c definition; + * type: refer w3c definition; + * challenge: each proof should contain a challenge to prevent replay attack; + * domain: like challenge; + * holder: maybe an ontId of String type or an object that has "id" attribute and "id" must be ontId; + * otherSigners: presentation could own multi proof, so there would be other signer to sign presentation; + * proofPurpose: only use `assertionMethod` at current; + + return: instance of `VerifiablePresentation`. + +2. **public String createJWTPresentation(String[] creds, String[] context, String[] type, Object holder, + String challenge, Object domain, String nonce, ProofPurpose purpose)** + + comment: use multi `VerifiableCredential` instance to create a JWT credential. + + param: + + * creds: `creds` is array of JWT `VerifiableCredential`. Others params are same with above; + * context: same with above; + * type: same with above; + * challenge: JWT presentation only has one jws, so there only need one challenge; + * domain: like challenge; + * holder: same with above; + * nonce: refer w3c specification; + * proofPurpose: only use `assertionMethod` at current; + + return: a JWT format of `VerifiablePresentation`. + +### Verify Presentation + +Verifier could verify presentation. + +1. **public boolean verifyPresentationProof(VerifiablePresentation presentation, int proofIndex)** + + comment: check proof at `presentation.proof[proofIndex]` is valid. + + param: + + * presentation: an instance of `VerifiablePresentation`; + * proofIndex: the index of destination proof at `presentation.proof`. + + return: boolean value. + +2. **public boolean verifyJWTPresentation(String[] credibleOntIds, String presentation)** + + comment: + + * parse `presentation` to `JWTCredential`; + * verify each `JWTCredential.vc`; + * verify `JWTCredential.jws`. + + param: + + * credibleOntIds: array of credible ontId; + * presentation: a JWT string of `VerifiablePresentation`. + + return: boolean value. + +### Revoke Credential + +Because the SDK used by different roles, so we encapsulate a credential revoking interface. User would use these interface at different circumstance. + +1. **public String revokeCred(VerifiableCredential cred, Account payer, + long gasLimit, long gasPrice, OntSdk sdk)** + + comment: revoke a credential by an instance of `VerifiableCredential`. + + param: + + * cred: an instance of `VerifiableCredential`; + * payer: transaction payer; + * gasLimit & gasPrice: transaction param; + * sdk: an instance of `OntSdk`; + + return: transaction hash of revoking credential. + +2. **public String revokeCredById(String credId, Account payer, long gasLimit, long gasPrice, + OntSdk sdk)** + + comment: revoke credential by credential id. + + param: `credId` is identification of credential, others param are same with above; + + return: transaction hash of revoking credential. + +3. **public String revokeJWTCred(String cred, Account payer, long gasLimit, long gasPrice, + OntSdk sdk)** + + comment: revoke credential by JWT format credential. + + * parse credential to `JWTCredential` instance; + * use `JWTCredential.payload.jti` to revoke this credential; + + param: `cred` is a JWT format of `VerifiableCredential` or `VerifiablePresentation`. Others param are same with above. + + return: transaction hash of revoking credential. + +### Remove Credential + +1. **public String removeCredById(String credId, Account payer, long gasLimit, long gasPrice, OntSdk sdk)** + + comment: remove credential by credential id. + + param: `credId` is identification of credential, other params are ontology transaction param; + + return: transaction hash of remove credential. + +2. **public String removeJWTCred(String cred, Account payer, long gasLimit, long gasPrice, OntSdk sdk)** + + comment: remove a JWT credential. + + param: `cred` is JWT format of credential, other params are ontology transaction param; + + return: transaction hash of remove credential. + +### Transition between JSON-LD and JWT + +We also provide some interface to parse verifiable credential between the format of JSON-LD and JWT. + +#### Parse JSON-LD to JWT + +1. **public JWTCredential(VerifiableCredential credential)** + + comment: + + * check `credential.proof.jws` is empty; + * parse `jwt.header`; + * parse `jwt.payload`; + * retrieve `credential.proof.jws`. + + param: `credential` is an instance of `VerifiableCredential`. + + return: an instance of `JWTCredential`. + +2. **public JWTCredential(VerifiablePresentation presentation, Proof proof, String nonce)** + + comment: Because there maybe many proof in presentation, you must specify the proof instance when you want to parse + `VerifiablePresentation` instance to JWT. + + param: + + * presentation: an instance of `VerifiablePresntation`; + * proof: an instance of `Proof`; + * nonce: refer w3c specification; + deserializeToJWTCred + return: an instance of `JWTCredential` that represent `VerifiablePresntation`. + +3. **public static JWTCredential deserializeToJWTCred(String jwt)** + + comment: deserialize a jwt string to `JWTCredential` object. + + param: a JWT format string of `VerifiableCredential` or `VerifiablePresentation`. + + return: an instance of `JWTCredential`. + +#### Parse JWT to JSON-LD + +1. **public static VerifiableCredential deserializeFromJWT(JWTCredential cred)** + + comment: parse `JWTCredential` to `VerifiableCredential`; + + param: `cred` is an instance of `JWTCredential`; + + return: an instance of `VerifiableCredential`. + +2. **public static VerifiablePresentation deserializeFromJWT(JWTCredential cred)** + + comment: parse `JWTCredential` to `VerifiablePresentation`; + + param: `cred` is an instance of `JWTCredential`; + + return: an instance of `VerifiableCredential`. + +## Credential Record Contract + +[code](../smartcontract/neovm/CredentialRecord.java) + +Ontology Verifiable Credential 2.0 use a new version CredentialRecord contract. There are 4 new interface. + +### Commit + +**public String sendCommit2(String issuerOntid, String password, byte[] salt, String subjectOntid, String credId, int pubkeyIndex, Account payerAcct, long gaslimit, long gasprice)** + +Used to commit a credential id to ontology chain. + +### Revoke + +**public String sendRevoke2(String ownerId, String password, byte[] salt, String credId, int pubkeyIndex, Account payerAcct, long gaslimit, long gasprice)** + +Used to revoke a recorded credential id. + +### Remove + +**public String sendRemove2(String ownerId, String password, byte[] salt, String credId, int pubkeyIndex, Account payerAcct, long gaslimit, long gasprice)** + +Used to remove a recorded credential id. + +### GetStatus + +**public String sendGetStatus2(String credId)** + +Used to query credential status by cred id, there are 3 return value: + +* "00": revoked. +* "01": committed; +* "02": removed; + +## Compatibility + +Considering that there are a lot of old version of credential, the protocol upgrade must be compatible with old data. The main +difference between the new and old protocol is in the form of credential. + +The old ONTID protocol use [OntId](../smartcontract/nativevm/OntId.java) to generate and verify credential. However, the new +use [OntId2](./OntId2.java) to generate and verify credential. + +In the other hands, we also provide the methods that verify old credential by new CredentialRecord contract: + +* **public boolean verifyCredOntIdCredible(String cred, String[] credibleIds)** +* **public boolean verifyCredNotExpired(String cred)** +* **public boolean verifyCredSignature(String cred)** +* **public boolean verifyCredNotRevoked(String cred)** + +See these code at [here](../smartcontract/nativevm/OntId.java#L2186-L2258). + +## How to Use + +The [document](./how%20to%20use.md) is a simple introduction about how to use Ontology Verifiable Credential 2.0. + +There are some [code](../../../../demo/OntId2Demo.java) to illustrate how to use Ontology Verifiable Credential 2.0 sdk. \ No newline at end of file diff --git a/src/main/java/com/github/DNAProject/dnaid/SignRequest.java b/src/main/java/com/github/DNAProject/dnaid/SignRequest.java new file mode 100644 index 0000000..4c378d5 --- /dev/null +++ b/src/main/java/com/github/DNAProject/dnaid/SignRequest.java @@ -0,0 +1,26 @@ +package com.github.DNAProject.dnaid; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONType; +import com.alibaba.fastjson.serializer.SerializerFeature; + +@JSONType(orders = {"credentialSubject", "dnaId", "proof"}) +public class SignRequest { + Object credentialSubject; + String dnaId; + Proof proof; + + public SignRequest(Object credentialSubject, String dnaId, Proof proof) { + this.credentialSubject = credentialSubject; + this.dnaId = dnaId; + this.proof = proof; + } + + public byte[] genNeedSignData() { + Proof proof = this.proof; + this.proof = this.proof.genNeedSignProof(); + String jsonStr = JSON.toJSONString(this, SerializerFeature.MapSortField); + this.proof = proof; + return jsonStr.getBytes(); + } +} diff --git a/src/main/java/com/github/DNAProject/dnaid/Util.java b/src/main/java/com/github/DNAProject/dnaid/Util.java new file mode 100644 index 0000000..e102209 --- /dev/null +++ b/src/main/java/com/github/DNAProject/dnaid/Util.java @@ -0,0 +1,51 @@ +package com.github.DNAProject.dnaid; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.github.DNAProject.sdk.exception.SDKException; + +public class Util { + + public static int getIndexFromPubKeyURI(String pubKeyURI) throws Exception { + String[] keyInfo = pubKeyURI.split("#keys-"); + if (keyInfo.length != 2) { + throw new SDKException(String.format("invalid pubKeyURI %s", pubKeyURI)); + } + return Integer.parseInt(keyInfo[1]); + } + + public static String getDnaIdFromPubKeyURI(String pubKeyURI) throws Exception { + String[] keyInfo = pubKeyURI.split("#keys-"); + if (keyInfo.length != 2) { + throw new SDKException(String.format("invalid pubKeyURI %s", pubKeyURI)); + } + return keyInfo[0]; + } + + // fetch "id" field of object + // if object doesn't contain "id" field, return "" + // if object is array, return "" + public static String fetchId(Object object) { + if (object == null) { + return ""; + } + if (object instanceof String) { + return (String) object; + } + if (object.getClass().isPrimitive()) { + return ""; + } + if (object instanceof JSONArray) { + return ""; + } + if (object.getClass().isArray()) { + return ""; + } + JSONObject jsonObject = (JSONObject) JSONObject.toJSON(object); + String id = jsonObject.getString("id"); + if (id == null) { + return ""; + } + return id; + } +} diff --git a/src/main/java/com/github/DNAProject/dnaid/VerifiableCredential.java b/src/main/java/com/github/DNAProject/dnaid/VerifiableCredential.java new file mode 100644 index 0000000..2e65dee --- /dev/null +++ b/src/main/java/com/github/DNAProject/dnaid/VerifiableCredential.java @@ -0,0 +1,87 @@ +package com.github.DNAProject.dnaid; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; +import com.alibaba.fastjson.annotation.JSONType; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.github.DNAProject.dnaid.jwt.JWTCredential; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; +import java.util.UUID; + + +@JSONType(orders = {"@context", "id", "type", "issuer", "issuanceDate", "expirationDate", + "credentialSubject", "credentialStatus", "proof"}) +public class VerifiableCredential { + @JSONField(name = "@context") + public String[] context; + public String id; // uuid + public String[] type; + public Object issuer; // issuer dnaId, or an object contains dnaId + public String issuanceDate; + public String expirationDate; + public Object credentialSubject; + public CredentialStatus credentialStatus; + public Proof proof; // TODO: support multi + + public VerifiableCredential() { + this.id = "urn:uuid:" + UUID.randomUUID().toString(); + } + + public String fetchIssuerDnaId() { + return Util.fetchId(this.issuer); + } + + public byte[] genNeedSignData() { + Proof proof = this.proof; + this.proof = this.proof.genNeedSignProof(); + String jsonStr = JSON.toJSONString(this, SerializerFeature.MapSortField); + this.proof = proof; + return jsonStr.getBytes(); + } + + public String findSubjectId() { + return Util.fetchId(credentialSubject); + } + + public static VerifiableCredential deserializeFromJWT(JWTCredential jwtCred) { + VerifiableCredential credential = new VerifiableCredential(); + credential.context = jwtCred.payload.vc.context; + credential.id = jwtCred.payload.jti; + credential.type = jwtCred.payload.vc.type; + // set date + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + formatter.setTimeZone(TimeZone.getTimeZone("UTC")); + if (jwtCred.payload.iat > 0) { + credential.issuanceDate = formatter.format(new Date(jwtCred.payload.iat * 1000)); + } else if (jwtCred.payload.nbf > 0) { + credential.issuanceDate = formatter.format(new Date(jwtCred.payload.nbf * 1000)); + } + if (jwtCred.payload.exp > 0) { + credential.expirationDate = formatter.format(new Date(jwtCred.payload.exp * 1000)); + } + credential.credentialStatus = jwtCred.payload.vc.credentialStatus; + // assign issuer + if (jwtCred.payload.vc.issuer == null) { + credential.issuer = jwtCred.payload.iss; + } else { + JSONObject jsonIssuer = (JSONObject) JSONObject.toJSON(jwtCred.payload.vc.issuer); + jsonIssuer.put("id", jwtCred.payload.iss); + credential.issuer = jsonIssuer; + } + // generate proof + credential.proof = jwtCred.parseProof(); + // generate credential subject + if (jwtCred.payload.sub != null && !jwtCred.payload.sub.isEmpty()) { // inject id to credential subject + JSONObject subject = (JSONObject) JSONObject.toJSON(jwtCred.payload.vc.credentialSubject); + subject.put("id", jwtCred.payload.sub); + credential.credentialSubject = subject; + } else { + credential.credentialSubject = jwtCred.payload.vc.credentialSubject; + } + return credential; + } +} diff --git a/src/main/java/com/github/DNAProject/dnaid/VerifiablePresentation.java b/src/main/java/com/github/DNAProject/dnaid/VerifiablePresentation.java new file mode 100644 index 0000000..e8c19c9 --- /dev/null +++ b/src/main/java/com/github/DNAProject/dnaid/VerifiablePresentation.java @@ -0,0 +1,64 @@ +package com.github.DNAProject.dnaid; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; +import com.alibaba.fastjson.annotation.JSONType; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.github.DNAProject.dnaid.jwt.JWTCredential; + +import java.util.UUID; + +@JSONType(orders = {"@context", "id", "type", "verifiableCredential", "holder", "proof"}) +public class VerifiablePresentation { + @JSONField(name = "@context") + public String[] context; + public String id; + public String[] type; + public VerifiableCredential[] verifiableCredential; + public Object holder; // holder may not use + public Proof[] proof; + + public VerifiablePresentation() { + this.id = "urn:uuid:" + UUID.randomUUID().toString(); + } + + public byte[] genNeedSignData(Proof needSignProof) { + Proof[] proofs = this.proof; + this.proof = new Proof[]{needSignProof.genNeedSignProof()}; + String jsonStr = JSON.toJSONString(this, SerializerFeature.MapSortField); + this.proof = proofs; + return jsonStr.getBytes(); + } + + public String fetchHolderDnaId() { + return Util.fetchId(holder); + } + + public static VerifiablePresentation deserializeFromJWT(JWTCredential jwtCred) + throws Exception { + VerifiablePresentation presentation = new VerifiablePresentation(); + presentation.context = jwtCred.payload.vp.context; + presentation.id = jwtCred.payload.jti; + presentation.type = jwtCred.payload.vp.type; + // assign issuer + if (jwtCred.payload.vp.holder == null) { + presentation.holder = jwtCred.payload.iss; + } else { + JSONObject jsonHolder = (JSONObject) JSONObject.toJSON(jwtCred.payload.vp.holder); + jsonHolder.put("id", jwtCred.payload.iss); + presentation.holder = jsonHolder; + } + presentation.proof = new Proof[]{jwtCred.parseProof()}; + int vcLength = jwtCred.payload.vp.verifiableCredential.length; + VerifiableCredential[] credentials = new VerifiableCredential[vcLength]; + for (int i = 0; i < vcLength; i++) { + String vc = jwtCred.payload.vp.verifiableCredential[i]; + JWTCredential vcJWT = JWTCredential.deserializeToJWTCred(vc); + VerifiableCredential credential = VerifiableCredential.deserializeFromJWT(vcJWT); + credentials[i] = credential; + } + presentation.verifiableCredential = credentials; + return presentation; + } +} diff --git a/src/main/java/com/github/DNAProject/dnaid/jwt/JWTCredential.java b/src/main/java/com/github/DNAProject/dnaid/jwt/JWTCredential.java new file mode 100644 index 0000000..57fcae5 --- /dev/null +++ b/src/main/java/com/github/DNAProject/dnaid/jwt/JWTCredential.java @@ -0,0 +1,120 @@ +package com.github.DNAProject.dnaid.jwt; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.annotation.JSONType; +import com.alibaba.fastjson.parser.Feature; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.dnaid.Proof; +import com.github.DNAProject.dnaid.VerifiableCredential; +import com.github.DNAProject.dnaid.VerifiablePresentation; +import com.github.DNAProject.sdk.exception.SDKException; + +import java.util.Base64; + +@JSONType(orders = {"header", "payload", "jws"}) +public class JWTCredential { + public String jws; + public JWTHeader header; + public JWTPayload payload; + + public JWTCredential() { + } + + // payload.jti need to be recalculated + // jti should be uuid, not json-ld hash + public JWTCredential(JWTHeader header, JWTPayload payload, Account signer) throws Exception { + this.header = header; + this.payload = payload; + byte[] needSignData = this.genNeedSignData(); + byte[] sig = signer.generateSignature(needSignData, signer.getSignatureScheme(), null); + jws = Base64.getEncoder().encodeToString(sig); + } + + private JWTCredential(String header, String payload, String jws) { + this.jws = jws; + Base64.Decoder decoder = Base64.getDecoder(); + byte[] decodedHeader = decoder.decode(header); + byte[] decodedPayload = decoder.decode(payload); + this.header = JSON.parseObject(decodedHeader, JWTHeader.class); + // should parse iss and credentialSubject by field order + this.payload = JSON.parseObject(decodedPayload, JWTPayload.class, Feature.OrderedField); + } + + // the proof signature should be jws + public JWTCredential(VerifiableCredential credential) throws Exception { + if (credential.proof == null) { + throw new SDKException("proof is null"); + } + if (credential.proof.jws == null || credential.proof.jws.isEmpty()) { + throw new SDKException("credential has no jws"); + } + this.header = new JWTHeader(credential); + this.payload = new JWTPayload(credential); + this.jws = credential.proof.jws; + } + + // the proof signature should be jws + public JWTCredential(VerifiablePresentation presentation, Proof proof) throws Exception { + if (proof == null) { + throw new SDKException("proof is null"); + } + if (proof.jws == null || proof.jws.isEmpty()) { + throw new SDKException("credential has no jws"); + } + this.jws = proof.jws; + this.header = new JWTHeader(proof); + this.payload = new JWTPayload(presentation, proof); + } + + public static JWTCredential deserializeToJWTCred(String jwt) throws Exception { + String[] parts = jwt.split("\\."); + if (parts.length != 3) { + throw new SDKException("invalid jwt cred"); + } + return new JWTCredential(parts[0], parts[1], parts[2]); + } + + public byte[] genNeedSignData() { + String header = Base64.getEncoder().encodeToString( + JSON.toJSONString(this.header, SerializerFeature.MapSortField).getBytes()); + String payload = Base64.getEncoder().encodeToString( + JSON.toJSONString(this.payload, SerializerFeature.MapSortField).getBytes()); + String needSignData = header + "." + payload; + return needSignData.getBytes(); + } + + public Proof parseProof() { + Proof p = null; + if (this.payload.vc != null) { + p = this.payload.vc.proof; + } else if (this.payload.vp != null) { + p = this.payload.vp.proof; + } + Proof proof = new Proof(); + if (p != null) { + proof.proofPurpose = p.proofPurpose; + proof.hex = p.hex; + proof.created = p.created; + } + proof.type = this.header.alg.proofPubKeyType(); + proof.verificationMethod = this.header.kid; + proof.jws = this.jws; + proof.domain = this.payload.aud; + proof.challenge = this.payload.nonce; + return proof; + } + + public byte[] parseSignature() { + return Base64.getDecoder().decode(this.jws); + } + + @Override + public String toString() { + String header = Base64.getEncoder().encodeToString( + JSON.toJSONString(this.header, SerializerFeature.MapSortField).getBytes()); + String payload = Base64.getEncoder().encodeToString( + JSON.toJSONString(this.payload, SerializerFeature.MapSortField).getBytes()); + return header + "." + payload + "." + jws; + } +} diff --git a/src/main/java/com/github/DNAProject/dnaid/jwt/JWTHeader.java b/src/main/java/com/github/DNAProject/dnaid/jwt/JWTHeader.java new file mode 100644 index 0000000..d276d7b --- /dev/null +++ b/src/main/java/com/github/DNAProject/dnaid/jwt/JWTHeader.java @@ -0,0 +1,34 @@ +package com.github.DNAProject.dnaid.jwt; + +import com.alibaba.fastjson.annotation.JSONType; +import com.github.DNAProject.dnaid.*; + +@JSONType(orders = {"alg", "kid", "typ"}) +public class JWTHeader { + public ALG alg; + public String kid; // VerifiableCredential issuer + public String typ = "JWT"; + + public JWTHeader() { + } + + public JWTHeader(ALG alg, String kid) { + this.alg = alg; + this.kid = kid; + } + + public JWTHeader(PubKeyType pubKeyType, String kid) { + this.alg = pubKeyType.getAlg(); + this.kid = kid; + } + + public JWTHeader(VerifiableCredential credential) { + this.alg = credential.proof.type.getAlg(); + this.kid = credential.proof.verificationMethod; + } + + public JWTHeader(Proof proof) throws Exception { + this.alg = proof.type.getAlg(); + this.kid = proof.verificationMethod; + } +} diff --git a/src/main/java/com/github/DNAProject/dnaid/jwt/JWTPayload.java b/src/main/java/com/github/DNAProject/dnaid/jwt/JWTPayload.java new file mode 100644 index 0000000..58e9845 --- /dev/null +++ b/src/main/java/com/github/DNAProject/dnaid/jwt/JWTPayload.java @@ -0,0 +1,81 @@ +package com.github.DNAProject.dnaid.jwt; + +import com.alibaba.fastjson.annotation.JSONField; +import com.alibaba.fastjson.annotation.JSONType; +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.github.DNAProject.dnaid.Proof; +import com.github.DNAProject.dnaid.VerifiableCredential; +import com.github.DNAProject.dnaid.VerifiablePresentation; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +@JSONType(orders = {"iss", "sub", "aud", "exp", "nbf", "iat", "jti", "nonce", "vc", "vp"}) +public class JWTPayload { + public String iss; // VerifiableCredential issuer + // VerifiableCredential credential id, if there are more than 1 credentialSubject, cannot parse to JWTPayload + public String sub; + public Object aud; // audience, may not present, String or String[] + + + @JSONField(serialzeFeatures = SerializerFeature.NotWriteDefaultValue) + public long exp; // VerifiableCredential expiration, for example 1541493724 + @JSONField(serialzeFeatures = SerializerFeature.NotWriteDefaultValue) + public long nbf; // VerifiableCredential issue date, for example 1541493724, 定义在什么时间之前,该jwt都是不可用的 + @JSONField(serialzeFeatures = SerializerFeature.NotWriteDefaultValue) + public long iat; // created date time, same with nbf, for example 1541493724, may not present, jwt的签发时间 + + public String jti; // VerifiableCredential id + public String nonce; // in case of replay attack, generated form proof, may not present + public JWTVC vc; + public JWTVP vp; + + public JWTPayload() { + } + +// public JWTPayload(VerifiableCredential credential, String audience) throws Exception { +// this(credential); +// this.aud = audience; +// } + + public JWTPayload(VerifiableCredential credential) throws Exception { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + formatter.setTimeZone(TimeZone.getTimeZone("UTC")); + if (credential.expirationDate != null && !credential.expirationDate.isEmpty()) { + Date exp = formatter.parse(credential.expirationDate); + this.exp = exp.getTime() / 1000; + } + this.iss = credential.fetchIssuerDnaId(); + if (credential.issuanceDate != null && !credential.issuanceDate.isEmpty()) { + Date nbf = formatter.parse(credential.issuanceDate); + this.nbf = nbf.getTime() / 1000; + this.iat = this.nbf; + } + this.jti = credential.id; + String credentialSubjectId = credential.findSubjectId(); + if (!"".equals(credentialSubjectId)) { + this.sub = credentialSubjectId; + } + if (credential.proof != null) { + this.aud = credential.proof.domain; + this.nonce = credential.proof.challenge; + } + this.vc = new JWTVC(credential); + } + +// public JWTPayload(VerifiablePresentation presentation, String audience) throws Exception { +// this(presentation); +// this.aud = audience; +// } + + public JWTPayload(VerifiablePresentation presentation, Proof proof) throws Exception { + if (proof != null) { + this.aud = proof.domain; + this.nonce = proof.challenge; + } + this.iss = presentation.fetchHolderDnaId(); + this.jti = presentation.id; + this.vp = new JWTVP(presentation, proof); + } +} diff --git a/src/main/java/com/github/DNAProject/dnaid/jwt/JWTVC.java b/src/main/java/com/github/DNAProject/dnaid/jwt/JWTVC.java new file mode 100644 index 0000000..d5ac08e --- /dev/null +++ b/src/main/java/com/github/DNAProject/dnaid/jwt/JWTVC.java @@ -0,0 +1,55 @@ +package com.github.DNAProject.dnaid.jwt; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; +import com.alibaba.fastjson.annotation.JSONType; +import com.github.DNAProject.dnaid.CredentialStatus; +import com.github.DNAProject.dnaid.Proof; +import com.github.DNAProject.dnaid.VerifiableCredential; +import com.github.DNAProject.sdk.exception.SDKException; + +@JSONType(orders = {"@context", "type", "issuer", "credentialSubject", "credentialStatus", "proof"}) +public class JWTVC { + @JSONField(name = "@context") + public String[] context; + public String[] type; + public Object issuer; + public Object credentialSubject; + public CredentialStatus credentialStatus; + public Proof proof; + + public JWTVC() { + } + + public JWTVC(VerifiableCredential credential) throws Exception { + this.context = credential.context; + this.type = credential.type; + this.credentialStatus = credential.credentialStatus; + if (credential.proof != null) { + this.proof = credential.proof.genJWTProof(); + } + if (credential.issuer.getClass().isPrimitive() || credential.issuer.getClass().isArray() || + credential.issuer instanceof JSONArray) { + throw new SDKException("illegal credential issuer"); + } + if (!(credential.issuer instanceof String)) { + JSONObject jsonObject = (JSONObject) JSONObject.toJSON(credential.issuer); + jsonObject.remove("id"); + if (jsonObject.size() > 0) { + this.issuer = jsonObject; + } + } + // remove id attribute + if (credential.credentialSubject != null && !credential.credentialSubject.getClass().isArray() + && !(credential.credentialSubject instanceof JSONArray)) { + JSONObject credentialSubject = (JSONObject) JSONObject.toJSON(credential.credentialSubject); + credentialSubject.remove("id"); + if (credentialSubject.size() > 0) { + this.credentialSubject = credentialSubject; + } + } else { + this.credentialSubject = credential.credentialSubject; + } + } +} diff --git a/src/main/java/com/github/DNAProject/dnaid/jwt/JWTVP.java b/src/main/java/com/github/DNAProject/dnaid/jwt/JWTVP.java new file mode 100644 index 0000000..d31fb68 --- /dev/null +++ b/src/main/java/com/github/DNAProject/dnaid/jwt/JWTVP.java @@ -0,0 +1,47 @@ +package com.github.DNAProject.dnaid.jwt; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.annotation.JSONField; +import com.alibaba.fastjson.annotation.JSONType; +import com.github.DNAProject.dnaid.Proof; +import com.github.DNAProject.dnaid.VerifiablePresentation; +import com.github.DNAProject.sdk.exception.SDKException; + +@JSONType(orders = {"@context", "type", "challenge", "verifiableCredential", "holder", "proof"}) +public class JWTVP { + @JSONField(name = "@context") + public String[] context; + public String[] type; + public String[] verifiableCredential; // base64url encoded JWTVC as string + public Object holder; + public Proof proof; + + public JWTVP() { + } + + public JWTVP(VerifiablePresentation presentation, Proof proof) throws Exception { + if (presentation.holder.getClass().isPrimitive() || presentation.holder.getClass().isArray() || + presentation.holder instanceof JSONArray) { + throw new SDKException("illegal presentation holder"); + } + if (!(presentation.holder instanceof String)) { + JSONObject jsonObject = (JSONObject) JSONObject.toJSON(presentation.holder); + jsonObject.remove("id"); + if (jsonObject.size() > 0) { + this.holder = jsonObject; + } + } + this.context = presentation.context; + this.type = presentation.type; + if (presentation.verifiableCredential != null) { + String[] verifiableCredential = new String[presentation.verifiableCredential.length]; + for (int i = 0; i < presentation.verifiableCredential.length; i++) { + JWTCredential jwtCred = new JWTCredential(presentation.verifiableCredential[i]); + verifiableCredential[i] = jwtCred.toString(); + } + this.verifiableCredential = verifiableCredential; + } + this.proof = proof.genJWTProof(); + } +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/NeoVm.java b/src/main/java/com/github/DNAProject/smartcontract/NeoVm.java index 564ca36..a2b6e39 100644 --- a/src/main/java/com/github/DNAProject/smartcontract/NeoVm.java +++ b/src/main/java/com/github/DNAProject/smartcontract/NeoVm.java @@ -23,6 +23,7 @@ import com.github.DNAProject.account.Account; import com.github.DNAProject.common.ErrorCode; import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.dnaid.DnaId2; import com.github.DNAProject.smartcontract.neovm.*; import com.github.DNAProject.smartcontract.neovm.abi.AbiFunction; import com.github.DNAProject.sdk.exception.SDKException; @@ -34,6 +35,8 @@ public class NeoVm { private Oep8 oep8Tx = null; private Record recordTx = null; private ClaimRecord claimRecordTx = null; + private CredentialRecord credentialRecordTx = null; + private DnaId2 dnaId2 = null; private DnaSdk sdk; public NeoVm(DnaSdk sdk){ @@ -79,6 +82,30 @@ public ClaimRecord claimRecord(){ } return claimRecordTx; } + + public CredentialRecord credentialRecord() { + if (credentialRecordTx == null) { + credentialRecordTx = new CredentialRecord(sdk); + } + return credentialRecordTx; + } + + public DnaId2 dnaId2() throws Exception { + if (dnaId2 == null) { + dnaId2 = new DnaId2("", null, credentialRecordTx, sdk.nativevm().dnaId()); + } + return dnaId2; + } + + public DnaId2 dnaId2(String dnaId, Account signer) throws Exception { + if (dnaId2 == null) { + dnaId2 = new DnaId2(dnaId, signer, credentialRecordTx, sdk.nativevm().dnaId()); + } else { + dnaId2.updateDnaIdAndSigner(dnaId, signer); + } + return dnaId2; + } + public Object sendTransaction(String contractAddr, Account acct,Account payerAcct, long gaslimit, long gasprice, AbiFunction func, boolean preExec) throws Exception { byte[] params; if (func != null) { diff --git a/src/main/java/com/github/DNAProject/smartcontract/neovm/CredentialRecord.java b/src/main/java/com/github/DNAProject/smartcontract/neovm/CredentialRecord.java new file mode 100644 index 0000000..1cc7be6 --- /dev/null +++ b/src/main/java/com/github/DNAProject/smartcontract/neovm/CredentialRecord.java @@ -0,0 +1,350 @@ +/* + * Copyright (C) 2018 The ontology Authors + * This file is part of The ontology library. + * + * The ontology is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The ontology is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The ontology. If not, see . + * + */ + +package com.github.DNAProject.smartcontract.neovm; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.Common; +import com.github.DNAProject.common.ErrorCode; +import com.github.DNAProject.common.Helper; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.io.BinaryReader; +import com.github.DNAProject.io.BinaryWriter; +import com.github.DNAProject.io.Serializable; +import com.github.DNAProject.sdk.exception.SDKException; +import com.github.DNAProject.smartcontract.neovm.abi.AbiFunction; +import com.github.DNAProject.smartcontract.neovm.abi.AbiInfo; +import com.github.DNAProject.smartcontract.neovm.abi.BuildParams; +import com.github.DNAProject.smartcontract.neovm.abi.Parameter; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +public class CredentialRecord { + private DnaSdk sdk; + private String contractAddress = "36bb5c053b6b839c8f6b923fe852f91239b9fccc"; + + private String abi = "{\"hash\":\"0x36bb5c053b6b839c8f6b923fe852f91239b9fccc\",\"entrypoint\":\"Main\",\"functions\":[{\"name\":\"Main\",\"parameters\":[{\"name\":\"operation\",\"type\":\"String\"},{\"name\":\"args\",\"type\":\"Array\"}],\"returntype\":\"Any\"},{\"name\":\"Commit\",\"parameters\":[{\"name\":\"claimId\",\"type\":\"ByteArray\"},{\"name\":\"commiterId\",\"type\":\"ByteArray\"},{\"name\":\"ownerId\",\"type\":\"ByteArray\"}],\"returntype\":\"Boolean\"},{\"name\":\"Revoke\",\"parameters\":[{\"name\":\"claimId\",\"type\":\"ByteArray\"},{\"name\":\"dnaId\",\"type\":\"ByteArray\"}],\"returntype\":\"Boolean\"},{\"name\":\"GetStatus\",\"parameters\":[{\"name\":\"claimId\",\"type\":\"ByteArray\"}],\"returntype\":\"ByteArray\"}],\"events\":[{\"name\":\"ErrorMsg\",\"parameters\":[{\"name\":\"id\",\"type\":\"ByteArray\"},{\"name\":\"error\",\"type\":\"String\"}],\"returntype\":\"Void\"},{\"name\":\"Push\",\"parameters\":[{\"name\":\"id\",\"type\":\"ByteArray\"},{\"name\":\"msg\",\"type\":\"String\"},{\"name\":\"args\",\"type\":\"ByteArray\"}],\"returntype\":\"Void\"}]}"; + + private String abi2 = "{\"hash\":\"52df370680de17bc5d4262c446f102a0ee0d6312\",\"entrypoint\":\"Main\",\"functions\":[{\"name\":\"Commit\",\"parameters\":[{\"name\":\"claimId\",\"type\":\"\"},{\"name\":\"commiterId\",\"type\":\"\"},{\"name\":\"index\",\"type\":\"\"},{\"name\":\"ownerId\",\"type\":\"\"}]},{\"name\":\"Revoke\",\"parameters\":[{\"name\":\"claimId\",\"type\":\"\"},{\"name\":\"dnaId\",\"type\":\"\"},{\"name\":\"index\",\"type\":\"\"}]},{\"name\":\"Remove\",\"parameters\":[{\"name\":\"claimId\",\"type\":\"\"},{\"name\":\"ownerId\",\"type\":\"\"},{\"name\":\"index\",\"type\":\"\"}]},{\"name\":\"GetStatus\",\"parameters\":[{\"name\":\"claimId\",\"type\":\"\"}]},{\"name\":\"Upgrade\",\"parameters\":[{\"name\":\"code\",\"type\":\"\"},{\"name\":\"needStorage\",\"type\":\"\"},{\"name\":\"name\",\"type\":\"\"},{\"name\":\"version\",\"type\":\"\"},{\"name\":\"author\",\"type\":\"\"},{\"name\":\"email\",\"type\":\"\"},{\"name\":\"description\",\"type\":\"\"}]}]}"; + + public CredentialRecord(DnaSdk sdk) { + this.sdk = sdk; + } + + public void setContractAddress(String codeHash) { + this.contractAddress = codeHash.replace("0x", ""); + } + + public String getContractAddress() { + return contractAddress; + } + + /** + * @param issuerDnaId + * @param password + * @param issuerDnaId + * @param claimId + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public String sendCommit(String issuerDnaId, String password, byte[] salt, String subjectDnaId, String claimId, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if (issuerDnaId == null || issuerDnaId.equals("") || password == null || password.equals("") || subjectDnaId == null || subjectDnaId.equals("") + || claimId == null || claimId.equals("") || payerAcct == null) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gaslimit < 0 || gasprice < 0) { + throw new SDKException(ErrorCode.ParamErr("gaslimit or gasprice is less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + Transaction tx = makeCommit(issuerDnaId, subjectDnaId, claimId, payerAcct.getAddressU160().toBase58(), gaslimit, gasprice); + sdk.signTx(tx, issuerDnaId, password, salt); + sdk.addSign(tx, payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + + // new version claim contract + public String sendCommit2(String issuerDnaId, String password, byte[] salt, String subjectDnaId, String claimId, int pubkeyIndex, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if (issuerDnaId == null || issuerDnaId.equals("") || password == null || password.equals("") || subjectDnaId == null || subjectDnaId.equals("") + || claimId == null || claimId.equals("") || payerAcct == null) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gaslimit < 0 || gasprice < 0) { + throw new SDKException(ErrorCode.ParamErr("gaslimit or gasprice is less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + Transaction tx = makeCommit2(issuerDnaId, subjectDnaId, claimId, pubkeyIndex, payerAcct.getAddressU160().toBase58(), gaslimit, gasprice); + sdk.signTx(tx, issuerDnaId, password, salt); + sdk.addSign(tx, payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + + /** + * @param issuerDnaId + * @param subjectDnaId + * @param claimId + * @param payer + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public Transaction makeCommit(String issuerDnaId, String subjectDnaId, String claimId, String payer, long gaslimit, long gasprice) throws Exception { + if (issuerDnaId == null || issuerDnaId.equals("") || subjectDnaId == null || subjectDnaId.equals("") || payer == null || payer.equals("") + || claimId == null || claimId.equals("")) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gaslimit < 0 || gasprice < 0) { + throw new SDKException(ErrorCode.ParamErr("gaslimit or gasprice is less than 0")); + } + + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + String name = "Commit"; + AbiFunction func = abiinfo.getFunction(name); + func.name = name; + func.setParamsValue(claimId.getBytes(), issuerDnaId.getBytes(), subjectDnaId.getBytes()); + byte[] params = BuildParams.serializeAbiFunction(func); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress), null, params, payer, gaslimit, gasprice); + return tx; + } + + public Transaction makeCommit2(String issuerDnaId, String subjectDnaId, String claimId, int pubkeyIndex, String payer, long gaslimit, long gasprice) throws Exception { + if (issuerDnaId == null || issuerDnaId.equals("") || subjectDnaId == null || subjectDnaId.equals("") || payer == null || payer.equals("") + || claimId == null || claimId.equals("")) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gaslimit < 0 || gasprice < 0) { + throw new SDKException(ErrorCode.ParamErr("gaslimit or gasprice is less than 0")); + } + + String name = "Commit"; + Parameter claimIdParam = new Parameter("claimId", Parameter.Type.String, claimId); + Parameter commiterIdParam = new Parameter("commiterId", Parameter.Type.String, issuerDnaId); + Parameter indexParam = new Parameter("index", Parameter.Type.Integer, pubkeyIndex); + Parameter ownerIdParam = new Parameter("ownerId", Parameter.Type.String, subjectDnaId); + AbiFunction func = new AbiFunction(name, claimIdParam, commiterIdParam, indexParam, ownerIdParam); + byte[] params = BuildParams.serializeAbiFunction(func); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress), null, params, payer, gaslimit, gasprice); + return tx; + } + + /** + * @param issuerDnaId + * @param password + * @param claimId + * @param payerAcct + * @param gaslimit + * @param gasprice + * @return + * @throws Exception + */ + public String sendRevoke(String issuerDnaId, String password, byte[] salt, String claimId, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if (issuerDnaId == null || issuerDnaId.equals("") || password == null || password.equals("") + || claimId == null || claimId.equals("") || payerAcct == null) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gaslimit < 0 || gasprice < 0) { + throw new SDKException(ErrorCode.ParamErr("gaslimit or gasprice is less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + String addr = issuerDnaId.replace(Common.diddna, ""); + Transaction tx = makeRevoke(issuerDnaId, claimId, payerAcct.getAddressU160().toBase58(), gaslimit, gasprice); + sdk.signTx(tx, addr, password, salt); + sdk.addSign(tx, payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + + public String sendRevoke2(String ownerId, String password, byte[] salt, String claimId, int pubkeyIndex, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if (ownerId == null || ownerId.equals("") || password == null || password.equals("") + || claimId == null || claimId.equals("") || payerAcct == null) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gaslimit < 0 || gasprice < 0) { + throw new SDKException(ErrorCode.ParamErr("gaslimit or gasprice is less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + Transaction tx = makeRevoke2(ownerId, claimId, pubkeyIndex, payerAcct.getAddressU160().toBase58(), gaslimit, gasprice); + sdk.signTx(tx, ownerId, password, salt); + sdk.addSign(tx, payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + + public Transaction makeRevoke(String issuerDnaId, String claimId, String payer, long gaslimit, long gasprice) throws Exception { + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + String name = "Revoke"; + AbiFunction func = abiinfo.getFunction(name); + func.name = name; + func.setParamsValue(claimId.getBytes(), issuerDnaId.getBytes()); + byte[] params = BuildParams.serializeAbiFunction(func); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress), null, params, payer, gaslimit, gasprice); + return tx; + } + + public Transaction makeRevoke2(String ownerId, String claimId, int pubkeyIndex, String payer, long gaslimit, long gasprice) throws Exception { + String name = "Revoke"; + Parameter claimIdParam = new Parameter("claimId", Parameter.Type.String, claimId); + Parameter ownerIdParam = new Parameter("dnaId", Parameter.Type.String, ownerId); + Parameter indexParam = new Parameter("index", Parameter.Type.Integer, pubkeyIndex); + AbiFunction func = new AbiFunction(name, claimIdParam, ownerIdParam, indexParam); + byte[] params = BuildParams.serializeAbiFunction(func); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress), null, params, payer, gaslimit, gasprice); + return tx; + } + + public String sendRemove2(String ownerId, String password, byte[] salt, String claimId, int pubkeyIndex, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if (ownerId == null || ownerId.equals("") || password == null || password.equals("") + || claimId == null || claimId.equals("") || payerAcct == null) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gaslimit < 0 || gasprice < 0) { + throw new SDKException(ErrorCode.ParamErr("gaslimit or gasprice is less than 0")); + } + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + Transaction tx = makeRemove2(ownerId, claimId, pubkeyIndex, payerAcct.getAddressU160().toBase58(), gaslimit, gasprice); + sdk.signTx(tx, ownerId, password, salt); + sdk.addSign(tx, payerAcct); + boolean b = sdk.getConnect().sendRawTransaction(tx.toHexString()); + if (b) { + return tx.hash().toString(); + } + return null; + } + + public Transaction makeRemove2(String ownerDnaId, String claimId, int pubkeyIndex, String payer, long gaslimit, long gasprice) throws Exception { + String name = "Remove"; + Parameter claimIdParam = new Parameter("claimId", Parameter.Type.String, claimId); + Parameter ownerIdParam = new Parameter("ownerId", Parameter.Type.String, ownerDnaId); + Parameter indexParam = new Parameter("index", Parameter.Type.Integer, pubkeyIndex); + AbiFunction func = new AbiFunction(name, claimIdParam, ownerIdParam, indexParam); + byte[] params = BuildParams.serializeAbiFunction(func); + Transaction tx = sdk.vm().makeInvokeCodeTransaction(Helper.reverse(contractAddress), null, params, payer, gaslimit, gasprice); + return tx; + } + + public String sendGetStatus(String claimId) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + if ("".equals(claimId)) { + throw new SDKException(ErrorCode.NullKeyOrValue); + } + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + String name = "GetStatus"; + AbiFunction func = abiinfo.getFunction(name); + func.name = name; + func.setParamsValue(claimId.getBytes()); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress), null, null, 0, 0, func, true); + String res = ((JSONObject) obj).getString("Result"); + if (res.equals("")) { + return ""; + } + ByteArrayInputStream bais = new ByteArrayInputStream(Helper.hexToBytes(res)); + BinaryReader br = new BinaryReader(bais); + CredentialTx credentialTx = new CredentialTx(); + credentialTx.deserialize(br); + if (credentialTx.status.length == 0) { + return new String(credentialTx.claimId) + "." + "00" + "." + new String(credentialTx.issuerDnaId) + "." + new String(credentialTx.subjectDnaId); + } + return new String(credentialTx.claimId) + "." + Helper.toHexString(credentialTx.status) + "." + new String(credentialTx.issuerDnaId) + "." + new String(credentialTx.subjectDnaId); + } + + public String sendGetStatus2(String claimId) throws Exception { + if (contractAddress == null) { + throw new SDKException(ErrorCode.NullCodeHash); + } + if ("".equals(claimId)) { + throw new SDKException(ErrorCode.NullKeyOrValue); + } + AbiInfo abiinfo = JSON.parseObject(abi, AbiInfo.class); + String name = "GetStatus"; + AbiFunction func = abiinfo.getFunction(name); + func.name = name; + func.setParamsValue(claimId.getBytes()); + Object obj = sdk.neovm().sendTransaction(Helper.reverse(contractAddress), null, null, 0, 0, func, true); + return ((JSONObject) obj).getString("Result"); + } +} + +class CredentialTx implements Serializable { + public byte[] claimId; + public byte[] issuerDnaId; + public byte[] subjectDnaId; + public byte[] status; + + CredentialTx() { + } + + CredentialTx(byte[] claimId, byte[] issuerDnaId, byte[] subjectDnaId, byte[] status) { + this.claimId = claimId; + this.issuerDnaId = issuerDnaId; + this.subjectDnaId = subjectDnaId; + this.status = status; + } + + @Override + public void deserialize(BinaryReader reader) throws IOException { + byte dataType = reader.readByte(); + long length = reader.readVarInt(); + byte dataType2 = reader.readByte(); + this.claimId = reader.readVarBytes(); + byte dataType3 = reader.readByte(); + this.issuerDnaId = reader.readVarBytes(); + byte dataType4 = reader.readByte(); + this.subjectDnaId = reader.readVarBytes(); + byte dataType5 = reader.readByte(); + this.status = reader.readVarBytes(); + } + + @Override + public void serialize(BinaryWriter writer) throws IOException { + + } +} diff --git a/src/main/java/com/github/DNAProject/smartcontract/neovm/abi/Parameter.java b/src/main/java/com/github/DNAProject/smartcontract/neovm/abi/Parameter.java index c8f05c4..d110af0 100644 --- a/src/main/java/com/github/DNAProject/smartcontract/neovm/abi/Parameter.java +++ b/src/main/java/com/github/DNAProject/smartcontract/neovm/abi/Parameter.java @@ -71,7 +71,7 @@ public boolean setValue(Object value) { boolean tmp = (boolean) value; this.value = JSON.toJSONString(tmp); } else if ("Integer".equals(type)) { - long tmp = (long)value; + long tmp = Long.valueOf(value.toString()); this.value = JSON.toJSONString(tmp); } else if ("Array".equals(type)) { List tmp = (List) value; diff --git a/src/test/java/com/github/DNAProject/credential/CredentialTest.java b/src/test/java/com/github/DNAProject/credential/CredentialTest.java new file mode 100644 index 0000000..51b9d36 --- /dev/null +++ b/src/test/java/com/github/DNAProject/credential/CredentialTest.java @@ -0,0 +1,301 @@ +package com.github.DNAProject.credential; + + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.DNAProject.DnaSdk; +import com.github.DNAProject.account.Account; +import com.github.DNAProject.common.*; +import com.github.DNAProject.core.payload.DeployCode; +import com.github.DNAProject.core.transaction.Transaction; +import com.github.DNAProject.crypto.Curve; +import com.github.DNAProject.crypto.ECC; +import com.github.DNAProject.dnaid.CredentialStatusType; +import com.github.DNAProject.dnaid.DnaId2; +import com.github.DNAProject.dnaid.ProofPurpose; +import com.github.DNAProject.sdk.exception.SDKException; +import com.github.DNAProject.sdk.wallet.Control; +import com.github.DNAProject.sdk.wallet.Identity; +import com.github.DNAProject.smartcontract.Vm; +import com.github.DNAProject.smartcontract.nativevm.abi.NativeBuildParams; +import com.github.DNAProject.smartcontract.nativevm.abi.Struct; + +import org.junit.Before; +import org.junit.Test; + +import java.util.*; + + +public class CredentialTest { + DnaSdk dnaSdk; + public static final String DNAID_CONTRACT_ADDRESS = "0000000000000000000000000000000000000003"; + public static final String PAYER_ADDRESS = "AQFUKqrFdgR9A56ryyqDTXGLkdRFh7mbXY"; + public static final String PAYER_WIF = "L3exzrGEmqm1zYdkziXfNWebmXnBK4eu7yY2hUXH6kx6W6KMheMo"; + + @Before + public void setUp() throws SDKException { + dnaSdk = DnaSdk.getInstance(); + dnaSdk.setRestful("http://1.116.79.177:20334"); + dnaSdk.setDefaultConnect(dnaSdk.getRestful()); + dnaSdk.openWalletFile("src\\test\\java\\com\\github\\DNAProject\\credential\\credentialTest.json"); + Vm.NATIVE_INVOKE_NAME = "DNA.Native.Invoke"; + dnaSdk.neovm().credentialRecord().setContractAddress("45867428484ccdfc1d1ad205d725ab7158f5b67b"); + } + + @Test + public void deployContract() throws Exception { + String code = "58c56b05322e302e306a00527ac42241476d7269314b786847736b6d6a733236366f4a347066626b79336e784e63516136681b444e412e52756e74696d652e426173653538546f416464726573736a51527ac41400000000000000000000000000000000000000036a52527ac4681953797374656d2e53746f726167652e476574436f6e746578746a53527ac46c0122c56b6a00527ac46a51527ac46a52527ac46a51c306436f6d6d69747d9c7c75645c006a52c3c0547d9e7c75640a00006c75666203006a52c300c36a53527ac46a52c351c36a54527ac46a52c352c36a55527ac46a52c353c36a56527ac46a56c36a55c36a54c36a53c3546a00c306a002000000006e6c75666203006a51c3065265766f6b657d9c7c75644f006a52c3c0537d9e7c75640a00006c75666203006a52c300c36a53527ac46a52c351c36a58527ac46a52c352c36a55527ac46a55c36a58c36a53c3536a00c3064b04000000006e6c75666203006a51c30652656d6f76657d9c7c75644f006a52c3c0537d9e7c75640a00006c75666203006a52c300c36a53527ac46a52c351c36a56527ac46a52c352c36a55527ac46a55c36a56c36a53c3536a00c3064406000000006e6c75666203006a51c3094765745374617475737d9c7c756435006a52c3c0517d9e7c75640a00006c75666203006a52c300c36a53527ac46a53c3516a00c306f307000000006e6c75666203006a51c307557067726164657d9c7c756483006a52c3c0577d9e7c75640a00006c75666203006a52c300c36a59527ac46a52c351c36a5a527ac46a52c352c36a5b527ac46a52c353c36a5c527ac46a52c354c36a5d527ac46a52c355c36a5e527ac46a52c356c36a5f527ac46a5fc36a5ec36a5dc36a5cc36a5bc36a5ac36a59c3576a00c3069b08000000006e6c75666203006c75665ec56b6a00527ac46a51527ac46a52527ac46a53527ac46a54527ac46a55527ac46203006a54c36a53c352c66b6a00527ac46a51527ac46c6a56527ac46a56c30f7665726966795369676e61747572656a00c352c3006811444e412e4e61746976652e496e766f6b656a57527ac46a57c301017d9e7c7564290021636f6d6d697465724964207665726966795369676e6174757265206572726f722ef06203006a55c358007b6b766b946c6c52727f086469643a646e613a7d9e7c75641f0017696c6c6567616c206f776e6572496420666f726d61742ef06203006a52c36a00c353c3681253797374656d2e53746f726167652e4765746a58527ac46a58c3c0007d9e7c756425001d436f6d6d69742c20636c61696d496420616c7265616479206578697374f06203006a52c3516a53c36a55c354c176c96a59527ac46a59c3681853797374656d2e52756e74696d652e53657269616c697a656a58527ac46a58c36a52c36a00c353c3681253797374656d2e53746f726167652e5075746a55c36a53c36a52c306436f6d6d697454c1681553797374656d2e52756e74696d652e4e6f74696679516c75665ec56b6a00527ac46a51527ac46a52527ac46a53527ac46a54527ac46203006a54c36a53c352c66b6a00527ac46a51527ac46c6a55527ac46a55c30f7665726966795369676e61747572656a00c352c3006811444e412e4e61746976652e496e766f6b656a56527ac46a56c301017d9e7c756424001c6f6e744964207665726966795369676e6174757265206572726f722ef06203006a52c36a00c353c3681253797374656d2e53746f726167652e4765746a57527ac46a57c3c0007d9c7c756424001c5265766f6b652c20636c61696d496420646f206e6f74206578697374f06203006a57c3681a53797374656d2e52756e74696d652e446573657269616c697a656a58527ac46a58c3c0547d9f7c756427001f5265766f6b652c20696c6c6567616c20666f726d6174206f6620636c61696df06203006a58c352c36a53c37d9e7c7576641000756a58c353c36a53c37d9e7c756432002a5265766f6b652c206f6e74496420646f206e6f7420686176652061636365737320746f207265766f6b65f0620300006a58c3517bc46a58c3681853797374656d2e52756e74696d652e53657269616c697a656a59527ac46a59c36a52c36a00c353c3681253797374656d2e53746f726167652e5075746a53c36a52c3065265766f6b6553c1681553797374656d2e52756e74696d652e4e6f74696679516c75665cc56b6a00527ac46a51527ac46a52527ac46a53527ac46a54527ac46203006a54c36a53c352c66b6a00527ac46a51527ac46c6a55527ac46a55c30f7665726966795369676e61747572656a00c352c3006811444e412e4e61746976652e496e766f6b656a56527ac46a56c301017d9e7c756426001e6f776e65724964207665726966795369676e6174757265206572726f722ef06203006a52c36a00c353c3681253797374656d2e53746f726167652e4765746a57527ac46a57c3c0007d9c7c756424001c52656d6f76652c20636c61696d496420646f206e6f74206578697374f06203006a57c3681a53797374656d2e52756e74696d652e446573657269616c697a656a58527ac46a58c3c0547d9f7c756427001f52656d6f76652c20696c6c6567616c20666f726d6174206f6620636c61696df06203006a58c353c36a53c37d9e7c756420001852656d6f76652c206f776e657249642069732077726f6e67f06203006a52c36a00c353c3681553797374656d2e53746f726167652e44656c6574656a53c36a52c30652656d6f766553c1681553797374656d2e52756e74696d652e4e6f74696679516c756659c56b6a00527ac46a51527ac46a52527ac46203006a52c36a00c353c3681253797374656d2e53746f726167652e4765746a53527ac46a53c3c0007d9c7c75640a00526c75666203006a53c3681a53797374656d2e52756e74696d652e446573657269616c697a656a54527ac46a54c3c0547d9f7c75642a00224765745374617475732c20696c6c6567616c20666f726d6174206f6620636c61696df06203006a54c351c36c75665dc56b6a00527ac46a51527ac46a52527ac46a53527ac46a54527ac46a55527ac46a56527ac46a57527ac46a58527ac46203006a00c351c3681b53797374656d2e52756e74696d652e436865636b5769746e65737391641b0013436865636b5769746e657373206661696c6564f06203006a58c36a57c36a56c36a55c36a54c36a53c36a52c36814444e412e436f6e74726163742e4d6967726174656a59527ac46a59c3916416000e4d696772617465206661696c6564f0620300516c7566"; + String name = "credential"; + String version = "1.0"; + String author = "author"; + String email = "email"; + String desc = "desc"; + String contractAddress = makeDeployCodeTransaction(code, name, version, author, email, desc); + System.out.println("contractAddress:" + contractAddress); + } + + @Test + public void createDnaId() throws Exception { + Map dnaId = createDnaId("123456"); + System.out.println("dnaId:" + dnaId); + } + + @Test + public void createCred() { + String issuerDnaId = "did:dna:AQFUKqrFdgR9A56ryyqDTXGLkdRFh7mbXY"; + String dnaIdPassword = "123456"; + String salt = "oxsJG8zko2L8DqeLIFD27A=="; + String context = "credential:demo"; + String subjectDnaId = "did:dna:AND16ZNbMDe2W5z1X4gcZfrHs9G29G11w2"; + Map credentialInfo = new HashMap<>(); + credentialInfo.put("Name", "ABC"); + credentialInfo.put("Gender", "male"); + credentialInfo.put("SubjectDnaId", subjectDnaId); + long expires = 31536000000L; + String credential = createCred(issuerDnaId, dnaIdPassword, salt, context, credentialInfo, expires); + System.out.println("credential:" + credential); + } + + @Test + public void sendCredentialRecordTx() { + String issuerDnaId = "did:dna:AQFUKqrFdgR9A56ryyqDTXGLkdRFh7mbXY"; + String dnaIdPassword = "123456"; + String salt = "oxsJG8zko2L8DqeLIFD27A=="; + String subjectDnaId = "did:dna:AND16ZNbMDe2W5z1X4gcZfrHs9G29G11w2"; + String credential = "eyJhbGciOiJFUzI1NiIsImtpZCI6ImRpZDpkbmE6QVFGVUtxckZkZ1I5QTU2cnl5cURUWEdMa2RSRmg3bWJYWSNrZXlzLTEiLCJ0eXAiOiJKV1QifQ==.eyJpc3MiOiJkaWQ6ZG5hOkFRRlVLcXJGZGdSOUE1NnJ5eXFEVFhHTGtkUkZoN21iWFkiLCJleHAiOjE2NTk2MDE2MTIsIm5iZiI6MTYyODA2NTYxMiwiaWF0IjoxNjI4MDY1NjEyLCJqdGkiOiJ1cm46dXVpZDpmZjM1ZDZjZC0wNTQ1LTQyZTEtOGQ1Zi05YzAwMzY3OWQzYmUiLCJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vZG5haWQub250LmlvL2NyZWRlbnRpYWxzL3YxIiwiY3JlZGVudGlhbDpkZW1vIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiXSwiY3JlZGVudGlhbFN1YmplY3QiOnsiR2VuZGVyIjoibWFsZSIsIk5hbWUiOiJBQkMiLCJTdWJqZWN0RG5hSWQiOiJkaWQ6ZG5hOkFORDE2Wk5iTURlMlc1ejFYNGdjWmZySHM5RzI5RzExdzIifSwiY3JlZGVudGlhbFN0YXR1cyI6eyJpZCI6IjQ1ODY3NDI4NDg0Y2NkZmMxZDFhZDIwNWQ3MjVhYjcxNThmNWI2N2IiLCJ0eXBlIjoiQXR0ZXN0Q29udHJhY3QifSwicHJvb2YiOnsiY3JlYXRlZCI6IjIwMjEtMDgtMDRUMDg6MjY6NTJaIiwicHJvb2ZQdXJwb3NlIjoiYXNzZXJ0aW9uTWV0aG9kIn19fQ==.AbSjGYtWbj5EJV5Mpf+wzPTE8CTur6ACy6S54fl0x/ayRw0ndFAtST3duXmo0ZbdMKcXetBQeV5Fx2PrCTaltQM="; + String txHash = sendCredentialRecordTx(issuerDnaId, dnaIdPassword, salt, subjectDnaId, credential); + System.out.println("txHash:" + txHash); + } + + @Test + public void verifyCred() throws Exception { + String issuerDnaId = "did:dna:AQFUKqrFdgR9A56ryyqDTXGLkdRFh7mbXY"; + String dnaIdPassword = "123456"; + String salt = "oxsJG8zko2L8DqeLIFD27A=="; + String credential = "eyJhbGciOiJFUzI1NiIsImtpZCI6ImRpZDpkbmE6QVFGVUtxckZkZ1I5QTU2cnl5cURUWEdMa2RSRmg3bWJYWSNrZXlzLTEiLCJ0eXAiOiJKV1QifQ==.eyJpc3MiOiJkaWQ6ZG5hOkFRRlVLcXJGZGdSOUE1NnJ5eXFEVFhHTGtkUkZoN21iWFkiLCJleHAiOjE2NTk2MDE2MTIsIm5iZiI6MTYyODA2NTYxMiwiaWF0IjoxNjI4MDY1NjEyLCJqdGkiOiJ1cm46dXVpZDpmZjM1ZDZjZC0wNTQ1LTQyZTEtOGQ1Zi05YzAwMzY3OWQzYmUiLCJ2YyI6eyJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSIsImh0dHBzOi8vZG5haWQub250LmlvL2NyZWRlbnRpYWxzL3YxIiwiY3JlZGVudGlhbDpkZW1vIl0sInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiXSwiY3JlZGVudGlhbFN1YmplY3QiOnsiR2VuZGVyIjoibWFsZSIsIk5hbWUiOiJBQkMiLCJTdWJqZWN0RG5hSWQiOiJkaWQ6ZG5hOkFORDE2Wk5iTURlMlc1ejFYNGdjWmZySHM5RzI5RzExdzIifSwiY3JlZGVudGlhbFN0YXR1cyI6eyJpZCI6IjQ1ODY3NDI4NDg0Y2NkZmMxZDFhZDIwNWQ3MjVhYjcxNThmNWI2N2IiLCJ0eXBlIjoiQXR0ZXN0Q29udHJhY3QifSwicHJvb2YiOnsiY3JlYXRlZCI6IjIwMjEtMDgtMDRUMDg6MjY6NTJaIiwicHJvb2ZQdXJwb3NlIjoiYXNzZXJ0aW9uTWV0aG9kIn19fQ==.AbSjGYtWbj5EJV5Mpf+wzPTE8CTur6ACy6S54fl0x/ayRw0ndFAtST3duXmo0ZbdMKcXetBQeV5Fx2PrCTaltQM="; + boolean verify = verifyCred(issuerDnaId, dnaIdPassword, salt, credential); + System.out.println("verify:" + verify); + } + + @Test + public void checkEvent() throws Exception { + String txHash = "206b58fb8ed882e9d468f95a5d892f3c1d02ac2e1dfe33f21cd413b230e6add0"; + Object event = checkEvent(txHash); + System.out.println("event:" + event); + } + + + private String makeDeployCodeTransaction(String code, String name, String version, String author, String email, String desc) throws Exception { + DeployCode tx = dnaSdk.vm().makeDeployCodeTransaction(code, true, name, version, author, email, desc, PAYER_ADDRESS, 30000000, 0); + Account payer = new Account(Account.getPrivateKeyFromWIF(PAYER_WIF), dnaSdk.getWalletMgr().getSignatureScheme()); + dnaSdk.addSign(tx, payer); + dnaSdk.getConnect().sendRawTransaction(tx); + System.out.println("txHash:" + tx.hash().toString()); + String contractHash = Address.AddressFromVmCode(code).toHexString(); + return contractHash; + } + + private Map createDnaId(String pwd) throws Exception { + Account payerAcct = new Account(Account.getPrivateKeyFromWIF(PAYER_WIF), dnaSdk.getWalletMgr().getSignatureScheme()); + + Identity identity = createIdentity(dnaSdk, pwd); + String txhash = sendRegister(dnaSdk, identity, pwd, payerAcct, 25000, 0); + + Map keystore = WalletQR.exportIdentityQRCode(dnaSdk.getWalletMgr().getWallet(), identity); + keystore.put("publicKey", identity.controls.get(0).publicKey); + String keystoreStr = JSON.toJSONString(keystore); + String wif = exportWif(keystoreStr, pwd); + + HashMap res = new HashMap<>(); + res.put("dnaId", identity.dnaid); + res.put("keystore", keystoreStr); + res.put("tx", txhash); + res.put("wif", wif); + + return res; + } + + private String sendRegister(DnaSdk dnaSdk, Identity ident, String password, Account payerAcct, long gaslimit, long gasprice) throws Exception { + if (ident == null || password == null || password.equals("") || payerAcct == null) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + + String addr = ident.dnaid.replace(Common.diddna, ""); + String prikey = com.github.DNAProject.account.Account.getGcmDecodedPrivateKey(ident.controls.get(0).key, password, + addr, ident.controls.get(0).getSalt(), dnaSdk.getWalletMgr().getWalletFile().getScrypt().getN(), dnaSdk.getWalletMgr().getSignatureScheme()); + Account account = new Account(Helper.hexToBytes(prikey), dnaSdk.getWalletMgr().getSignatureScheme()); + + Transaction tx = makeRegister(dnaSdk, ident.dnaid, ident.controls.get(0).publicKey, payerAcct.getAddressU160().toBase58(), gaslimit, gasprice); + dnaSdk.addSign(tx, account); + dnaSdk.addSign(tx, payerAcct); + + boolean b = dnaSdk.getConnect().sendRawTransaction(tx.toHexString()); + if (!b) { + throw new SDKException(ErrorCode.SendRawTxError); + } + return tx.hash().toHexString(); + } + + private Transaction makeRegister(DnaSdk dnaSdk, String dnaId, String publickey, String payer, long gaslimit, long gasprice) throws Exception { + if (payer == null || payer.equals("")) { + throw new SDKException(ErrorCode.ParamErr("parameter should not be null")); + } + if (gasprice < 0 || gaslimit < 0) { + throw new SDKException(ErrorCode.ParamErr("gas or gaslimit should not be less than 0")); + } + + byte[] pk = Helper.hexToBytes(publickey); + + List list = new ArrayList(); + list.add(new Struct().add(dnaId, pk)); + byte[] args = NativeBuildParams.createCodeParamsScript(list); + Transaction tx = dnaSdk.vm().buildNativeParams(new Address(Helper.hexToBytes(DNAID_CONTRACT_ADDRESS)), "regIDWithPublicKey", args, payer, gaslimit, gasprice); + return tx; + } + + + private Identity createIdentity(DnaSdk dnaSdk, String password) throws Exception { + String label = ""; + byte[] prikey = ECC.generateKey(); + byte[] salt = ECC.generateKey(16); + Account account = new Account(prikey, dnaSdk.getWalletMgr().getSignatureScheme()); + com.github.DNAProject.sdk.wallet.Account acct; + switch (dnaSdk.getWalletMgr().getSignatureScheme()) { + case SHA256WITHECDSA: + acct = new com.github.DNAProject.sdk.wallet.Account("ECDSA", new Object[]{Curve.P256.toString()}, "aes-256-gcm", "SHA256withECDSA", "sha256"); + break; + case SM3WITHSM2: + acct = new com.github.DNAProject.sdk.wallet.Account("SM2", new Object[]{Curve.SM2P256V1.toString()}, "aes-256-gcm", "SM3withSM2", "sha256"); + break; + default: + throw new SDKException(ErrorCode.OtherError("scheme type error")); + } + if (password != null) { + acct.key = account.exportGcmEncryptedPrikey(password, salt, dnaSdk.getWalletMgr().getWalletFile().getScrypt().getN()); + } else { + acct.key = Helper.toHexString(account.serializePrivateKey()); + } + acct.address = Address.addressFromPubKey(account.serializePublicKey()).toBase58(); + if (label == null || label.equals("")) { + String uuidStr = UUID.randomUUID().toString(); + label = uuidStr.substring(0, 8); + } + + Identity idt = new Identity(); + idt.dnaid = Common.diddna + acct.address; + idt.label = label; + + idt.controls = new ArrayList(); + Control ctl = new Control(acct.key, "keys-1", Helper.toHexString(account.serializePublicKey())); + ctl.setSalt(salt); + ctl.setAddress(acct.address); + idt.controls.add(ctl); + return idt; + } + + private String exportWif(String keystore, String pwd) throws Exception { + Account account = exportAccount(keystore, pwd); + return account.exportWif(); + } + + private Account exportAccount(String keystoreBefore, String pwd) throws Exception { + String keystore = keystoreBefore.replace("\\", ""); + JSONObject jsonObject = JSON.parseObject(keystore); + String key = jsonObject.getString("key"); + String address = jsonObject.getString("address"); + String saltStr = jsonObject.getString("salt"); + + int scrypt = jsonObject.getJSONObject("scrypt").getIntValue("n"); + String privateKey = Account.getGcmDecodedPrivateKey(key, pwd, address, com.alibaba.fastjson.util.Base64.decodeFast(saltStr), scrypt, dnaSdk.getWalletMgr().getSignatureScheme()); + return new Account(Helper.hexToBytes(privateKey), dnaSdk.getWalletMgr().getSignatureScheme()); + } + + private Map createDnaId2(String pwd) throws Exception { + Account payerAcct = new Account(Account.getPrivateKeyFromWIF(PAYER_WIF), dnaSdk.getWalletMgr().getSignatureScheme()); + HashMap res = new HashMap<>(); + Identity identity = dnaSdk.getWalletMgr().createIdentity(pwd); + String txhash = dnaSdk.nativevm().dnaId().sendRegister(identity, pwd, payerAcct, 20000, 0); + dnaSdk.getWalletMgr().getWallet().clearIdentity(); + dnaSdk.getWalletMgr().writeWallet(); + Map keystore = WalletQR.exportIdentityQRCode(dnaSdk.getWalletMgr().getWallet(), identity); + keystore.put("publicKey", identity.controls.get(0).publicKey); + res.put("dnaId", identity.dnaid); + res.put("keystore", JSON.toJSONString(keystore)); + + res.put("tx", txhash); + dnaSdk.getWalletMgr().getWallet().clearIdentity(); + return res; + } + + private String createCred(String issuerDnaId, String dnaIdPassword, String salt, String context, Map credentialInfo, long expires) { + try { + Account issuerAcc = dnaSdk.getWalletMgr().getAccount(issuerDnaId, dnaIdPassword, java.util.Base64.getDecoder().decode(salt)); + DnaId2 issuer = new DnaId2(issuerDnaId, issuerAcc, dnaSdk.neovm().credentialRecord(), dnaSdk.nativevm().dnaId()); + Date expiration = new Date(System.currentTimeMillis() + expires); + String cred = issuer.createJWTCred(new String[]{context}, new String[]{}, issuerDnaId, credentialInfo, expiration, CredentialStatusType.AttestContract, ProofPurpose.assertionMethod); + return cred; + } catch (Exception e) { + System.out.println("createCred error..."); + e.printStackTrace(); + } + return ""; + } + + private String sendCredentialRecordTx(String issuerDnaId, String dnaIdPassword, String salt, String subjectDnaId, String credential) { + try { + Account issuerAcc = dnaSdk.getWalletMgr().getAccount(issuerDnaId, dnaIdPassword, java.util.Base64.getDecoder().decode(salt)); + DnaId2 issuer = new DnaId2(issuerDnaId, issuerAcc, dnaSdk.neovm().credentialRecord(), dnaSdk.nativevm().dnaId()); + + String txHash = issuer.commitCred(credential, subjectDnaId, issuerAcc, 20000, 0, dnaSdk); + return txHash; + } catch (Exception e) { + System.out.println("sendCredentialRecordTx error..."); + e.printStackTrace(); + } + return ""; + } + + private boolean verifyCred(String issuerDnaId, String dnaIdPassword, String salt, String credential) { + try { + Account issuerAcc = dnaSdk.getWalletMgr().getAccount(issuerDnaId, dnaIdPassword, java.util.Base64.getDecoder().decode(salt)); + DnaId2 issuer = new DnaId2(issuerDnaId, issuerAcc, dnaSdk.neovm().credentialRecord(), dnaSdk.nativevm().dnaId()); + String[] credibleDnaIds = new String[]{Common.diddna + issuerAcc.getAddressU160().toBase58()}; + boolean verify = issuer.verifyJWTCred(credibleDnaIds, credential); + return verify; + } catch (Exception e) { + System.out.println("createCred error..."); + e.printStackTrace(); + } + return false; + } + + private Object checkEvent(String txHash) throws Exception { + Object event = dnaSdk.getConnect().getSmartCodeEvent(txHash); + return event; + } +} + + diff --git a/src/test/java/com/github/DNAProject/credential/credentialTest.json b/src/test/java/com/github/DNAProject/credential/credentialTest.json new file mode 100644 index 0000000..119abc9 --- /dev/null +++ b/src/test/java/com/github/DNAProject/credential/credentialTest.json @@ -0,0 +1 @@ +{"accounts":[],"createTime":"2021-08-03T18:57:37Z","defaultAccountAddress":"","defaultDnaid":"","identities":[{"controls":[{"address":"","algorithm":"ECDSA","enc-alg":"aes-256-gcm","hash":"sha256","id":"","key":"1F0ARTRrOQZWGyXxtkgqHLca6ESMUQ+M+IhYtVPrz4F6QbJ/gVeOZlSD4fULWW8q","parameters":{"curve":"secp256r1"},"publicKey":"","salt":"oxsJG8zko2L8DqeLIFD27A=="}],"dnaid":"did:dna:AQFUKqrFdgR9A56ryyqDTXGLkdRFh7mbXY","isDefault":true,"label":"03c90548","lock":false}],"name":"com.github.DNAProject","scrypt":{"dkLen":64,"n":16384,"p":8,"r":8},"version":"1.0"} From 7469505050c94098f1e5090bfd05eba0227e7608 Mon Sep 17 00:00:00 2001 From: leej1012 Date: Tue, 26 Oct 2021 11:22:20 +0800 Subject: [PATCH 17/18] Update version to 2.1.0 --- docs/README.md | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index 4a23429..82fe45a 100644 --- a/docs/README.md +++ b/docs/README.md @@ -60,7 +60,7 @@ $ mvn clean install com.github.DNAProject DNA-java-sdk/artifactId> - 2.0.0 + 2.1.0 ``` diff --git a/pom.xml b/pom.xml index 85db965..d6c3985 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.github.DNAProject DNA-java-sdk - 2.0.0 + 2.1.0 UTF-8 From 08400743728bbc8ddcd4e89d0932aab56f3b7a33 Mon Sep 17 00:00:00 2001 From: leej1012 Date: Tue, 26 Oct 2021 11:26:24 +0800 Subject: [PATCH 18/18] Update version to 2.1.0 --- README.md | 4 ++-- docs/README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8b90b6c..5fe81ac 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@

JAVA SDK For DNA

-

Version 2.0.0

+

Version 2.1.0

## Overview @@ -37,7 +37,7 @@ Add maven dependency: com.github.DNAProject DNA-java-sdk/artifactId> - 2.0.0 + 2.1.0 ``` diff --git a/docs/README.md b/docs/README.md index 82fe45a..d97a957 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,6 +1,6 @@

DNA Java SDK 介绍

-

Version 2.0.0

+

Version 2.1.0

# 总体介绍