diff --git a/.gitignore b/.gitignore index a1c2a23..365fa67 100644 --- a/.gitignore +++ b/.gitignore @@ -1,23 +1,82 @@ -# Compiled class file +# Built application files +*.apk +*.ap_ +*.aab + +# Files for the ART/Dalvik VM +*.dex + +# Java class files *.class -# Log file +# Generated files +bin/ +gen/ +out/ + +# Gradle files +.gradle/ +build/ + +# Local configuration file (sdk path, etc) +local.properties +gradle.properties + +# Proguard folder generated by Eclipse +proguard/ + +# Log Files *.log -# BlueJ files -*.ctxt +# Android Studio Navigation editor temp files +.navigation/ + +# Android Studio captures folder +captures/ + +# IntelliJ +*.iml +.idea/workspace.xml +.idea/tasks.xml +.idea/gradle.xml +.idea/assetWizardSettings.xml +.idea/dictionaries +.idea/libraries +.idea/caches +# Android Studio 3 in .gitignore file. +.idea/caches/build_file_checksums.ser +.idea/modules.xml +.idea/codeStyles/Project.xml +.idea/codeStyles/codeStyleConfig.xml +.idea/misc.xml +.idea/runConfigurations.xml + +# Keystore files +# Uncomment the following lines if you do not want to check your keystore files in. +#*.jks +#*.keystore + +# External native build folder generated in Android Studio 2.2 and later +.externalNativeBuild + +# Google Services (e.g. APIs or Firebase) +# google-services.json + +# Freeline +freeline.py +freeline/ +freeline_project_description.json + +# Version control +vcs.xml -# Mobile Tools for Java (J2ME) -.mtj.tmp/ +# lint +lint/intermediates/ +lint/generated/ +lint/outputs/ +lint/tmp/ +# lint/reports/ -# Package Files # -*.jar -*.war -*.nar -*.ear -*.zip -*.tar.gz -*.rar +gradle.properties -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* +.idea \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..b1889b6 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,106 @@ +language: android +jdk: oraclejdk8 +env: + global: + - DATE=`date +"%Y-%m-%d-%H%M"` + - ANDROID_API=28 + - EMULATOR_API=25 + - ANDROID_BUILD_TOOLS=28.0.3 + - ABI=x86_64 + - EMU_FLAVOR=default # use google_apis flavor if no default flavor emulator + - ADB_INSTALL_TIMEOUT=10 # minutes + - TOOLS=${ANDROID_HOME}tools + - PATH=${ANDROID_HOME}:${ANDROID_HOME}emulator:${TOOLS}:${TOOLS}/bin:${ANDROID_HOME}platform-tools:${PATH} + - ARTIFACTORY_CONTEXT_URL=https://blockone.jfrog.io/blockone + - ARTIFACTORY_REPO=android-libs-scratch-local + - ARTIFACTORY_LIBS_PATH=https://blockone.jfrog.io/blockone/android-libs + +dist: trusty +android: + components: + - tools + - extra-google-google_play_services + - extra-google-m2repository + - extra-android-m2repository + +licenses: + - 'android-sdk-preview-license-.+' + - 'android-sdk-license-.+' + - 'google-gdk-license-.+' + + +before_cache: + - rm -f $HOME/.gradle/caches/modules-2/modules-2.lock +cache: + directories: + - $HOME/.gradle/caches/ + - $HOME/.gradle/wrapper/ + - $HOME/.android/build-cache + +before_script: + - echo no | ${ANDROID_HOME}tools/bin/avdmanager create avd --force -n test -k "system-images;android-$EMULATOR_API;$EMU_FLAVOR;$ABI" -c 10M + - emulator -verbose -avd test -no-accel -no-snapshot -no-window $AUDIO -camera-back none -camera-front none -selinux permissive -qemu -m 2048 & + - android-wait-for-emulator + - adb shell input keyevent 82 & + +before_install: + - echo "artifactory_username=$ARTIFACTORY_USERNAME" > gradle.properties + - echo "artifactory_password=$ARTIFACTORY_PASSWORD" >> gradle.properties + - echo "artifactory_path_android_libraries=$ARTIFACTORY_LIBS_PATH" >> gradle.properties + - echo "artifactory_contextURL=$ARTIFACTORY_CONTEXT_URL" >> gradle.properties + - echo "artifactory_repo=$ARTIFACTORY_REPO" >> gradle.properties + + +install: + - touch $HOME/.android/repositories.cfg + - yes | sdkmanager "platform-tools" >/dev/null + - yes | sdkmanager "build-tools;$ANDROID_BUILD_TOOLS" >/dev/null + - yes | sdkmanager "tools" >/dev/null + - yes | sdkmanager "platforms;android-$ANDROID_API" >/dev/null + - yes | sdkmanager "platforms;android-$EMULATOR_API" >/dev/null #for matrix builds, we want to also install the matrix version. + - yes | sdkmanager "system-images;android-$EMULATOR_API;$EMU_FLAVOR;$ABI" >/dev/null + + +script: + - "./gradlew clean check --stacktrace" + +before_deploy: + - echo "artifactory_username=$ARTIFACTORY_USERNAME" > gradle.properties + - echo "artifactory_password=$ARTIFACTORY_PASSWORD" >> gradle.properties + - echo "artifactory_path_android_libraries=$ARTIFACTORY_LIBS_PATH" >> gradle.properties + - echo "artifactory_contextURL=$ARTIFACTORY_CONTEXT_URL" >> gradle.properties + - echo "artifactory_repo=$ARTIFACTORY_REPO" >> gradle.properties + + +deploy: + - provider: script + skip_cleanup: true + script: "bash scripts/deploy-artifactory.sh 'android-libs-feature-local'" + on: + all_branches: true + condition: ${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH} =~ ^feature\/.*$ + # develop deploys + - provider: script + skip_cleanup: true + script: "bash scripts/deploy-artifactory.sh 'android-libs-dev-local'" + on: + branch: + - develop + # release branches and master + - provider: script + skip_cleanup: true + script: "bash scripts/deploy-artifactory.sh 'android-libs-release-local'" + on: + all_branches: true + condition: $TRAVIS_BRANCH == master || ${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH} =~ ^release\/.*$ + # tagged releases from master, go to distribution + - provider: script + skip_cleanup: true + script: "bash scripts/deploy-artifactory.sh 'eosiojavarpcprovider-product-eosio-dist'" + on: + tags: true + branch: master + +after_deploy: + - echo "cleaning up properties" + - rm gradle.properties diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..9d7da77 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,170 @@ +# Contributing to EOSIO SDK for Java: Android RPC Provider + +Interested in contributing? That's awesome! Here are some guidelines to get started quickly and easily: + +- [Reporting An Issue](#reporting-an-issue) + - [Bug Reports](#bug-reports) + - [Feature Requests](#feature-requests) + - [Change Requests](#change-requests) +- [Working on Android RPC Provider](#working-on-android-rpc-provider) + - [Feature Branches](#feature-branches) + - [Developing With Gradle Locally](#developing-with-gradle-locally) + - [Submitting Pull Requests](#submitting-pull-requests) + - [Testing and Quality Assurance](#testing-and-quality-assurance) + - [Code Style and Linting](#code-style-and-linting) +- [Conduct](#conduct) +- [Contributor License & Acknowledgments](#contributor-license--acknowledgments) +- [References](#references) + +## Reporting An Issue + +If you're about to raise an issue because you think you've found a problem with Android RPC Provider, or you'd like to make a request for a new feature in the codebase, or any other reason… please read this first. + +The GitHub issue tracker is the preferred channel for [bug reports](#bug-reports), [feature requests](#feature-requests), and [submitting pull requests](#submitting-pull-requests), but please respect the following restrictions: + +* Please **search for existing issues**. Help us keep duplicate issues to a minimum by checking to see if someone has already reported your problem or requested your idea. + +* Please **be civil**. Keep the discussion on topic and respect the opinions of others. See also our [Contributor Code of Conduct](#conduct). + +### Bug Reports + +A bug is a _demonstrable problem_ that is caused by the code in the repository. Good bug reports are extremely helpful - thank you! + +Guidelines for bug reports: + +1. **Use the GitHub issue search** — check if the issue has already been + reported. + +1. **Check if the issue has been fixed** — look for [closed issues in the + current milestone](/../../issues?q=is%3Aissue+is%3Aclosed) or try to reproduce it + using the latest `develop` branch. + +A good bug report shouldn't leave others needing to chase you down for more information. Be sure to include the details of your environment and relevant tests that demonstrate the failure. + +[Report a bug](/../../issues/new?title=Bug%3A) + +### Feature Requests + +Feature requests are welcome. Before you submit one be sure to have: + +1. **Use the GitHub search** and check the feature hasn't already been requested. +1. Take a moment to think about whether your idea fits with the scope and aims of the project. +1. Remember, it's up to *you* to make a strong case to convince the project's leaders of the merits of this feature. Please provide as much detail and context as possible, this means explaining the use case and why it is likely to be common. + +### Change Requests + +Change requests cover both architectural and functional changes to how Android RPC Provider works. If you have an idea for a new or different dependency, a refactor, or an improvement to a feature, etc - please be sure to: + +1. **Use the GitHub search** and check someone else didn't get there first +1. Take a moment to think about the best way to make a case for, and explain what you're thinking. Are you sure this shouldn't really be a [bug report](#bug-reports) or a [feature request](#feature-requests)? Is it really one idea or is it many? What's the context? What problem are you solving? Why is what you are suggesting better than what's already there? + +## Working on Android RPC Provider + +Code contributions are welcome and encouraged! If you are looking for a good place to start, check out the [good first issue](/../../labels/good%20first%20issue) label in GitHub issues. + +Also, please follow these guidelines when submitting code: + +### Feature Branches + +To get it out of the way: + +- **[develop](/../../tree/develop)** is the development branch. All work on the next release happens here so you should generally branch off `develop`. Do **NOT** use this branch for a production site. +- **[master](/../../tree/master)** contains the latest release of Android RPC Provider. This branch may be used in production. Do **NOT** use this branch to work on Android RPC Provider's source. + +### Developing With Gradle Locally + +By default, libraries are installed from remote Maven repositories through Gradle. If, however, you wish to develop locally and you'd like to integrate with locally-cloned versions of EOSIO SDK for Java and/or other Providers, follow these instructions: + +1. Clone this and other repos into the same directory, as siblings of one another. +1. Github repo of all libraries: + * [EOSIO SDK for Java](https://github.com/EOSIO/eosio-java): The core EOSIO SDK for Java library + * [RPC Provider](https://github.com/EOSIO/eosio-java-android-rpc-provider): The RPC provider implementation in the core library + * [ABIEOS Serialization Provider](https://github.com/EOSIO/eosio-java-android-abieos-serialization-provider): A pluggable serialization provider for EOSIO SDK for Java using ABIEOS (for transaction and action conversion between JSON and binary data representations) + * [Softkey Signature Provider](https://github.com/EOSIO/eosio-java-softkey-signature-provider): An example pluggable signature provider for EOSIO SDK for Java for signing transactions using in-memory keys (not for production use) +1. Import as a gradle project into your favorite IDE or build with gradle from the command line. +1. Develop! + +### Submitting Pull Requests + +Pull requests are awesome. If you're looking to raise a PR for something which doesn't have an open issue, please think carefully about [raising an issue](#reporting-an-issue) which your PR can close, especially if you're fixing a bug. This makes it more likely that there will be enough information available for your PR to be properly tested and merged. + +### Testing and Quality Assurance + +Never underestimate just how useful quality assurance is. If you're looking to get involved with the code base and don't know where to start, checking out and testing a pull request is one of the most useful things you could do. + +Essentially, [check out the latest develop branch](#working-on-rpc-provider), take it for a spin, and if you find anything odd, please follow the [bug report guidelines](#bug-reports) and let us know! + +### Code Style and Linting + +Android RPC Provider leverages [SonarLint](https://www.sonarlint.org/) for linting and the [Google Java Style Guide](https://github.com/google/styleguide) with tab size and indent set to 4, and continuation indent set to 8 for code format flagging. Once SonarLint is installed, linting warnings and errors will be flagged inline with squiggles. Automatic code formatting can be accomplished by downloading and importing the Google Java Style settings into your IDE. + +Please be sure to resolve any linting issues introduced by your contributions prior to requesting a review on your PR. + +## Conduct + +While contributing, please be respectful and constructive, so that participation in our project is a positive experience for everyone. + +Examples of behavior that contributes to creating a positive environment include: +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members + +Examples of unacceptable behavior include: +- The use of sexualized language or imagery and unwelcome sexual attention or advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others’ private information, such as a physical or electronic address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a professional setting + + + +## Contributor License & Acknowledgments + +Whenever you make a contribution to this project, you license your contribution under the same terms as set out in LICENSE, and you represent and warrant that you have the right to license your contribution under those terms. Whenever you make a contribution to this project, you also certify in the terms of the Developer’s Certificate of Origin set out below: + +``` +Developer Certificate of Origin +Version 1.1 + +Copyright (C) 2004, 2006 The Linux Foundation and its contributors. +1 Letterman Drive +Suite D4700 +San Francisco, CA, 94129 + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + + +Developer's Certificate of Origin 1.1 + +By making a contribution to this project, I certify that: + +(a) The contribution was created in whole or in part by me and I + have the right to submit it under the open source license + indicated in the file; or + +(b) The contribution is based upon previous work that, to the best + of my knowledge, is covered under an appropriate open source + license and I have the right under that license to submit that + work with modifications, whether created in whole or in part + by me, under the same open source license (unless I am + permitted to submit under a different license), as indicated + in the file; or + +(c) The contribution was provided directly to me by some other + person who certified (a), (b) or (c) and I have not modified + it. + +(d) I understand and agree that this project and the contribution + are public and that a record of the contribution (including all + personal information I submit with it, including my sign-off) is + maintained indefinitely and may be redistributed consistent with + this project or the open source license(s) involved. +``` + +## References + +* Overall CONTRIB adapted from https://github.com/mathjax/MathJax/blob/master/CONTRIBUTING.md +* Conduct section adapted from the Contributor Covenant, version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html diff --git a/LICENSE b/LICENSE index 5b582c8..28db19e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,12 @@ +<<<<<<< HEAD +Copyright (c) 2017-2019 block.one and its contributors. All rights reserved. + +The MIT License +======= MIT License Copyright (c) 2020 EOSIO +>>>>>>> 0ba26dfdbe619ea99d2a6d2b2839a79e7d04d49d Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -9,13 +15,23 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: +<<<<<<< HEAD +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. +======= The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. +>>>>>>> 0ba26dfdbe619ea99d2a6d2b2839a79e7d04d49d THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +<<<<<<< HEAD +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +======= OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +>>>>>>> 0ba26dfdbe619ea99d2a6d2b2839a79e7d04d49d diff --git a/README.md b/README.md index c5872a2..7245079 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,13 @@ ![Java Logo](img/java-logo.png) +<<<<<<< HEAD +# EOSIO SDK for Java: RPC Provider ![EOSIO Alpha](https://img.shields.io/badge/EOSIO-Alpha-blue.svg) + +[![Software License](https://img.shields.io/badge/license-MIT-lightgrey.svg)](/./LICENSE) +![Language Java](https://img.shields.io/badge/Language-Java-yellow.svg) +![](https://img.shields.io/badge/Deployment%20Target-Android%206%2B-blue.svg) + +A [RPC provider](https://github.com/EOSIO/eosio-java/tree/master#rpc-provider-protocol) implementation for use within [EOSIO SDK for Java](https://github.com/EOSIO/eosio-java) as a plugin. RPC providers are responsible for all [RPC calls to nodeos](https://developers.eos.io/eosio-nodeos/reference), as well as general network handling. +======= # EOSIO SDK for Java: Java RPC Provider ![EOSIO Alpha](https://img.shields.io/badge/EOSIO-Alpha-blue.svg) [![Software License](https://img.shields.io/badge/license-MIT-lightgrey.svg)](/./LICENSE) @@ -6,6 +15,7 @@ ![](https://img.shields.io/badge/Deployment%20Target-Java%208%2B-blue.svg) A Java [RPC provider](https://github.com/EOSIO/eosio-java/tree/master#rpc-provider-protocol) implementation for use within [EOSIO SDK for Java](https://github.com/EOSIO/eosio-java) as a plugin. RPC providers are responsible for all [RPC calls to nodeos](https://developers.eos.io/eosio-nodeos/reference), as well as general network handling. +>>>>>>> 0ba26dfdbe619ea99d2a6d2b2839a79e7d04d49d _All product and company names are trademarks™ or registered® trademarks of their respective holders. Use of them does not imply any affiliation with or endorsement by them._ @@ -14,13 +24,25 @@ _All product and company names are trademarks™ or registered® trademarks of t - [Prerequisites](#prerequisites) - [Installation](#installation) - [Direct Usage](#direct-usage) +<<<<<<< HEAD +======= - [Java Example App](#java-example-app) +>>>>>>> 0ba26dfdbe619ea99d2a6d2b2839a79e7d04d49d - [Releases](#releases) - [Want to Help?](#want-to-help) - [License & Legal](#license) ## Prerequisites +<<<<<<< HEAD +* Eclipse 4.5+ +* Gradle 4.10.1+ +* Gradle Plugin 3.3.0+ +* Java SE 8+ + +This project is compatible with server-side Java, as well as Android 6+. Therefore, any project depending on Java RPC Provider with [EOSIO SDK for Java](https://github.com/EOSIO/eosio-java) **must be a server-side Java or Android 6+ project**. Other RPC providers, however, can be created to support earlier Android versions or other platforms. If your project requires earlier Android version or alternate platform support, or if you'd like to create a RPC provider and have questions, please reach out to us by [logging an issue](/../../issues/new). +======= +>>>>>>> 0ba26dfdbe619ea99d2a6d2b2839a79e7d04d49d ## Installation @@ -33,6 +55,8 @@ implementation 'one.block:eosiojava:0.1.2' implementation 'one.block:eosiojavarpcprovider:0.1.1' ``` +<<<<<<< HEAD +======= You must also add the following to the `android` section of your application's `build.gradle`: ```groovy @@ -43,6 +67,7 @@ packagingOptions { exclude 'lib/x86_64/linux/libscrypt.so' } ``` +>>>>>>> 0ba26dfdbe619ea99d2a6d2b2839a79e7d04d49d The `build.gradle` files for the project currently include configurations for publishing the project to Artifactory. These should be removed if you are not planning to use Artifactory or you will encounter build errors. To do so, make the changes marked by comments throughout the files. Then refresh your gradle project. @@ -62,6 +87,8 @@ GetRawAbiRequest request = new GetRawAbiRequest("eosio.token"); GetRawAbiResponse response = rpcProvider.getRawAbi(request); String abi = response.getAbi(); String abiHash = response.getAbiHash(); +<<<<<<< HEAD +======= // Asynchronous call final EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( @@ -91,6 +118,7 @@ AsyncTask asyncTask = new AsyncTask>>>>>> 0ba26dfdbe619ea99d2a6d2b2839a79e7d04d49d ``` Please note that only the following five RPC endpoints have proper response marshalling: @@ -120,18 +148,30 @@ JSONArray jsonArray = new JSONArray(response); String balance = jsonArray.getString(0); ``` +<<<<<<< HEAD +## Releases + +2/26/20 + +Version 0.1.1 The version consumes the new eosio-java library version 0.1.2. +======= ## Java Example App If you'd like to see EOSIO SDK for Java: Java RPC Provider in action, check out our open source --a working application that fetches an account's token balance and pushes a transfer action. ## Releases +>>>>>>> 0ba26dfdbe619ea99d2a6d2b2839a79e7d04d49d ## Want to help? Interested in contributing? That's awesome! Here are some [Contribution Guidelines](./CONTRIBUTING.md) and the [Code of Conduct](./CONTRIBUTING.md#conduct). +<<<<<<< HEAD +We're always looking for ways to improve EOSIO SDK for Java: Java RPC Provider. Check out our [#enhancement Issues](/../../issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement) for ways you can pitch in. +======= We're always looking for ways to improve EOSIO SDK for Java: Android RPC Provider. Check out our [#enhancement Issues](/../../issues?q=is%3Aissue+is%3Aopen+label%3Aenhancement) for ways you can pitch in. +>>>>>>> 0ba26dfdbe619ea99d2a6d2b2839a79e7d04d49d ## License diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..21a712d --- /dev/null +++ b/build.gradle @@ -0,0 +1,27 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + jcenter() + mavenCentral() + } +} + +allprojects { + repositories { + jcenter() + mavenCentral() + //Remove maven{} block if you are not using Artifactory, otherwise define your own values in the gradle.properties file + maven { + credentials{ + username artifactory_username + password artifactory_password + } + url artifactory_path_android_libraries + } + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/eosiojavarpcprovider/.gitignore b/eosiojavarpcprovider/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/eosiojavarpcprovider/.gitignore @@ -0,0 +1 @@ +/build diff --git a/eosiojavarpcprovider/build.gradle b/eosiojavarpcprovider/build.gradle new file mode 100644 index 0000000..8a9aa5d --- /dev/null +++ b/eosiojavarpcprovider/build.gradle @@ -0,0 +1,89 @@ +plugins { + id 'java-library' + //Remove 'com.jfrog.artifactory' plugin if you are not using Artifactory + id 'com.jfrog.artifactory' version '4.10.0' + id 'maven-publish' + +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'one.block:eosiojava:0.2.0-amqp9' + + implementation 'org.jetbrains:annotations:17.0.0' + implementation (group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1.1') { + exclude group: 'org.hamcrest', module: 'hamcrest-core' + } + api 'com.squareup.retrofit2:retrofit:2.5.0' + api 'com.squareup.retrofit2:converter-gson:2.5.0' + api 'com.squareup.okhttp3:logging-interceptor:3.12.1' + + testImplementation 'junit:junit:4.12' + testImplementation 'org.mockito:mockito-core:3.0.0' + testImplementation 'org.powermock:powermock-module-junit4:2.0.2' + testImplementation 'org.powermock:powermock-api-mockito2:2.0.2' + testImplementation 'com.squareup.okhttp3:mockwebserver:3.12.1' +} + + +def libraryGroupId = 'one.block' +def libraryArtifactId = 'eosiojavarpcprovider' +def libraryVersion = '0.1.2-amqp2' + +task sourcesJar(type: Jar, dependsOn: classes){ + classifier = 'sources' + from sourceSets.main.allSource +} + +javadoc.failOnError = false +task javadocJar(type: Jar, dependsOn: javadoc){ + classifier = 'javadoc' + from javadoc.destinationDir +} + +artifacts { + archives sourcesJar + archives javadocJar +} + +publishing { + publications { + jar(MavenPublication) { + from components.java + + artifact sourcesJar { + classifier "sources" + } + + artifact javadocJar { + classifier "javadoc" + } + + groupId libraryGroupId + version libraryVersion + artifactId libraryArtifactId + + artifact("$buildDir/libs/${artifactId}.jar") + } + } +} + +//Remove artifactory{} block if you are not using Artifactory +artifactory { + contextUrl = artifactory_contextURL + publish { + repository { + repoKey = artifactory_repo + + username = artifactory_username + password = artifactory_password + } + defaults { + publications('jar') + publishArtifacts = true + + properties = ['qa.level': 'basic', 'q.os': 'android', 'dev.team': 'core'] + publishPom = true + } + } +} diff --git a/eosiojavarpcprovider/proguard-rules.pro b/eosiojavarpcprovider/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/eosiojavarpcprovider/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/eosiojavarpcprovider/src/main/java/one/block/eosiojavarpcprovider/error/EosioJavaRpcErrorConstants.java b/eosiojavarpcprovider/src/main/java/one/block/eosiojavarpcprovider/error/EosioJavaRpcErrorConstants.java new file mode 100644 index 0000000..843abc0 --- /dev/null +++ b/eosiojavarpcprovider/src/main/java/one/block/eosiojavarpcprovider/error/EosioJavaRpcErrorConstants.java @@ -0,0 +1,148 @@ +package one.block.eosiojavarpcprovider.error; +// +// Copyright © 2017-2019 block.one. +// + +import okhttp3.RequestBody; +import one.block.eosiojava.models.rpcProvider.request.GetBlockRequest; +import one.block.eosiojava.models.rpcProvider.request.GetRawAbiRequest; +import one.block.eosiojava.models.rpcProvider.request.GetRequiredKeysRequest; +import one.block.eosiojava.models.rpcProvider.request.SendTransactionRequest; +import one.block.eosiojava.models.rpcProvider.response.RPCResponseError; +import one.block.eosiojavarpcprovider.implementations.EosioJavaRpcProviderImpl; + +/** + * Error constants used in error messages thrown by the RPC Provider. + */ +public class EosioJavaRpcErrorConstants { + + // region EosioRpcProvderImpl errors + + /** + * Error message gets thrown if input Base URL is empty. + */ + public static final String RPC_PROVIDER_BASE_URL_EMPTY = "Base URL cannot be empty or null."; + + /** + * Error message gets thrown if {@link EosioJavaRpcProviderImpl#getInfo()} returns error. + */ + public static final String RPC_PROVIDER_ERROR_GETTING_CHAIN_INFO = "Error retrieving chain information."; + + /** + * Error message gets thrown if {@link EosioJavaRpcProviderImpl#getBlock(GetBlockRequest)} returns error. + */ + public static final String RPC_PROVIDER_ERROR_GETTING_BLOCK_INFO = "Error retrieving block information."; + + /** + * Error message gets thrown if {@link EosioJavaRpcProviderImpl#getRawAbi(GetRawAbiRequest)} returns error. + */ + public static final String RPC_PROVIDER_ERROR_GETTING_RAW_ABI = "Error retrieving raw ABI."; + + /** + * Error message gets thrown if {@link EosioJavaRpcProviderImpl#getRequiredKeys(GetRequiredKeysRequest)} returns error. + */ + public static final String RPC_PROVIDER_ERROR_GETTING_REQUIRED_KEYS = "Error retrieving required keys."; + + /** + * Error message gets thrown if {@link EosioJavaRpcProviderImpl#sendTransaction(SendTransactionRequest)} returns error. + */ + public static final String RPC_PROVIDER_ERROR_SENDING_TRANSACTION = "Error sending transaction."; + + /** + * Error message gets thrown if {@link EosioJavaRpcProviderImpl#pushTransactions(RequestBody)} returns error. + */ + public static final String RPC_PROVIDER_ERROR_PUSHING_TRANSACTIONS = "Error pushing transactions."; + + /** + * Error message gets thrown if {@link EosioJavaRpcProviderImpl#getAccount(RequestBody)} returns error. + */ + public static final String RPC_PROVIDER_ERROR_GET_ACCOUNT = "Error get account."; + + /** + * Error message gets thrown if {@link EosioJavaRpcProviderImpl#getBlock(GetBlockRequest)} returns error. + */ + public static final String RPC_PROVIDER_ERROR_GET_BLOCK_HEADER_STATE = "Error get block header state."; + + /** + * Error message gets thrown if {@link EosioJavaRpcProviderImpl#getAbi(RequestBody)} returns error. + */ + public static final String RPC_PROVIDER_ERROR_GET_ABI = "Error get abi."; + + /** + * Error message gets thrown if {@link EosioJavaRpcProviderImpl#getCurrencyBalance(RequestBody)} returns error. + */ + public static final String RPC_PROVIDER_ERROR_GET_CURRENT_BALANCE = "Error get current balance."; + + /** + * Error message gets thrown if {@link EosioJavaRpcProviderImpl#getCurrencyStats(RequestBody)} returns error. + */ + public static final String RPC_PROVIDER_ERROR_GET_CURRENT_STATS = "Error get current stats."; + + /** + * Error message gets thrown if {@link EosioJavaRpcProviderImpl#getProducers(RequestBody)} returns error. + */ + public static final String RPC_PROVIDER_ERROR_GET_PRODUCERS = "Error get producers."; + + /** + * Error message gets thrown if {@link EosioJavaRpcProviderImpl#getRawCodeAndAbi(RequestBody)} returns error. + */ + public static final String RPC_PROVIDER_ERROR_GET_RAW_CODE_AND_ABI = "Error get raw code and abi."; + + /** + * Error message gets thrown if {@link EosioJavaRpcProviderImpl#getTableByScope(RequestBody)} returns error. + */ + public static final String RPC_PROVIDER_ERROR_GET_TABLE_BY_SCOPE = "Error get table by scope."; + + /** + * Error message gets thrown if {@link EosioJavaRpcProviderImpl#getTableRows(RequestBody)} returns error. + */ + public static final String RPC_PROVIDER_ERROR_GET_TABLE_ROWS = "Error get table rows."; + + /** + * Error message gets thrown if {@link EosioJavaRpcProviderImpl#getCode(RequestBody)} returns error. + */ + public static final String RPC_PROVIDER_ERROR_GET_CODE = "Error get code."; + + /** + * Error message gets thrown if {@link EosioJavaRpcProviderImpl#getActions(RequestBody)} returns error. + */ + public static final String RPC_PROVIDER_ERROR_GET_ACTION = "Error get action."; + + /** + * Error message gets thrown if {@link EosioJavaRpcProviderImpl#getTransaction(RequestBody)} returns error. + */ + public static final String RPC_PROVIDER_ERROR_GET_TRANSACTION = "Error get transaction."; + + /** + * Error message gets thrown if {@link EosioJavaRpcProviderImpl#getKeyAccounts(RequestBody)} returns error. + */ + public static final String RPC_PROVIDER_ERROR_GET_KEY_ACCOUNTS = "Error get key accounts."; + + /** + * Error message gets thrown if {@link EosioJavaRpcProviderImpl#getControlledAccounts(RequestBody)} returns error. + */ + public static final String RPC_PROVIDER_ERROR_GET_CONTROLLED_ACCOUNTS = "Error get controlled accounts."; + + /** + * Error message gets thrown if RPC call returns bad status code from server. + */ + public static final String RPC_PROVIDER_BAD_STATUS_CODE_RETURNED = "Bad status code: %d (%s), returned from server. Additional error information: %s"; + + /** + * Error message gets thrown if RPC call returns empty response. + */ + public static final String RPC_PROVIDER_EMPTY_RESPONSE_RETURNED = "Empty response returned from the server."; + + /** + * Default error message for failed RPC call if there is no expected error return. + */ + public static final String RPC_PROVIDER_NO_FURTHER_ERROR_INFO = "No further error information available."; + + /** + * Error message is a reference to {@link RPCResponseError} for additional information. + */ + public static final String RPC_PROVIDER_SEE_FURTHER_ERROR_INFO = "See further error information in RPCProviderError."; + + // endregion + +} \ No newline at end of file diff --git a/eosiojavarpcprovider/src/main/java/one/block/eosiojavarpcprovider/error/EosioJavaRpcProviderCallError.java b/eosiojavarpcprovider/src/main/java/one/block/eosiojavarpcprovider/error/EosioJavaRpcProviderCallError.java new file mode 100644 index 0000000..6d5816b --- /dev/null +++ b/eosiojavarpcprovider/src/main/java/one/block/eosiojavarpcprovider/error/EosioJavaRpcProviderCallError.java @@ -0,0 +1,61 @@ +package one.block.eosiojavarpcprovider.error; + +import one.block.eosiojava.error.rpcProvider.RpcProviderError; +import one.block.eosiojava.models.rpcProvider.response.RPCResponseError; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +// +// Copyright © 2017-2019 block.one. +// + +/** + * Error thrown when there is a lower level processing error sending or receiving an RPC call. + */ +public class EosioJavaRpcProviderCallError extends RpcProviderError { + + /** + * Contains additional information about errors coming back from the blockchain, if available. + */ + @Nullable + private RPCResponseError rpcResponseError; + + public EosioJavaRpcProviderCallError() { + } + + public EosioJavaRpcProviderCallError(@NotNull String message) { + super(message); + } + + public EosioJavaRpcProviderCallError(@NotNull String message, + @Nullable RPCResponseError rpcResponseError) { + super(message); + this.rpcResponseError = rpcResponseError; + } + + public EosioJavaRpcProviderCallError(@NotNull String message, + @NotNull Exception exception) { + super(message, exception); + } + + public EosioJavaRpcProviderCallError( + @NotNull Exception exception) { + super(exception); + } + + public EosioJavaRpcProviderCallError(@NotNull String message, + @NotNull Exception exception, + @Nullable RPCResponseError rpcRepsonseError) { + super(message, exception); + this.rpcResponseError = rpcRepsonseError; + } + + public RPCResponseError getRpcResponseError() { + return rpcResponseError; + } + + public void setRpcResponseError( + RPCResponseError rpcResponseError) { + this.rpcResponseError = rpcResponseError; + } +} diff --git a/eosiojavarpcprovider/src/main/java/one/block/eosiojavarpcprovider/error/EosioJavaRpcProviderInitializerError.java b/eosiojavarpcprovider/src/main/java/one/block/eosiojavarpcprovider/error/EosioJavaRpcProviderInitializerError.java new file mode 100644 index 0000000..7e51f38 --- /dev/null +++ b/eosiojavarpcprovider/src/main/java/one/block/eosiojavarpcprovider/error/EosioJavaRpcProviderInitializerError.java @@ -0,0 +1,34 @@ +package one.block.eosiojavarpcprovider.error; + +import one.block.eosiojava.error.rpcProvider.RpcProviderError; +import org.jetbrains.annotations.NotNull; + +// +// Copyright © 2017-2019 block.one. +// + +/** + * Error thrown when there is an issue initializing the RPC Provider. + */ +public class EosioJavaRpcProviderInitializerError extends RpcProviderError { + + public EosioJavaRpcProviderInitializerError() { + } + + public EosioJavaRpcProviderInitializerError( + @NotNull String message) { + super(message); + } + + public EosioJavaRpcProviderInitializerError( + @NotNull String message, + @NotNull Exception exception) { + super(message, exception); + } + + public EosioJavaRpcProviderInitializerError( + @NotNull Exception exception) { + super(exception); + } + +} diff --git a/eosiojavarpcprovider/src/main/java/one/block/eosiojavarpcprovider/error/package-info.java b/eosiojavarpcprovider/src/main/java/one/block/eosiojavarpcprovider/error/package-info.java new file mode 100644 index 0000000..509850a --- /dev/null +++ b/eosiojavarpcprovider/src/main/java/one/block/eosiojavarpcprovider/error/package-info.java @@ -0,0 +1,6 @@ +/** + * Provides the classes necessary to describe meaningful exceptions that occur during an RPC provider implementation like: + * {@link one.block.eosiojava.error.rpcProvider.GetInfoRpcError} and {@link one.block.eosiojavarpcprovider.error.EosioJavaRpcErrorConstants}. + */ + +package one.block.eosiojavarpcprovider.error; \ No newline at end of file diff --git a/eosiojavarpcprovider/src/main/java/one/block/eosiojavarpcprovider/implementations/EosioJavaRpcProviderImpl.java b/eosiojavarpcprovider/src/main/java/one/block/eosiojavarpcprovider/implementations/EosioJavaRpcProviderImpl.java new file mode 100644 index 0000000..c943ebc --- /dev/null +++ b/eosiojavarpcprovider/src/main/java/one/block/eosiojavarpcprovider/implementations/EosioJavaRpcProviderImpl.java @@ -0,0 +1,473 @@ +package one.block.eosiojavarpcprovider.implementations; + +import com.google.gson.Gson; + +import org.jetbrains.annotations.NotNull; + +import java.util.Locale; + +import okhttp3.OkHttpClient; +import okhttp3.RequestBody; +import okhttp3.ResponseBody; +import okhttp3.logging.HttpLoggingInterceptor; +import okhttp3.logging.HttpLoggingInterceptor.Level; +import one.block.eosiojava.error.rpcProvider.GetBlockRpcError; +import one.block.eosiojava.error.rpcProvider.GetInfoRpcError; +import one.block.eosiojava.error.rpcProvider.GetRawAbiRpcError; +import one.block.eosiojava.error.rpcProvider.GetRequiredKeysRpcError; +import one.block.eosiojava.error.rpcProvider.SendTransactionRpcError; +import one.block.eosiojava.error.rpcProvider.RpcProviderError; +import one.block.eosiojava.interfaces.IRPCProvider; +import one.block.eosiojava.models.rpcProvider.request.GetBlockRequest; +import one.block.eosiojava.models.rpcProvider.request.GetRawAbiRequest; +import one.block.eosiojava.models.rpcProvider.request.GetRequiredKeysRequest; +import one.block.eosiojava.models.rpcProvider.request.SendTransactionRequest; +import one.block.eosiojava.models.rpcProvider.response.GetBlockResponse; +import one.block.eosiojava.models.rpcProvider.response.GetInfoResponse; +import one.block.eosiojava.models.rpcProvider.response.GetRawAbiResponse; +import one.block.eosiojava.models.rpcProvider.response.GetRequiredKeysResponse; +import one.block.eosiojava.models.rpcProvider.response.SendTransactionResponse; +import one.block.eosiojava.models.rpcProvider.response.RPCResponseError; +import one.block.eosiojavarpcprovider.error.EosioJavaRpcErrorConstants; +import one.block.eosiojavarpcprovider.error.EosioJavaRpcProviderCallError; +import one.block.eosiojavarpcprovider.error.EosioJavaRpcProviderInitializerError; +import retrofit2.Call; +import retrofit2.Response; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +// +// Copyright © 2017-2019 block.one. +// + +/** + * Simple implementation of an RPC provider for communicating with the blockchain. + * The calls are implemented synchronously. It is assumed that the developer will + * wrap them in asynchronous semantics such as AsyncTask in normal use... + */ +public class EosioJavaRpcProviderImpl implements IRPCProvider { + + @NotNull + private String baseURL; + + @NotNull + private Retrofit retrofit; + + @NotNull + private IEosioJavaRpcProviderApi rpcProviderApi; + + /** + * Construct a new RPC provider instance given the base URL to use for building requests. + * @param baseURL Base URL to use for building requests. + * @throws EosioJavaRpcProviderInitializerError thrown if the base URL passed in is null. + */ + public EosioJavaRpcProviderImpl(@NotNull String baseURL) throws EosioJavaRpcProviderInitializerError { + this(baseURL, false); + } + + /** + * Construct a new RPC provider instance given the base URL to use for building requests. + * @param baseURL Base URL to use for building requests. + * @param enableDebug Enable Network Log at {@link Level#BODY} level + * @throws EosioJavaRpcProviderInitializerError thrown if the base URL passed in is null. + */ + public EosioJavaRpcProviderImpl(@NotNull String baseURL, boolean enableDebug) throws EosioJavaRpcProviderInitializerError { + if(baseURL == null || baseURL.isEmpty()) { + throw new EosioJavaRpcProviderInitializerError(EosioJavaRpcErrorConstants.RPC_PROVIDER_BASE_URL_EMPTY); + } + + this.baseURL = baseURL; + OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); + if (enableDebug) { + HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor(); + httpLoggingInterceptor.setLevel(Level.BODY); + httpClient.addInterceptor(httpLoggingInterceptor); + } + + this.retrofit = new Retrofit.Builder() + .baseUrl(this.baseURL) + .addConverterFactory(GsonConverterFactory.create()) + .client(httpClient.build()) + .build(); + + this.rpcProviderApi = this.retrofit.create(IEosioJavaRpcProviderApi.class); + } + + /** + * Process a retrofit call, setting arguments, checking responses and decoding responses and errors + * as necessary. + * @param call Retrofit call to execute. + * @param Response type to use for decoding. + * @return Response type given in signature. + * @throws Exception Can throw EosioJavaRpcProviderCallError for RPC provider specific + * processing errors or Java IO or network errors from Retrofit. + */ + @NotNull + private O processCall(Call call) throws Exception { + Response response = call.execute(); + if (!response.isSuccessful()) { + String additionalErrInfo = EosioJavaRpcErrorConstants.RPC_PROVIDER_NO_FURTHER_ERROR_INFO; + + RPCResponseError rpcResponseError = null; + if (response.errorBody() != null) { + Gson gson = new Gson(); + rpcResponseError = gson.fromJson(response.errorBody().charStream(), RPCResponseError.class); + if (rpcResponseError == null) { + additionalErrInfo = response.errorBody().string(); + } else { + additionalErrInfo = EosioJavaRpcErrorConstants.RPC_PROVIDER_SEE_FURTHER_ERROR_INFO; + } + } + + String msg = String.format(Locale.getDefault(), EosioJavaRpcErrorConstants.RPC_PROVIDER_BAD_STATUS_CODE_RETURNED, + response.code(), response.message(), additionalErrInfo); + throw new EosioJavaRpcProviderCallError(msg, rpcResponseError); + } + if (response.body() == null) { + throw new EosioJavaRpcProviderCallError(EosioJavaRpcErrorConstants.RPC_PROVIDER_EMPTY_RESPONSE_RETURNED); + } + return response.body(); + } + + /** + * Issue a getInfo() call to the blockchain and process the response. + * @return GetInfoResponse on successful return. + * @throws GetInfoRpcError Thrown if any errors occur calling or processing the request. + */ + @Override + public @NotNull GetInfoResponse getInfo() throws GetInfoRpcError { + try { + Call syncCall = this.rpcProviderApi.getInfo(); + return processCall(syncCall); + } catch (Exception ex) { + throw new GetInfoRpcError(EosioJavaRpcErrorConstants.RPC_PROVIDER_ERROR_GETTING_CHAIN_INFO, + ex); + } + } + + /** + * Issue a getBlock() call to the blockchain and process the response. + * @param getBlockRequest Info about a specific block. + * @return GetBlockRsponse on successful return. + * @throws GetBlockRpcError Thrown if any errors occur calling or processing the request. + */ + @Override + public @NotNull GetBlockResponse getBlock(GetBlockRequest getBlockRequest) + throws GetBlockRpcError { + try { + Call syncCall = this.rpcProviderApi.getBlock(getBlockRequest); + return processCall(syncCall); + } catch (Exception ex) { + throw new GetBlockRpcError(EosioJavaRpcErrorConstants.RPC_PROVIDER_ERROR_GETTING_BLOCK_INFO, + ex); + } + } + + /** + * Issue a getRawAbi() request to the blockchain and process the response. + * @param getRawAbiRequest Info about a specific smart contract. + * @return GetRawAbiResponse on successful return. + * @throws GetRawAbiRpcError Thrown if any errors occur calling or processing the request. + */ + @Override + public @NotNull GetRawAbiResponse getRawAbi(GetRawAbiRequest getRawAbiRequest) + throws GetRawAbiRpcError { + try { + Call syncCall = this.rpcProviderApi.getRawAbi(getRawAbiRequest); + return processCall(syncCall); + } catch (Exception ex) { + throw new GetRawAbiRpcError(EosioJavaRpcErrorConstants.RPC_PROVIDER_ERROR_GETTING_RAW_ABI, + ex); + } + } + + /** + * Issue a getRequiredKeys() request to the blockchain and process the response. + * @param getRequiredKeysRequest Info to get required keys + * @return GetRequiredKeysResponse on successful return. + * @throws GetRequiredKeysRpcError Thrown if any errors occur calling or processing the request. + */ + @Override + public @NotNull GetRequiredKeysResponse getRequiredKeys( + GetRequiredKeysRequest getRequiredKeysRequest) throws GetRequiredKeysRpcError { + try { + Call syncCall = this.rpcProviderApi.getRequiredKeys(getRequiredKeysRequest); + return processCall(syncCall); + } catch (Exception ex) { + throw new GetRequiredKeysRpcError(EosioJavaRpcErrorConstants.RPC_PROVIDER_ERROR_GETTING_REQUIRED_KEYS, + ex); + } + } + + /** + * Send a given transaction to the blockchain and process the response. + * @param sendTransactionRequest the transaction to send with signatures. + * @return SendTransactionResponse on successful return. + * @throws SendTransactionRpcError Thrown if any errors occur calling or processing the request. + */ + public @NotNull SendTransactionResponse sendTransaction( + SendTransactionRequest sendTransactionRequest) throws SendTransactionRpcError { + try { + Call syncCall = this.rpcProviderApi.sendTransaction(sendTransactionRequest); + return processCall(syncCall); + } catch (Exception ex) { + throw new SendTransactionRpcError(EosioJavaRpcErrorConstants.RPC_PROVIDER_ERROR_SENDING_TRANSACTION, + ex); + } + } + + /** + * Issue a get_account call to the blockchain and process the response. + * @param requestBody request body of get_account API + * @return String content of ResponseBody on successful return. + * @throws RpcProviderError Thrown if any errors occur calling or processing the request. + */ + public @NotNull String getAccount(RequestBody requestBody) throws RpcProviderError { + try { + Call syncCall = this.rpcProviderApi.getAccount(requestBody); + try(ResponseBody responseBody = processCall(syncCall)) { + return responseBody.string(); + } + } catch (Exception ex) { + throw new RpcProviderError(EosioJavaRpcErrorConstants.RPC_PROVIDER_ERROR_GET_ACCOUNT, ex); + } + } + + /** + * Issue a pushTransactions() call to the blockchain and process the response. + * @param requestBody request body of push_transactions API + * @return String content of ResponseBody on successful return. + * @throws RpcProviderError Thrown if any errors occur calling or processing the request. + */ + public @NotNull String pushTransactions(RequestBody requestBody) throws RpcProviderError { + try { + Call syncCall = this.rpcProviderApi.pushTransactions(requestBody); + try(ResponseBody responseBody = processCall(syncCall)) { + return responseBody.string(); + } + } catch (Exception ex) { + throw new RpcProviderError(EosioJavaRpcErrorConstants.RPC_PROVIDER_ERROR_PUSHING_TRANSACTIONS, ex); + } + } + + /** + * Issue a getBlockHeaderState() call to the blockchain and process the response. + * @param requestBody request body of get_block_header_state API + * @return String content of ResponseBody on successful return. + * @throws RpcProviderError Thrown if any errors occur calling or processing the request. + */ + public @NotNull String getBlockHeaderState(RequestBody requestBody) throws RpcProviderError { + try { + Call syncCall = this.rpcProviderApi.getBlockHeaderState(requestBody); + try(ResponseBody responseBody = processCall(syncCall)) { + return responseBody.string(); + } + } catch (Exception ex) { + throw new RpcProviderError(EosioJavaRpcErrorConstants.RPC_PROVIDER_ERROR_GET_BLOCK_HEADER_STATE, ex); + } + } + + /** + * Issue a getAbi() call to the blockchain and process the response. + * @param requestBody request body of get_abi API + * @return String content of ResponseBody on successful return. + * @throws RpcProviderError Thrown if any errors occur calling or processing the request. + */ + public @NotNull String getAbi(RequestBody requestBody) throws RpcProviderError { + try { + Call syncCall = this.rpcProviderApi.getAbi(requestBody); + try(ResponseBody responseBody = processCall(syncCall)) { + return responseBody.string(); + } + } catch (Exception ex) { + throw new RpcProviderError(EosioJavaRpcErrorConstants.RPC_PROVIDER_ERROR_GET_ABI, ex); + } + } + + /** + * Issue a getCurrencyBalance call to the blockchain and process the response. + * @param requestBody request body of get_currency_balance API + * @return String content of ResponseBody on successful return. + * @throws RpcProviderError Thrown if any errors occur calling or processing the request. + */ + public @NotNull String getCurrencyBalance(RequestBody requestBody) throws RpcProviderError { + try { + Call syncCall = this.rpcProviderApi.getCurrencyBalance(requestBody); + try(ResponseBody responseBody = processCall(syncCall)) { + return responseBody.string(); + } + } catch (Exception ex) { + throw new RpcProviderError(EosioJavaRpcErrorConstants.RPC_PROVIDER_ERROR_GET_CURRENT_BALANCE, ex); + } + } + + /** + * Issue a getCurrencyStats() call to the blockchain and process the response. + * @param requestBody request body of get_currency_stats API + * @return String content of ResponseBody on successful return. + * @throws RpcProviderError Thrown if any errors occur calling or processing the request. + */ + public @NotNull String getCurrencyStats(RequestBody requestBody) throws RpcProviderError { + try { + Call syncCall = this.rpcProviderApi.getCurrencyStats(requestBody); + try(ResponseBody responseBody = processCall(syncCall)) { + return responseBody.string(); + } + } catch (Exception ex) { + throw new RpcProviderError(EosioJavaRpcErrorConstants.RPC_PROVIDER_ERROR_GET_CURRENT_STATS, ex); + } + } + + /** + * Issue a getProducers() call to the blockchain and process the response. + * @param requestBody request body of get_producers API + * @return String content of ResponseBody on successful return. + * @throws RpcProviderError Thrown if any errors occur calling or processing the request. + */ + public @NotNull String getProducers(RequestBody requestBody) throws RpcProviderError { + try { + Call syncCall = this.rpcProviderApi.getProducers(requestBody); + try(ResponseBody responseBody = processCall(syncCall)) { + return responseBody.string(); + } + } catch (Exception ex) { + throw new RpcProviderError(EosioJavaRpcErrorConstants.RPC_PROVIDER_ERROR_GET_PRODUCERS, ex); + } + } + + /** + * Issue a getRawCodeAndAbi() call to the blockchain and process the response. + * @param requestBody request body of get_raw_code_and_abi API + * @return String content of ResponseBody on successful return. + * @throws RpcProviderError Thrown if any errors occur calling or processing the request. + */ + public @NotNull String getRawCodeAndAbi(RequestBody requestBody) throws RpcProviderError { + try { + Call syncCall = this.rpcProviderApi.getRawCodeAndAbi(requestBody); + try(ResponseBody responseBody = processCall(syncCall)) { + return responseBody.string(); + } + } catch (Exception ex) { + throw new RpcProviderError(EosioJavaRpcErrorConstants.RPC_PROVIDER_ERROR_GET_RAW_CODE_AND_ABI, ex); + } + } + + /** + * Issue a getTableByScope() call to the blockchain and process the response. + * @param requestBody request body of get_table_by_scope API + * @return String content of ResponseBody on successful return. + * @throws RpcProviderError Thrown if any errors occur calling or processing the request. + */ + public @NotNull String getTableByScope(RequestBody requestBody) throws RpcProviderError { + try { + Call syncCall = this.rpcProviderApi.getTableByScope(requestBody); + try(ResponseBody responseBody = processCall(syncCall)) { + return responseBody.string(); + } + } catch (Exception ex) { + throw new RpcProviderError(EosioJavaRpcErrorConstants.RPC_PROVIDER_ERROR_GET_TABLE_BY_SCOPE, ex); + } + } + + /** + * Issue a getTableRows() call to the blockchain and process the response. + * @param requestBody request body of get_table_rows API + * @return String content of ResponseBody on successful return. + * @throws RpcProviderError Thrown if any errors occur calling or processing the request. + */ + public @NotNull String getTableRows(RequestBody requestBody) throws RpcProviderError { + try { + Call syncCall = this.rpcProviderApi.getTableRows(requestBody); + try(ResponseBody responseBody = processCall(syncCall)) { + return responseBody.string(); + } + } catch (Exception ex) { + throw new RpcProviderError(EosioJavaRpcErrorConstants.RPC_PROVIDER_ERROR_GET_TABLE_ROWS, ex); + } + } + + /** + * Issue a getCode() call to the blockchain and process the response. + * @param requestBody request body of get_code API + * @return String content of ResponseBody on successful return. + * @throws RpcProviderError Thrown if any errors occur calling or processing the request. + */ + public @NotNull String getCode(RequestBody requestBody) throws RpcProviderError { + try { + Call syncCall = this.rpcProviderApi.getCode(requestBody); + try(ResponseBody responseBody = processCall(syncCall)) { + return responseBody.string(); + } + } catch (Exception ex) { + throw new RpcProviderError(EosioJavaRpcErrorConstants.RPC_PROVIDER_ERROR_GET_CODE, ex); + } + } + + /** + * Issue a getActions() call to the blockchain and process the response. + * @param requestBody request body of get_actions API + * @return String content of ResponseBody on successful return. + * @throws RpcProviderError Thrown if any errors occur calling or processing the request. + */ + public @NotNull String getActions(RequestBody requestBody) throws RpcProviderError { + try { + Call syncCall = this.rpcProviderApi.getActions(requestBody); + try(ResponseBody responseBody = processCall(syncCall)) { + return responseBody.string(); + } + } catch (Exception ex) { + throw new RpcProviderError(EosioJavaRpcErrorConstants.RPC_PROVIDER_ERROR_GET_ACTION, ex); + } + } + + /** + * Issue a getTransaction() call to the blockchain and process the response. + * @param requestBody request body of get_transaction API + * @return String content of ResponseBody on successful return. + * @throws RpcProviderError Thrown if any errors occur calling or processing the request. + */ + public @NotNull String getTransaction(RequestBody requestBody) throws RpcProviderError { + try { + Call syncCall = this.rpcProviderApi.getTransaction(requestBody); + try(ResponseBody responseBody = processCall(syncCall)) { + return responseBody.string(); + } + } catch (Exception ex) { + throw new RpcProviderError(EosioJavaRpcErrorConstants.RPC_PROVIDER_ERROR_GET_TRANSACTION, ex); + } + } + + /** + * Issue a getKeyAccounts() call to the blockchain and process the response. + * @param requestBody request body of get_key_accounts API + * @return String content of ResponseBody on successful return. + * @throws RpcProviderError Thrown if any errors occur calling or processing the request. + */ + public @NotNull String getKeyAccounts(RequestBody requestBody) throws RpcProviderError { + try { + Call syncCall = this.rpcProviderApi.getKeyAccounts(requestBody); + try(ResponseBody responseBody = processCall(syncCall)) { + return responseBody.string(); + } + } catch (Exception ex) { + throw new RpcProviderError(EosioJavaRpcErrorConstants.RPC_PROVIDER_ERROR_GET_KEY_ACCOUNTS, ex); + } + } + + /** + * Issue a getControlledAccounts() call to the blockchain and process the response. + * @param requestBody request body of get_controlled_accounts API + * @return String content of ResponseBody on successful return. + * @throws RpcProviderError Thrown if any errors occur calling or processing the request. + */ + public @NotNull String getControlledAccounts(RequestBody requestBody) throws RpcProviderError { + try { + Call syncCall = this.rpcProviderApi.getControlledAccounts(requestBody); + try(ResponseBody responseBody = processCall(syncCall)) { + return responseBody.string(); + } + } catch (Exception ex) { + throw new RpcProviderError(EosioJavaRpcErrorConstants.RPC_PROVIDER_ERROR_GET_CONTROLLED_ACCOUNTS, ex); + } + } +} \ No newline at end of file diff --git a/eosiojavarpcprovider/src/main/java/one/block/eosiojavarpcprovider/implementations/IEosioJavaRpcProviderApi.java b/eosiojavarpcprovider/src/main/java/one/block/eosiojavarpcprovider/implementations/IEosioJavaRpcProviderApi.java new file mode 100644 index 0000000..2b89f00 --- /dev/null +++ b/eosiojavarpcprovider/src/main/java/one/block/eosiojavarpcprovider/implementations/IEosioJavaRpcProviderApi.java @@ -0,0 +1,233 @@ +package one.block.eosiojavarpcprovider.implementations; +// +// Copyright © 2017-2019 block.one. +// + +import okhttp3.RequestBody; +import okhttp3.ResponseBody; +import one.block.eosiojava.models.rpcProvider.request.GetBlockRequest; +import one.block.eosiojava.models.rpcProvider.request.GetRawAbiRequest; +import one.block.eosiojava.models.rpcProvider.request.GetRequiredKeysRequest; +import one.block.eosiojava.models.rpcProvider.request.SendTransactionRequest; +import one.block.eosiojava.models.rpcProvider.response.GetBlockResponse; +import one.block.eosiojava.models.rpcProvider.response.GetInfoResponse; +import one.block.eosiojava.models.rpcProvider.response.GetRawAbiResponse; +import one.block.eosiojava.models.rpcProvider.response.GetRequiredKeysResponse; +import one.block.eosiojava.models.rpcProvider.response.SendTransactionResponse; +import retrofit2.Call; +import retrofit2.http.Body; +import retrofit2.http.POST; + +/** + * Retrofit definitions for communication with the EOSIO blockchain. + */ +public interface IEosioJavaRpcProviderApi { + + //region Model supported APIs + + /** + * Retrofit POST call to "chain/get_info" to an EOSIO blockchain. + * This method gets called from {@link EosioJavaRpcProviderImpl#getInfo()} to get latest information about the pointing chain. + * + * @return Executable {@link Call} to return {@link GetInfoResponse} has latest information about a chain. + */ + @POST("v1/chain/get_info") + Call getInfo(); + + /** + * Retrofit POST call to "chain/get_block" to an EOSIO blockchain. + * This method gets called from {@link EosioJavaRpcProviderImpl#getBlock(GetBlockRequest)} to get info/status of a specific block in the request. + * + * @param getBlockRequest Info of a specific block. + * @return Executable {@link Call} to return {@link GetBlockResponse} has the info/status of a specific block in the request. + */ + @POST("v1/chain/get_block") + Call getBlock(@Body GetBlockRequest getBlockRequest); + + /** + * Retrofit POST call to "chain/get_raw_abi" to an EOSIO blockchain. + * This method gets called from {@link EosioJavaRpcProviderImpl#getRawAbi(GetRawAbiRequest)} to get serialized ABI of a smart contract in the request. + * + * @param getRawAbiRequest Info of a specific smart contract. + * @return Executable {@link Call} to return {@link GetRawAbiResponse} has the serialized ABI of a smart contract in the request. + */ + @POST("v1/chain/get_raw_abi") + Call getRawAbi(@Body GetRawAbiRequest getRawAbiRequest); + + /** + * Retrofit POST call to "chain/get_required_keys" to an EOSIO blockchain. + * This method gets called from {@link EosioJavaRpcProviderImpl#getRequiredKeys(GetRequiredKeysRequest)} to get required keys to sign a transaction + * + * @param getRequiredKeysRequest Info to get required keys + * @return Executable {@link Call} to return {@link GetRequiredKeysResponse} has the required keys to sign a transaction + */ + @POST("v1/chain/get_required_keys") + Call getRequiredKeys(@Body GetRequiredKeysRequest getRequiredKeysRequest); + + /** + * Retrofit POST call to "chain/send_transaction" to an EOSIO blockchain. + * This method gets called from {@link EosioJavaRpcProviderImpl#sendTransaction(SendTransactionRequest)} to Send transaction RPC call to broadcast a transaction to backend + * + * @param sendTransactionRequest the transaction to push with signatures. + * @return Executable {@link Call} to return {@link SendTransactionResponse} has the send transaction response + */ + @POST("v1/chain/send_transaction") + Call sendTransaction(@Body SendTransactionRequest sendTransactionRequest); + //endregion + + //region Extra APIs + // Chain APIs + /** + * Retrofit POST call to "chain/get_account" to an EOSIO blockchain. + * This method gets called from {@link EosioJavaRpcProviderImpl#getAccount(RequestBody)} + * + * @param requestBody the request body to call 'get_account' API + * @return Executable {@link Call} to return {@link ResponseBody} of 'get_account' API + */ + @POST("v1/chain/get_account") + Call getAccount(@Body RequestBody requestBody); + + /** + * Retrofit POST call to "chain/push_transactions" to an EOSIO blockchain. + * This method gets called from {@link EosioJavaRpcProviderImpl#pushTransactions(RequestBody)} + * + * @param requestBody the request body to call 'push_transactions' API + * @return Executable {@link Call} to return {@link ResponseBody} of 'push_transactions' API + */ + @POST("v1/chain/push_transactions") + Call pushTransactions(@Body RequestBody requestBody); + + /** + * Retrofit POST call to "chain/get_block_header_state" to an EOSIO blockchain. + * This method get called from {@link EosioJavaRpcProviderImpl#getBlockHeaderState(RequestBody)} + * + * @param requestBody the request body to call 'get_block_header_state' API + * @return Executable {@link Call} to return {@link ResponseBody} of 'get_block_header_state' API + */ + @POST("v1/chain/get_block_header_state") + Call getBlockHeaderState(@Body RequestBody requestBody); + + /** + * Retrofit POST call to "chain/get_abi" to an EOSIO blockchain. + * This method gets called from {@link EosioJavaRpcProviderImpl#getAbi(RequestBody)} + * + * @param requestBody the request body to call 'get_abi' API + * @return Executable {@link Call} to return {@link ResponseBody} of 'get_abi' API + */ + @POST("v1/chain/get_abi") + Call getAbi(@Body RequestBody requestBody); + + /** + * Retrofit POST call to "chain/get_currency_balance" to an EOSIO blockchain. + * This method gets called from {@link EosioJavaRpcProviderImpl#getCurrencyBalance(RequestBody)} + * + * @param requestBody the request body to call 'get_currency_balance' API + * @return Executable {@link Call} to return {@link ResponseBody} of 'get_currency_balance' API + */ + @POST("v1/chain/get_currency_balance") + Call getCurrencyBalance(@Body RequestBody requestBody); + + /** + * Retrofit POST call to "chain/get_currency_stats" to an EOSIO blockchain. + * This method gets called from {@link EosioJavaRpcProviderImpl#getCurrencyStats(RequestBody)} + * + * @param requestBody the request body to call 'get_currency_stats' API + * @return Executable {@link Call} to return {@link ResponseBody} of 'get_currency_stats' API + */ + @POST("v1/chain/get_currency_stats") + Call getCurrencyStats(@Body RequestBody requestBody); + + /** + * Retrofit POST call to "chain/get_producers" to an EOSIO blockchain. + * This method gets called from {@link EosioJavaRpcProviderImpl#getProducers(RequestBody)} + * + * @param requestBody the request body to call 'get_producers' API + * @return Executable {@link Call} to return {@link ResponseBody} of 'get_producers' API + */ + @POST("v1/chain/get_producers") + Call getProducers(@Body RequestBody requestBody); + + /** + * Retrofit POST call to "chain/get_raw_code_and_abi" to an EOSIO blockchain. + * This method gets called from {@link EosioJavaRpcProviderImpl#getRawCodeAndAbi(RequestBody)} + * + * @param requestBody the request body to call 'get_raw_code_and_abi' API + * @return Executable {@link Call} to return {@link ResponseBody} of 'get_raw_code_and_abi' API + */ + @POST("v1/chain/get_raw_code_and_abi") + Call getRawCodeAndAbi(@Body RequestBody requestBody); + + /** + * Retrofit POST call to "chain/get_table_by_scope" to an EOSIO blockchain. + * This method get called from {@link EosioJavaRpcProviderImpl#getTableByScope(RequestBody)} + * + * @param requestBody the request body to call 'get_table_by_scope' API + * @return Executable {@link Call} to return {@link ResponseBody} of 'get_table_by_scope' API + */ + @POST("v1/chain/get_table_by_scope") + Call getTableByScope(@Body RequestBody requestBody); + + /** + * Retrofit POST call to "chain/get_table_rows" to an EOSIO blockchain. + * This method gets called from {@link EosioJavaRpcProviderImpl#getTableRows(RequestBody)} + * + * @param requestBody the request body to call 'get_table_rows' API + * @return Executable {@link Call} to return {@link ResponseBody} of 'get_table_rows' API + */ + @POST("v1/chain/get_table_rows") + Call getTableRows(@Body RequestBody requestBody); + + /** + * Retrofit POST call to "chain/get_code" to an EOSIO blockchain. + * This method gets called from {@link EosioJavaRpcProviderImpl#getCode(RequestBody)} + * + * @param requestBody the request body to call 'get_code' API + * @return Executable {@link Call} to return {@link ResponseBody} of 'get_code' API + */ + @POST("v1/chain/get_code") + Call getCode(@Body RequestBody requestBody); + + //History APIs + + /** + * Retrofit POST call to "chain/get_actions" to an EOSIO blockchain. + * This method gets called from {@link EosioJavaRpcProviderImpl#getActions(RequestBody)} + * + * @param requestBody the request body to call 'get_actions' API + * @return Executable {@link Call} to return {@link ResponseBody} of 'get_actions' API + */ + @POST("v1/history/get_actions") + Call getActions(@Body RequestBody requestBody); + + /** + * Retrofit POST call to "chain/get_transaction" to an EOSIO blockchain. + * This method gets called from {@link EosioJavaRpcProviderImpl#getTransaction(RequestBody)} + * + * @param requestBody the request body to call 'get_transaction' API + * @return Executable {@link Call} to return {@link ResponseBody} of 'get_transaction' API + */ + @POST("v1/history/get_transaction") + Call getTransaction(@Body RequestBody requestBody); + + /** + * Retrofit POST call to "chain/get_key_accounts" to an EOSIO blockchain. + * This method gets called from {@link EosioJavaRpcProviderImpl#getKeyAccounts(RequestBody)} + * + * @param requestBody the request body to call 'get_key_accounts' API + * @return Executable {@link Call} to return {@link ResponseBody} of 'get_key_accounts' API + */ + @POST("v1/history/get_key_accounts") + Call getKeyAccounts(@Body RequestBody requestBody); + + /** + * Retrofit POST call to "chain/get_controlled_accounts" to an EOSIO blockchain. + * This method gets called from {@link EosioJavaRpcProviderImpl#getControlledAccounts(RequestBody)} + * + * @param requestBody the request body to call 'get_controlled_accounts' API + * @return Executable {@link Call} to return {@link ResponseBody} of 'get_controlled_accounts' API + */ + @POST("v1/history/get_controlled_accounts") + Call getControlledAccounts(@Body RequestBody requestBody); + + //endregion +} \ No newline at end of file diff --git a/eosiojavarpcprovider/src/main/java/one/block/eosiojavarpcprovider/implementations/package-info.java b/eosiojavarpcprovider/src/main/java/one/block/eosiojavarpcprovider/implementations/package-info.java new file mode 100644 index 0000000..ebe1d39 --- /dev/null +++ b/eosiojavarpcprovider/src/main/java/one/block/eosiojavarpcprovider/implementations/package-info.java @@ -0,0 +1,5 @@ +/** + * Provides the implementation of {@link one.block.eosiojava.interfaces.IRPCProvider} by using Retrofit library to communicate with EOSIO blockchain. + */ + +package one.block.eosiojavarpcprovider.implementations; \ No newline at end of file diff --git a/eosiojavarpcprovider/src/main/res/values/strings.xml b/eosiojavarpcprovider/src/main/res/values/strings.xml new file mode 100644 index 0000000..203cd2d --- /dev/null +++ b/eosiojavarpcprovider/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + EosioJavaRpcProvider + diff --git a/eosiojavarpcprovider/src/test/java/one/block/eosiojavarpcprovider/ExampleUnitTest.java b/eosiojavarpcprovider/src/test/java/one/block/eosiojavarpcprovider/ExampleUnitTest.java new file mode 100644 index 0000000..9068999 --- /dev/null +++ b/eosiojavarpcprovider/src/test/java/one/block/eosiojavarpcprovider/ExampleUnitTest.java @@ -0,0 +1,872 @@ +package one.block.eosiojavarpcprovider; + +import one.block.eosiojava.models.rpcProvider.request.SendTransactionRequest; +import one.block.eosiojava.models.rpcProvider.response.*; +import org.json.simple.*; +import org.json.simple.parser.JSONParser; +import org.junit.Before; +import org.junit.Test; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.math.BigInteger; +import java.net.SocketTimeoutException; +import java.util.ArrayList; +import java.util.List; + +import okhttp3.RequestBody; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.SocketPolicy; +import one.block.eosiojava.models.rpcProvider.Action; +import one.block.eosiojava.models.rpcProvider.Authorization; +import one.block.eosiojava.models.rpcProvider.Transaction; +import one.block.eosiojava.models.rpcProvider.request.GetBlockRequest; +import one.block.eosiojava.models.rpcProvider.request.GetRawAbiRequest; +import one.block.eosiojava.models.rpcProvider.request.GetRequiredKeysRequest; +import one.block.eosiojavarpcprovider.error.EosioJavaRpcProviderCallError; +import one.block.eosiojavarpcprovider.implementations.EosioJavaRpcProviderImpl; + +import static one.block.eosiojavarpcprovider.RpcTestConstants.*; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + + private JSONParser parser; + + @Before + public void setup() { + this.parser = new JSONParser(); + } + + @Test + public void getInfoTest() { + + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200).setBody(GET_INFO_RESPONSE)); + + try { + server.start(); + String baseUrl = server.url("/").toString(); + + EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( + baseUrl); + GetInfoResponse response = rpcProvider.getInfo(); + assertNotNull(response); + assertEquals("687fa513e18843ad3e820744f4ffcf93b1354036d80737db8dc444fe4b15ad17", + response.getChainId()); + assertEquals("0f6695cb", response.getServerVersion()); + assertEquals("v1.3.0", response.getServerVersionString()); + } catch (Exception ex) { + fail("Should not get exception when calling getInfo(): " + "\n" + getStackTraceString(ex)); + } finally { + try { + server.shutdown(); + } catch (Exception ex) { + // No need for anything here. + } + } + + } + + @Test + public void getBlockTest() { + + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200).setBody(GET_BLOCK_RESPONSE)); + + try { + server.start(); + String baseUrl = server.url("/").toString(); + + EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( + baseUrl); + GetBlockRequest request = new GetBlockRequest("25260032"); + GetBlockResponse response = rpcProvider.getBlock(request); + assertNotNull(response); + assertEquals("0181700002e623f2bf291b86a10a5cec4caab4954d4231f31f050f4f86f26116", + response.getId()); + assertEquals(new BigInteger("2249927103"), response.getRefBlockPrefix()); + assertEquals("de5493939e3abdca80deeab2fc9389cc43dc1982708653cfe6b225eb788d6659", + response.getActionMroot()); + } catch (Exception ex) { + fail("Should not get exception when calling getBlock(): " + ex.getLocalizedMessage() + + "\n" + getStackTraceString(ex)); + } finally { + try { + server.shutdown(); + } catch (Exception ex) { + // No need for anything here. + } + } + + } + + @Test + public void getRawAbiTest() { + + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200).setBody(GET_RAW_EOSIO_TOKEN_ABI_RESPONSE)); + + try { + server.start(); + String baseUrl = server.url("/").toString(); + + EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( + baseUrl); + GetRawAbiRequest request = new GetRawAbiRequest("eosio.token"); + GetRawAbiResponse response = rpcProvider.getRawAbi(request); + assertNotNull(response); + assertEquals("eosio.token", response.getAccountName()); + assertEquals("43864d5af0fe294d44d19c612036cbe8c098414c4a12a5a7bb0bfe7db1556248", response.getAbiHash()); + assertEquals("DmVvc2lvOjphYmkvMS4wAQxhY2NvdW50X25hbWUEbmFtZQUIdHJhbnNmZXIABARmcm9tDGFjY291bnRfbmFtZQJ0bwxhY2NvdW50X25hbWUIcXVhbnRpdHkFYXNzZXQEbWVtbwZzdHJpbmcGY3JlYXRlAAIGaXNzdWVyDGFjY291bnRfbmFtZQ5tYXhpbXVtX3N1cHBseQVhc3NldAVpc3N1ZQADAnRvDGFjY291bnRfbmFtZQhxdWFudGl0eQVhc3NldARtZW1vBnN0cmluZwdhY2NvdW50AAEHYmFsYW5jZQVhc3NldA5jdXJyZW5jeV9zdGF0cwADBnN1cHBseQVhc3NldAptYXhfc3VwcGx5BWFzc2V0Bmlzc3VlcgxhY2NvdW50X25hbWUDAAAAVy08zc0IdHJhbnNmZXK8By0tLQp0aXRsZTogVG9rZW4gVHJhbnNmZXIKc3VtbWFyeTogVHJhbnNmZXIgdG9rZW5zIGZyb20gb25lIGFjY291bnQgdG8gYW5vdGhlci4KaWNvbjogaHR0cHM6Ly9jZG4udGVzdG5ldC5kZXYuYjFvcHMubmV0L3Rva2VuLXRyYW5zZmVyLnBuZyNjZTUxZWY5ZjllZWNhMzQzNGU4NTUwN2UwZWQ0OWU3NmZmZjEyNjU0MjJiZGVkMDI1NWYzMTk2ZWE1OWM4YjBjCi0tLQoKIyMgVHJhbnNmZXIgVGVybXMgJiBDb25kaXRpb25zCgpJLCB7e2Zyb219fSwgY2VydGlmeSB0aGUgZm9sbG93aW5nIHRvIGJlIHRydWUgdG8gdGhlIGJlc3Qgb2YgbXkga25vd2xlZGdlOgoKMS4gSSBjZXJ0aWZ5IHRoYXQge3txdWFudGl0eX19IGlzIG5vdCB0aGUgcHJvY2VlZHMgb2YgZnJhdWR1bGVudCBvciB2aW9sZW50IGFjdGl2aXRpZXMuCjIuIEkgY2VydGlmeSB0aGF0LCB0byB0aGUgYmVzdCBvZiBteSBrbm93bGVkZ2UsIHt7dG99fSBpcyBub3Qgc3VwcG9ydGluZyBpbml0aWF0aW9uIG9mIHZpb2xlbmNlIGFnYWluc3Qgb3RoZXJzLgozLiBJIGhhdmUgZGlzY2xvc2VkIGFueSBjb250cmFjdHVhbCB0ZXJtcyAmIGNvbmRpdGlvbnMgd2l0aCByZXNwZWN0IHRvIHt7cXVhbnRpdHl9fSB0byB7e3RvfX0uCgpJIHVuZGVyc3RhbmQgdGhhdCBmdW5kcyB0cmFuc2ZlcnMgYXJlIG5vdCByZXZlcnNpYmxlIGFmdGVyIHRoZSB7eyR0cmFuc2FjdGlvbi5kZWxheV9zZWN9fSBzZWNvbmRzIG9yIG90aGVyIGRlbGF5IGFzIGNvbmZpZ3VyZWQgYnkge3tmcm9tfX0ncyBwZXJtaXNzaW9ucy4KCklmIHRoaXMgYWN0aW9uIGZhaWxzIHRvIGJlIGlycmV2ZXJzaWJseSBjb25maXJtZWQgYWZ0ZXIgcmVjZWl2aW5nIGdvb2RzIG9yIHNlcnZpY2VzIGZyb20gJ3t7dG99fScsIEkgYWdyZWUgdG8gZWl0aGVyIHJldHVybiB0aGUgZ29vZHMgb3Igc2VydmljZXMgb3IgcmVzZW5kIHt7cXVhbnRpdHl9fSBpbiBhIHRpbWVseSBtYW5uZXIuAAAAAAClMXYFaXNzdWUAAAAAAKhs1EUGY3JlYXRlAAIAAAA4T00RMgNpNjQBCGN1cnJlbmN5AQZ1aW50NjQHYWNjb3VudAAAAAAAkE3GA2k2NAEIY3VycmVuY3kBBnVpbnQ2NA5jdXJyZW5jeV9zdGF0cwAAAAA==", + response.getAbi()); + } catch (Exception ex) { + fail("Should not get exception when calling getRawAbi(): " + ex.getLocalizedMessage() + + "\n" + getStackTraceString(ex)); + } finally { + try { + server.shutdown(); + } catch (Exception ex) { + // No need for anything here. + } + } + + } + + @Test + public void getRequiredKeysTest() { + + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200).setBody(GET_REQUIRED_KEYS_RESPONSE)); + + try { + server.start(); + String baseUrl = server.url("/").toString(); + + EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( + baseUrl); + + GetRequiredKeysRequest request = new GetRequiredKeysRequest(availableKeys(), transactionForRequiredKeys()); + GetRequiredKeysResponse response = rpcProvider.getRequiredKeys(request); + assertNotNull(response); + assertFalse(response.getRequiredKeys().isEmpty()); + assertNotNull(response.getRequiredKeys().get(0)); + assertEquals("EOS5j67P1W2RyBXAL8sNzYcDLox3yLpxyrxgkYy1xsXzVCvzbYpba", + response.getRequiredKeys().get(0)); + } catch (Exception ex) { + fail("Should not get exception when calling getRequiredKeys(): " + ex.getLocalizedMessage() + + "\n" + getStackTraceString(ex)); + } finally { + try { + server.shutdown(); + } catch (Exception ex) { + // No need for anything here. + } + } + + } + + @Test + public void sendTransactionTest() { + + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200).setBody(SEND_TRANSACTION_RESPONSE)); + + try { + server.start(); + String baseUrl = server.url("/").toString(); + + EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( + baseUrl); + + List signatures = new ArrayList<>(); + signatures.add("SIG_K1_JzFA9ffefWfrTBvpwMwZi81kR6tvHF4mfsRekVXrBjLWWikg9g1FrS9WupYuoGaRew5mJhr4d39tHUjHiNCkxamtEfxi68"); + SendTransactionRequest request = new SendTransactionRequest(signatures, + 0, + "", + "C62A4F5C1CEF3D6D71BD000000000290AFC2D800EA3055000000405DA7ADBA0072CBDD956F52ACD910C3C958136D72F8560D1846BC7CF3157F5FBFB72D3001DE4597F4A1FDBECDA6D59C96A43009FC5E5D7B8F639B1269C77CEC718460DCC19CB30100A6823403EA3055000000572D3CCDCD0143864D5AF0FE294D44D19C612036CBE8C098414C4A12A5A7BB0BFE7DB155624800A6823403EA3055000000572D3CCDCD0100AEAA4AC15CFD4500000000A8ED32323B00AEAA4AC15CFD4500000060D234CD3DA06806000000000004454F53000000001A746865206772617373686F70706572206C69657320686561767900"); + SendTransactionResponse response = rpcProvider.sendTransaction(request); + assertNotNull(response); + assertEquals("ae735820e26a7b771e1b522186294d7cbba035d0c31ca88237559d6c0a3bf00a", + response.getTransactionId()); + } catch (Exception ex) { + fail("Should not get exception when calling sendTransaction(): " + ex.getLocalizedMessage() + + "\n" + getStackTraceString(ex)); + } finally { + try { + server.shutdown(); + } catch (Exception ex) { + // No need for anything here. + } + } + + } + + @Test + public void pushTransactionErrorTest() { + + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(500).setBody(SEND_TRANSACTION_ERROR_RESPONSE)); + + try { + server.start(); + String baseUrl = server.url("/").toString(); + + EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( + baseUrl); + + List signatures = new ArrayList<>(); + signatures.add("SIG_K1_JzFA9ffefWfrTBvpwMwZi81kR6tvHF4mfsRekVXrBjLWWikg9g1FrS9WupYuoGaRew5mJhr4d39tHUjHiNCkxamtEfxi68"); + SendTransactionRequest request = new SendTransactionRequest(signatures, + 0, + "", + "C62A4F5C1CEF3D6D71BD000000000290AFC2D800EA3055000000405DA7ADBA0072CBDD956F52ACD910C3C958136D72F8560D1846BC7CF3157F5FBFB72D3001DE4597F4A1FDBECDA6D59C96A43009FC5E5D7B8F639B1269C77CEC718460DCC19CB30100A6823403EA3055000000572D3CCDCD0143864D5AF0FE294D44D19C612036CBE8C098414C4A12A5A7BB0BFE7DB155624800A6823403EA3055000000572D3CCDCD0100AEAA4AC15CFD4500000000A8ED32323B00AEAA4AC15CFD4500000060D234CD3DA06806000000000004454F53000000001A746865206772617373686F70706572206C69657320686561767900"); + SendTransactionResponse response = rpcProvider.sendTransaction(request); + fail("Push transaction should not succeed."); + } catch (Exception ex) { + assertEquals("Error sending transaction.", ex.getLocalizedMessage()); + assertNotNull(ex.getCause()); + assertEquals("Bad status code: 500 (Server Error), returned from server. Additional error information: See further error information in RPCProviderError.", ex.getCause().getMessage()); + RPCResponseError rpcResponseError = ((EosioJavaRpcProviderCallError)ex.getCause()).getRpcResponseError(); + assertNotNull(rpcResponseError); + assertEquals(new BigInteger("500"), rpcResponseError.getCode()); + assertEquals("Internal Service Error", rpcResponseError.getMessage()); + RpcError rpcError = rpcResponseError.getError(); + assertNotNull(rpcError); + assertEquals(new BigInteger("3040005"), rpcError.getCode()); + assertEquals("Expired Transaction", rpcError.getWhat()); + } finally { + try { + server.shutdown(); + } catch (Exception ex) { + // No need for anything here. + } + } + + } + + @Test + public void getInfoTimeoutTest() { + + MockWebServer server = new MockWebServer(); + MockResponse mockResponse = new MockResponse().setResponseCode(200).setBody(GET_INFO_RESPONSE); + // This will cause the call to time out. + mockResponse.setSocketPolicy(SocketPolicy.NO_RESPONSE); + server.enqueue(mockResponse); + + try { + server.start(); + String baseUrl = server.url("/").toString(); + + EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( + baseUrl); + GetInfoResponse response = rpcProvider.getInfo(); + fail("Should not succeed when calling getInfo(). Should time out."); + } catch (Exception ex) { + assertEquals("Error retrieving chain information.", ex.getMessage()); + assertNotNull(ex.getCause()); + assertTrue(ex.getCause() instanceof SocketTimeoutException); + assertEquals("timeout", ex.getCause().getMessage()); + } finally { + try { + server.shutdown(); + } catch (Exception ex) { + // No need for anything here. + } + } + + } + + // Is this test necessary? +// @Test +// public void getBlockAsyncTest() { +// +// // This test shows how an RPC provider call might be made asynchronously. +// +// final CountDownLatch testLock = new CountDownLatch(1); +// +// MockWebServer server = new MockWebServer(); +// server.enqueue(new MockResponse().setResponseCode(200).setBody(GET_BLOCK_RESPONSE)); +// +// try { +// server.start(); +// String baseUrl = server.url("/").toString(); +// +// final EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( +// baseUrl); +// GetBlockRequest[] request = { new GetBlockRequest("25260032") }; +// +// AsyncTask asyncTask = new AsyncTask() { +// GetBlockRpcError getBlockError = null; +// @Override +// protected GetBlockResponse doInBackground(GetBlockRequest... getBlockRequests) { +// // Here we are on a background thread. +// GetBlockResponse response = null; +// try { +// response = rpcProvider.getBlock(getBlockRequests[0]); +// } catch (GetBlockRpcError err) { +// getBlockError = err; +// } +// return response; +// } +// +// protected void onPostExecute(GetBlockResponse response) { +// // Here we are back on the main thread and could update the UI. +// assertNotNull(response); +// assertEquals("0181700002e623f2bf291b86a10a5cec4caab4954d4231f31f050f4f86f26116", +// response.getId()); +// assertEquals(new BigInteger("2249927103"), response.getRefBlockPrefix()); +// assertEquals("de5493939e3abdca80deeab2fc9389cc43dc1982708653cfe6b225eb788d6659", +// response.getActionMroot()); +// testLock.countDown(); +// } +// }.execute(request); +// +// try { +// testLock.await(5000, TimeUnit.MILLISECONDS); +// } catch (InterruptedException interruptedException) { +// fail("Interrupted waiting for getBlock() to complete: " + +// interruptedException.getLocalizedMessage()); +// } +// +// } catch (Exception ex) { +// fail("Should not get exception when calling getBlock(): " + ex.getLocalizedMessage()); +// } finally { +// try { +// server.shutdown(); +// } catch (Exception ex) { +// // No need for anything here. +// } +// } +// +// } + + @Test + public void testGetAccountRpcCall() { + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200).setBody(GET_ACCOUNT_RESPONSE)); + + try { + server.start(); + String baseUrl = server.url("/").toString(); + + EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( + baseUrl); + String testAccount = "test_account"; + + RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), "{\"name\":\""+testAccount+"\"}"); + String response = rpcProvider.getAccount(requestBody); + assertNotNull(response); + + JSONObject jsonObject = (JSONObject)parser.parse(response); + + assertEquals(testAccount, jsonObject.get("account_name")); + } catch (Exception ex) { + fail("Should not get exception when calling getAccount(): " + ex.getLocalizedMessage() + + "\n" + getStackTraceString(ex)); + } finally { + try { + server.shutdown(); + } catch (Exception ex) { + // No need for anything here. + } + } + } + + @Test + public void testPushTransactionsRpcCall() { + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200).setBody(PUSH_TRANSACTIONS_RESPONSE)); + + try { + server.start(); + String baseUrl = server.url("/").toString(); + + EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( + baseUrl); + + RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), PUSH_TRANSACTIONS_REQUEST); + String response = rpcProvider.pushTransactions(requestBody); + assertNotNull(response); + + JSONArray jsonArray = (JSONArray)parser.parse(response); + assertEquals(2, jsonArray.size()); + JSONObject firstObject = (JSONObject)jsonArray.get(0); + JSONObject secondObject = (JSONObject)jsonArray.get(1); + assertEquals("ae735820e26a7b771e1b522186294d7cbba035d0c31ca88237559d6c0a3bf00a", firstObject.get("transaction_id")); + assertEquals("ae735820e26a7b771e1b522186294d7cbba035d0c31ca88237559d6c0a3bf00a", secondObject.get("transaction_id")); + } catch (Exception ex) { + fail("Should not get exception when calling pushTransactions(): " + ex.getLocalizedMessage() + + "\n" + getStackTraceString(ex)); + } finally { + try { + server.shutdown(); + } catch (Exception ex) { + // No need for anything here. + } + } + } + + @Test + public void testGetBlockHeaderStateRpcCall() { + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200).setBody(GET_BLOCK_HEADER_STATE_RESPONSE)); + + try { + server.start(); + String baseUrl = server.url("/").toString(); + + EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( + baseUrl); + + RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), GET_BLOCK_HEADER_STATE_REQUEST); + String response = rpcProvider.getBlockHeaderState(requestBody); + assertNotNull(response); + + JSONObject jsonObject = (JSONObject)parser.parse(response); + assertEquals("020c00e41e66ca6a0fa489c9b2df391fd06089426a3daed5e4859cebc1d41b73", jsonObject.get("id")); + } catch (Exception ex) { + fail("Should not get exception when calling getBlockHeaderState(): " + ex.getLocalizedMessage() + + "\n" + getStackTraceString(ex)); + } finally { + try { + server.shutdown(); + } catch (Exception ex) { + // No need for anything here. + } + } + } + + @Test + public void testGetAbiRpcCall() { + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200).setBody(GET_ABI_RESPONSE)); + + try { + server.start(); + String baseUrl = server.url("/").toString(); + + EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( + baseUrl); + + RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), GET_ABI_REQUEST); + String response = rpcProvider.getAbi(requestBody); + assertNotNull(response); + + JSONObject jsonObject = (JSONObject)parser.parse(response); + assertEquals("eosio.token", jsonObject.get("account_name")); + } catch (Exception ex) { + fail("Should not get exception when calling getAbi(): " + ex.getLocalizedMessage() + + "\n" + getStackTraceString(ex)); + } finally { + try { + server.shutdown(); + } catch (Exception ex) { + // No need for anything here. + } + } + } + + @Test + public void testGetCurrencyBalanceRpcCall() { + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200).setBody(GET_CURRENT_BALANCE_RESPONSE)); + + try { + server.start(); + String baseUrl = server.url("/").toString(); + + EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( + baseUrl); + + RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), GET_CURRENT_BALANCE_REQUEST); + String response = rpcProvider.getCurrencyBalance(requestBody); + assertNotNull(response); + + JSONArray jsonArray = (JSONArray)parser.parse(response); + assertEquals("1.0000 EOS", jsonArray.get(0)); + } catch (Exception ex) { + fail("Should not get exception when calling getCurrencyBalance(): " + ex.getLocalizedMessage() + + "\n" + getStackTraceString(ex)); + } finally { + try { + server.shutdown(); + } catch (Exception ex) { + // No need for anything here. + } + } + } + + @Test + public void testGetCurrencyStatsRpcCall() { + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200).setBody(GET_CURRENT_STATS_RESPONSE)); + + try { + server.start(); + String baseUrl = server.url("/").toString(); + + EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( + baseUrl); + + RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), GET_CURRENT_STATS_REQUEST); + String response = rpcProvider.getCurrencyStats(requestBody); + assertNotNull(response); + + JSONObject jsonObject = (JSONObject)parser.parse(response); + JSONObject eosJsonObject = (JSONObject)jsonObject.get("EOS"); + assertEquals("100000000.0000 EOS", eosJsonObject.get("supply")); + assertEquals("10000000000.0000 EOS", eosJsonObject.get("max_supply")); + } catch (Exception ex) { + fail("Should not get exception when calling getCurrencyStats(): " + ex.getLocalizedMessage() + + "\n" + getStackTraceString(ex)); + } finally { + try { + server.shutdown(); + } catch (Exception ex) { + // No need for anything here. + } + } + } + + @Test + public void testGetProducersRpcCall() { + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200).setBody(GET_PRODUCER_RESPONSE)); + + try { + server.start(); + String baseUrl = server.url("/").toString(); + + EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( + baseUrl); + + RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), GET_PRODUCER_REQUEST); + String response = rpcProvider.getProducers(requestBody); + assertNotNull(response); + + JSONObject jsonObject = (JSONObject)parser.parse(response); + JSONArray rowsArray = (JSONArray)jsonObject.get("rows"); + assertEquals(2, rowsArray.size()); + JSONObject firstObject = (JSONObject)rowsArray.get(0); + JSONObject secondObject = (JSONObject)rowsArray.get(1); + assertEquals("blkproducer2", firstObject.get("owner")); + assertEquals("blkproducer3", secondObject.get("owner")); + } catch (Exception ex) { + fail("Should not get exception when calling getProducers(): " + ex.getLocalizedMessage() + + "\n" + getStackTraceString(ex)); + } finally { + try { + server.shutdown(); + } catch (Exception ex) { + // No need for anything here. + } + } + } + + @Test + public void testGetRawCodeAndAbiRpcCall() { + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200).setBody(GET_RAW_CODE_AND_ABI_RESPONSE)); + + try { + server.start(); + String baseUrl = server.url("/").toString(); + + EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( + baseUrl); + + RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), GET_RAW_CODE_AND_ABI_REQUEST); + String response = rpcProvider.getRawCodeAndAbi(requestBody); + assertNotNull(response); + + JSONObject jsonObject = (JSONObject)parser.parse(response); + assertEquals("eosio.token", jsonObject.get("account_name")); + } catch (Exception ex) { + fail("Should not get exception when calling getRawCodeAndAbi(): " + ex.getLocalizedMessage() + + "\n" + getStackTraceString(ex)); + } finally { + try { + server.shutdown(); + } catch (Exception ex) { + // No need for anything here. + } + } + } + + @Test + public void testGetTableByScopeRpcCall() { + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200).setBody(GET_TABLE_BY_SCOPE_RESPONSE)); + + try { + server.start(); + String baseUrl = server.url("/").toString(); + + EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( + baseUrl); + + RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), GET_TABLE_BY_SCOPE_REQUEST); + String response = rpcProvider.getTableByScope(requestBody); + assertNotNull(response); + + JSONObject jsonObject = (JSONObject)parser.parse(response); + JSONArray jsonArray = (JSONArray)jsonObject.get("rows"); + assertEquals(10, jsonArray.size()); + JSONObject firstObject = (JSONObject)jsonArray.get(0); + JSONObject secondObject = (JSONObject)jsonArray.get(1); + JSONObject thirdObject = (JSONObject)jsonArray.get(2); + JSONObject fourthObject = (JSONObject)jsonArray.get(3); + assertEquals("eosio.token", firstObject.get("code")); + assertEquals("test_account_1", firstObject.get("scope")); + assertEquals("test_account_2", secondObject.get("scope")); + assertEquals("test_account_7", thirdObject.get("scope")); + assertEquals("test_account_3", fourthObject.get("scope")); + } catch (Exception ex) { + fail("Should not get exception when calling getTableByScope(): " + ex.getLocalizedMessage() + + "\n" + getStackTraceString(ex)); + } finally { + try { + server.shutdown(); + } catch (Exception ex) { + // No need for anything here. + } + } + } + + @Test + public void testGetTableRowsRpcCall() { + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200).setBody(GET_TABLE_ROWS_RESPONSE)); + + try { + server.start(); + String baseUrl = server.url("/").toString(); + + EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( + baseUrl); + + RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), GET_TABLE_ROWS_REQUEST); + String response = rpcProvider.getTableRows(requestBody); + assertNotNull(response); + + JSONObject jsonObject = (JSONObject)parser.parse(response); + JSONArray jsonArray = (JSONArray)jsonObject.get("rows"); + assertEquals(1, jsonArray.size()); + JSONObject firstObject = (JSONObject)jsonArray.get(0); + assertEquals("1000.0000 EOS", firstObject.get("balance")); + } catch (Exception ex) { + fail("Should not get exception when calling getTableRows(): " + ex.getLocalizedMessage() + + "\n" + getStackTraceString(ex)); + } finally { + try { + server.shutdown(); + } catch (Exception ex) { + // No need for anything here. + } + } + } + + @Test + public void testGetCodeRpcCall() { + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200).setBody(GET_CODE_RESPONSE)); + + try { + server.start(); + String baseUrl = server.url("/").toString(); + + EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( + baseUrl); + + RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), GET_CODE_REQUEST); + String response = rpcProvider.getCode(requestBody); + assertNotNull(response); + + JSONObject jsonObject = (JSONObject)parser.parse(response); + assertEquals(new Long(500), jsonObject.get("code")); + } catch (Exception ex) { + fail("Should not get exception when calling getCode(): " + ex.getLocalizedMessage() + + "\n" + getStackTraceString(ex)); + } finally { + try { + server.shutdown(); + } catch (Exception ex) { + // No need for anything here. + } + } + } + + @Test + public void testGetActionsRpcCall() { + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200).setBody(GET_ACTIONS_RESPONSE)); + + try { + server.start(); + String baseUrl = server.url("/").toString(); + + EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( + baseUrl); + + RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), GET_ACTIONS_REQUEST); + String response = rpcProvider.getActions(requestBody); + assertNotNull(response); + + JSONObject jsonObject = (JSONObject)parser.parse(response); + assertEquals(new Long(34394836), jsonObject.get("last_irreversible_block")); + } catch (Exception ex) { + fail("Should not get exception when calling getActions(): " + ex.getLocalizedMessage() + + "\n" + getStackTraceString(ex)); + } finally { + try { + server.shutdown(); + } catch (Exception ex) { + // No need for anything here. + } + } + } + + @Test + public void testGetTransactionRpcCall() { + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200).setBody(GET_TRANSACTION_RESPONSE)); + + try { + server.start(); + String baseUrl = server.url("/").toString(); + + EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( + baseUrl); + + RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), GET_TRANSACTION_REQUEST); + String response = rpcProvider.getTransaction(requestBody); + assertNotNull(response); + + JSONObject jsonObject = (JSONObject)parser.parse(response); + assertEquals("transaction id", jsonObject.get("id")); + assertEquals(new Long(49420058), jsonObject.get("block_num")); + } catch (Exception ex) { + fail("Should not get exception when calling getTransaction(): " + ex.getLocalizedMessage() + + "\n" + getStackTraceString(ex)); + } finally { + try { + server.shutdown(); + } catch (Exception ex) { + // No need for anything here. + } + } + } + + @Test + public void testGetKeyAccountsRpcCall() { + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200).setBody(GET_KEY_ACCOUNTS_RESPONSE)); + + try { + server.start(); + String baseUrl = server.url("/").toString(); + + EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( + baseUrl); + + RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), GET_KEY_ACCOUNTS_REQUEST); + String response = rpcProvider.getKeyAccounts(requestBody); + assertNotNull(response); + + JSONObject jsonObject = (JSONObject)parser.parse(response); + JSONArray jsonArray = (JSONArray)jsonObject.get("account_names"); + assertEquals(1, jsonArray.size()); + assertEquals("test_account", jsonArray.get(0)); + } catch (Exception ex) { + fail("Should not get exception when calling getKeyAccounts(): " + ex.getLocalizedMessage() + + "\n" + getStackTraceString(ex)); + } finally { + try { + server.shutdown(); + } catch (Exception ex) { + // No need for anything here. + } + } + } + + @Test + public void testGetControlledAccountsRpcCall() { + MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200).setBody(GET_CONTROLLED_ACCOUNTS_RESPONSE)); + + try { + server.start(); + String baseUrl = server.url("/").toString(); + + EosioJavaRpcProviderImpl rpcProvider = new EosioJavaRpcProviderImpl( + baseUrl); + + RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("application/json; charset=utf-8"), GET_CONTROLLED_ACCOUNTS_REQUEST); + String response = rpcProvider.getControlledAccounts(requestBody); + assertNotNull(response); + + JSONObject jsonObject = (JSONObject)parser.parse(response); + JSONArray jsonArray = (JSONArray)jsonObject.get("controlled_accounts"); + assertEquals(0, jsonArray.size()); + } catch (Exception ex) { + fail("Should not get exception when calling getControlledAccounts(): " + ex.getLocalizedMessage() + + "\n" + getStackTraceString(ex)); + } finally { + try { + server.shutdown(); + } catch (Exception ex) { + // No need for anything here. + } + } + } + + private String getStackTraceString(Exception ex) { + StringWriter stringWriter = new StringWriter(); + PrintWriter printWriter = new PrintWriter(stringWriter); + ex.printStackTrace(printWriter); + return stringWriter.toString(); + } + + private List availableKeys() { + + List availableKeys = new ArrayList<>(); + availableKeys.add("PUB_K1_5j67P1W2RyBXAL8sNzYcDLox3yLpxyrxgkYy1xsXzVCw1oi9eG"); + return availableKeys; + + } + + private Transaction transactionForRequiredKeys() { + List authList = new ArrayList<>(); + authList.add(new Authorization("cryptkeeper", "active")); + + List actionList = new ArrayList<>(); + Action action = new Action("eosio.token", + "transfer", + authList, + "00AEAA4AC15CFD4500000060D234CD3DA06806000000000004454F53000000001A746865206772617373686F70706572206C696573206865617679" + ); + actionList.add(action); + + Transaction transaction = new Transaction( + "2019-01-25T22:13:55", + new BigInteger("44503"), + new BigInteger("1776994640"), + BigInteger.ZERO, + BigInteger.ZERO, + BigInteger.ZERO, + new ArrayList(), + actionList, + new ArrayList() + ); + + return transaction; + } +} \ No newline at end of file diff --git a/eosiojavarpcprovider/src/test/java/one/block/eosiojavarpcprovider/RpcTestConstants.java b/eosiojavarpcprovider/src/test/java/one/block/eosiojavarpcprovider/RpcTestConstants.java new file mode 100644 index 0000000..0751b5a --- /dev/null +++ b/eosiojavarpcprovider/src/test/java/one/block/eosiojavarpcprovider/RpcTestConstants.java @@ -0,0 +1,883 @@ +package one.block.eosiojavarpcprovider; + +public class RpcTestConstants { + + public static final String GET_INFO_RESPONSE = "{\n" + + " \"server_version\": \"0f6695cb\",\n" + + " \"chain_id\": \"687fa513e18843ad3e820744f4ffcf93b1354036d80737db8dc444fe4b15ad17\",\n" + + " \"head_block_num\": 20583056,\n" + + " \"last_irreversible_block_num\": 20583039,\n" + + " \"last_irreversible_block_id\": \"013a127fab9a79403a20b55914cdc7e1ac136618387325ad3c1914d27528a1f1\",\n" + + " \"head_block_id\": \"013a129048f4486ce8a5ac8380870a8ce1bcbd4ff45b40fd0792503dc44c427d\",\n" + + " \"head_block_time\": \"2019-01-25T16:39:38.000\",\n" + + " \"head_block_producer\": \"blkproducer1\",\n" + + " \"virtual_block_cpu_limit\": 200000000,\n" + + " \"virtual_block_net_limit\": 1048576000,\n" + + " \"block_cpu_limit\": 199900,\n" + + " \"block_net_limit\": 1048576,\n" + + " \"server_version_string\": \"v1.3.0\"\n" + + "}"; + + public static final String GET_BLOCK_RESPONSE = "{\n" + + " \"timestamp\": \"2019-02-21T18:31:40.000\",\n" + + " \"producer\": \"blkproducer2\",\n" + + " \"confirmed\": 0,\n" + + " \"previous\": \"01816fffa4548475add3c45d0e0620f59468a6817426137b37851c23ccafa9cc\",\n" + + " \"transaction_mroot\": \"0000000000000000000000000000000000000000000000000000000000000000\",\n" + + " \"action_mroot\": \"de5493939e3abdca80deeab2fc9389cc43dc1982708653cfe6b225eb788d6659\",\n" + + " \"schedule_version\": 3,\n" + + " \"new_producers\": null,\n" + + " \"header_extensions\": [],\n" + + " \"producer_signature\": \"SIG_K1_KZ3ptku7orAgcyMzd9FKW4jPC9PvjW9BGadFoyxdJFWM44VZdjW28DJgDe6wkNHAxnpqCWSzaBHB1AfbXBUn3HDzetemoA\",\n" + + " \"transactions\": [],\n" + + " \"block_extensions\": [],\n" + + " \"id\": \"0181700002e623f2bf291b86a10a5cec4caab4954d4231f31f050f4f86f26116\",\n" + + " \"block_num\": 25260032,\n" + + " \"ref_block_prefix\": 2249927103\n" + + "}"; + + public static final String GET_RAW_EOSIO_TOKEN_ABI_RESPONSE = "{\n" + + " \"account_name\": \"eosio.token\",\n" + + " \"code_hash\": \"3e0cf4172ab025f9fff5f1db11ee8a34d44779492e1d668ae1dc2d129e865348\",\n" + + " \"abi_hash\": \"43864d5af0fe294d44d19c612036cbe8c098414c4a12a5a7bb0bfe7db1556248\",\n" + + " \"abi\": \"DmVvc2lvOjphYmkvMS4wAQxhY2NvdW50X25hbWUEbmFtZQUIdHJhbnNmZXIABARmcm9tDGFjY291bnRfbmFtZQJ0bwxhY2NvdW50X25hbWUIcXVhbnRpdHkFYXNzZXQEbWVtbwZzdHJpbmcGY3JlYXRlAAIGaXNzdWVyDGFjY291bnRfbmFtZQ5tYXhpbXVtX3N1cHBseQVhc3NldAVpc3N1ZQADAnRvDGFjY291bnRfbmFtZQhxdWFudGl0eQVhc3NldARtZW1vBnN0cmluZwdhY2NvdW50AAEHYmFsYW5jZQVhc3NldA5jdXJyZW5jeV9zdGF0cwADBnN1cHBseQVhc3NldAptYXhfc3VwcGx5BWFzc2V0Bmlzc3VlcgxhY2NvdW50X25hbWUDAAAAVy08zc0IdHJhbnNmZXK8By0tLQp0aXRsZTogVG9rZW4gVHJhbnNmZXIKc3VtbWFyeTogVHJhbnNmZXIgdG9rZW5zIGZyb20gb25lIGFjY291bnQgdG8gYW5vdGhlci4KaWNvbjogaHR0cHM6Ly9jZG4udGVzdG5ldC5kZXYuYjFvcHMubmV0L3Rva2VuLXRyYW5zZmVyLnBuZyNjZTUxZWY5ZjllZWNhMzQzNGU4NTUwN2UwZWQ0OWU3NmZmZjEyNjU0MjJiZGVkMDI1NWYzMTk2ZWE1OWM4YjBjCi0tLQoKIyMgVHJhbnNmZXIgVGVybXMgJiBDb25kaXRpb25zCgpJLCB7e2Zyb219fSwgY2VydGlmeSB0aGUgZm9sbG93aW5nIHRvIGJlIHRydWUgdG8gdGhlIGJlc3Qgb2YgbXkga25vd2xlZGdlOgoKMS4gSSBjZXJ0aWZ5IHRoYXQge3txdWFudGl0eX19IGlzIG5vdCB0aGUgcHJvY2VlZHMgb2YgZnJhdWR1bGVudCBvciB2aW9sZW50IGFjdGl2aXRpZXMuCjIuIEkgY2VydGlmeSB0aGF0LCB0byB0aGUgYmVzdCBvZiBteSBrbm93bGVkZ2UsIHt7dG99fSBpcyBub3Qgc3VwcG9ydGluZyBpbml0aWF0aW9uIG9mIHZpb2xlbmNlIGFnYWluc3Qgb3RoZXJzLgozLiBJIGhhdmUgZGlzY2xvc2VkIGFueSBjb250cmFjdHVhbCB0ZXJtcyAmIGNvbmRpdGlvbnMgd2l0aCByZXNwZWN0IHRvIHt7cXVhbnRpdHl9fSB0byB7e3RvfX0uCgpJIHVuZGVyc3RhbmQgdGhhdCBmdW5kcyB0cmFuc2ZlcnMgYXJlIG5vdCByZXZlcnNpYmxlIGFmdGVyIHRoZSB7eyR0cmFuc2FjdGlvbi5kZWxheV9zZWN9fSBzZWNvbmRzIG9yIG90aGVyIGRlbGF5IGFzIGNvbmZpZ3VyZWQgYnkge3tmcm9tfX0ncyBwZXJtaXNzaW9ucy4KCklmIHRoaXMgYWN0aW9uIGZhaWxzIHRvIGJlIGlycmV2ZXJzaWJseSBjb25maXJtZWQgYWZ0ZXIgcmVjZWl2aW5nIGdvb2RzIG9yIHNlcnZpY2VzIGZyb20gJ3t7dG99fScsIEkgYWdyZWUgdG8gZWl0aGVyIHJldHVybiB0aGUgZ29vZHMgb3Igc2VydmljZXMgb3IgcmVzZW5kIHt7cXVhbnRpdHl9fSBpbiBhIHRpbWVseSBtYW5uZXIuAAAAAAClMXYFaXNzdWUAAAAAAKhs1EUGY3JlYXRlAAIAAAA4T00RMgNpNjQBCGN1cnJlbmN5AQZ1aW50NjQHYWNjb3VudAAAAAAAkE3GA2k2NAEIY3VycmVuY3kBBnVpbnQ2NA5jdXJyZW5jeV9zdGF0cwAAAAA==\"\n" + + "}"; + + + public static final String GET_REQUIRED_KEYS_RESPONSE = "{\n" + + " \"required_keys\": [\n" + + " \"EOS5j67P1W2RyBXAL8sNzYcDLox3yLpxyrxgkYy1xsXzVCvzbYpba\"\n" + + " ]\n" + + "}"; + + public static final String SEND_TRANSACTION_RESPONSE = "{\n" + + " \"transaction_id\": \"ae735820e26a7b771e1b522186294d7cbba035d0c31ca88237559d6c0a3bf00a\",\n" + + " \"processed\": {\n" + + " \"id\": \"ae735820e26a7b771e1b522186294d7cbba035d0c31ca88237559d6c0a3bf00a\",\n" + + " \"block_num\": 21098575,\n" + + " \"block_time\": \"2019-01-28T16:15:37.500\",\n" + + " \"producer_block_id\": null,\n" + + " \"receipt\": {\n" + + " \"status\": \"executed\",\n" + + " \"cpu_usage_us\": 3837,\n" + + " \"net_usage_words\": 36\n" + + " },\n" + + " \"elapsed\": 3837,\n" + + " \"net_usage\": 288,\n" + + " \"scheduled\": false,\n" + + " \"action_traces\": [\n" + + " {\n" + + " \"receipt\": {\n" + + " \"receiver\": \"eosio.assert\",\n" + + " \"act_digest\": \"a4caeedd5e5824dd916c1aaabc84f0a114ddbda83728c8c23ba859d4a8a93721\",\n" + + " \"global_sequence\": 21103875,\n" + + " \"recv_sequence\": 332,\n" + + " \"auth_sequence\": [],\n" + + " \"code_sequence\": 1,\n" + + " \"abi_sequence\": 1\n" + + " },\n" + + " \"act\": {\n" + + " \"account\": \"eosio.assert\",\n" + + " \"name\": \"require\",\n" + + " \"authorization\": [],\n" + + " \"data\": {\n" + + " \"chain_params_hash\": \"cbdd956f52acd910c3c958136d72f8560d1846bc7cf3157f5fbfb72d3001de45\",\n" + + " \"manifest_id\": \"97f4a1fdbecda6d59c96a43009fc5e5d7b8f639b1269c77cec718460dcc19cb3\",\n" + + " \"actions\": [\n" + + " {\n" + + " \"contract\": \"eosio.token\",\n" + + " \"action\": \"transfer\"\n" + + " }\n" + + " ],\n" + + " \"abi_hashes\": [\n" + + " \"43864d5af0fe294d44d19c612036cbe8c098414c4a12a5a7bb0bfe7db1556248\"\n" + + " ]\n" + + " },\n" + + " \"hex_data\": \"cbdd956f52acd910c3c958136d72f8560d1846bc7cf3157f5fbfb72d3001de4597f4a1fdbecda6d59c96a43009fc5e5d7b8f639b1269c77cec718460dcc19cb30100a6823403ea3055000000572d3ccdcd0143864d5af0fe294d44d19c612036cbe8c098414c4a12a5a7bb0bfe7db1556248\"\n" + + " },\n" + + " \"context_free\": false,\n" + + " \"elapsed\": 1264,\n" + + " \"cpu_usage\": 0,\n" + + " \"console\": \"\",\n" + + " \"total_cpu_usage\": 0,\n" + + " \"trx_id\": \"ae735820e26a7b771e1b522186294d7cbba035d0c31ca88237559d6c0a3bf00a\",\n" + + " \"block_num\": 21098575,\n" + + " \"block_time\": \"2019-01-28T16:15:37.500\",\n" + + " \"producer_block_id\": null,\n" + + " \"account_ram_deltas\": [],\n" + + " \"inline_traces\": []\n" + + " },\n" + + " {\n" + + " \"receipt\": {\n" + + " \"receiver\": \"eosio.token\",\n" + + " \"act_digest\": \"9eab239d66d13c34b9cc35a6f79fb2f6d61a2d9df9a484075c82e65d73a0cbc8\",\n" + + " \"global_sequence\": 21103876,\n" + + " \"recv_sequence\": 1366,\n" + + " \"auth_sequence\": [\n" + + " [\n" + + " \"cryptkeeper\",\n" + + " 875\n" + + " ]\n" + + " ],\n" + + " \"code_sequence\": 1,\n" + + " \"abi_sequence\": 4\n" + + " },\n" + + " \"act\": {\n" + + " \"account\": \"eosio.token\",\n" + + " \"name\": \"transfer\",\n" + + " \"authorization\": [\n" + + " {\n" + + " \"actor\": \"cryptkeeper\",\n" + + " \"permission\": \"active\"\n" + + " }\n" + + " ],\n" + + " \"data\": {\n" + + " \"from\": \"cryptkeeper\",\n" + + " \"to\": \"brandon\",\n" + + " \"quantity\": \"42.0000 EOS\",\n" + + " \"memo\": \"the grasshopper lies heavy\"\n" + + " },\n" + + " \"hex_data\": \"00aeaa4ac15cfd4500000060d234cd3da06806000000000004454f53000000001a746865206772617373686f70706572206c696573206865617679\"\n" + + " },\n" + + " \"context_free\": false,\n" + + " \"elapsed\": 2197,\n" + + " \"cpu_usage\": 0,\n" + + " \"console\": \"\",\n" + + " \"total_cpu_usage\": 0,\n" + + " \"trx_id\": \"ae735820e26a7b771e1b522186294d7cbba035d0c31ca88237559d6c0a3bf00a\",\n" + + " \"block_num\": 21098575,\n" + + " \"block_time\": \"2019-01-28T16:15:37.500\",\n" + + " \"producer_block_id\": null,\n" + + " \"account_ram_deltas\": [],\n" + + " \"inline_traces\": [\n" + + " {\n" + + " \"receipt\": {\n" + + " \"receiver\": \"cryptkeeper\",\n" + + " \"act_digest\": \"9eab239d66d13c34b9cc35a6f79fb2f6d61a2d9df9a484075c82e65d73a0cbc8\",\n" + + " \"global_sequence\": 21103877,\n" + + " \"recv_sequence\": 496,\n" + + " \"auth_sequence\": [\n" + + " [\n" + + " \"cryptkeeper\",\n" + + " 876\n" + + " ]\n" + + " ],\n" + + " \"code_sequence\": 1,\n" + + " \"abi_sequence\": 4\n" + + " },\n" + + " \"act\": {\n" + + " \"account\": \"eosio.token\",\n" + + " \"name\": \"transfer\",\n" + + " \"authorization\": [\n" + + " {\n" + + " \"actor\": \"cryptkeeper\",\n" + + " \"permission\": \"active\"\n" + + " }\n" + + " ],\n" + + " \"data\": {\n" + + " \"from\": \"cryptkeeper\",\n" + + " \"to\": \"brandon\",\n" + + " \"quantity\": \"42.0000 EOS\",\n" + + " \"memo\": \"the grasshopper lies heavy\"\n" + + " },\n" + + " \"hex_data\": \"00aeaa4ac15cfd4500000060d234cd3da06806000000000004454f53000000001a746865206772617373686f70706572206c696573206865617679\"\n" + + " },\n" + + " \"context_free\": false,\n" + + " \"elapsed\": 6,\n" + + " \"cpu_usage\": 0,\n" + + " \"console\": \"\",\n" + + " \"total_cpu_usage\": 0,\n" + + " \"trx_id\": \"ae735820e26a7b771e1b522186294d7cbba035d0c31ca88237559d6c0a3bf00a\",\n" + + " \"block_num\": 21098575,\n" + + " \"block_time\": \"2019-01-28T16:15:37.500\",\n" + + " \"producer_block_id\": null,\n" + + " \"account_ram_deltas\": [],\n" + + " \"inline_traces\": []\n" + + " },\n" + + " {\n" + + " \"receipt\": {\n" + + " \"receiver\": \"brandon\",\n" + + " \"act_digest\": \"9eab239d66d13c34b9cc35a6f79fb2f6d61a2d9df9a484075c82e65d73a0cbc8\",\n" + + " \"global_sequence\": 21103878,\n" + + " \"recv_sequence\": 582,\n" + + " \"auth_sequence\": [\n" + + " [\n" + + " \"cryptkeeper\",\n" + + " 877\n" + + " ]\n" + + " ],\n" + + " \"code_sequence\": 1,\n" + + " \"abi_sequence\": 4\n" + + " },\n" + + " \"act\": {\n" + + " \"account\": \"eosio.token\",\n" + + " \"name\": \"transfer\",\n" + + " \"authorization\": [\n" + + " {\n" + + " \"actor\": \"cryptkeeper\",\n" + + " \"permission\": \"active\"\n" + + " }\n" + + " ],\n" + + " \"data\": {\n" + + " \"from\": \"cryptkeeper\",\n" + + " \"to\": \"brandon\",\n" + + " \"quantity\": \"42.0000 EOS\",\n" + + " \"memo\": \"the grasshopper lies heavy\"\n" + + " },\n" + + " \"hex_data\": \"00aeaa4ac15cfd4500000060d234cd3da06806000000000004454f53000000001a746865206772617373686f70706572206c696573206865617679\"\n" + + " },\n" + + " \"context_free\": false,\n" + + " \"elapsed\": 5,\n" + + " \"cpu_usage\": 0,\n" + + " \"console\": \"\",\n" + + " \"total_cpu_usage\": 0,\n" + + " \"trx_id\": \"ae735820e26a7b771e1b522186294d7cbba035d0c31ca88237559d6c0a3bf00a\",\n" + + " \"block_num\": 21098575,\n" + + " \"block_time\": \"2019-01-28T16:15:37.500\",\n" + + " \"producer_block_id\": null,\n" + + " \"account_ram_deltas\": [],\n" + + " \"inline_traces\": []\n" + + " }\n" + + " ]\n" + + " }\n" + + " ],\n" + + " \"except\": null\n" + + " }\n" + + "}"; + + public static final String SEND_TRANSACTION_ERROR_RESPONSE = "{\n" + + " \"code\": 500,\n" + + " \"message\": \"Internal Service Error\",\n" + + " \"error\": {\n" + + " \"code\": 3040005,\n" + + " \"name\": \"expired_tx_exception\",\n" + + " \"what\": \"Expired Transaction\",\n" + + " \"details\": [\n" + + " {\n" + + " \"message\": \"expired transaction ae735820e26a7b771e1b522186294d7cbba035d0c31ca88237559d6c0a3bf00a\",\n" + + " \"file\": \"producer_plugin.cpp\",\n" + + " \"line_number\": 378,\n" + + " \"method\": \"on_incoming_transaction_async\"\n" + + " }\n" + + " ]\n" + + " }\n" + + "}"; + + public static final String GET_ACCOUNT_RESPONSE = "{\n" + + " \"account_name\": \"test_account\",\n" + + " \"head_block_num\": 33869724,\n" + + " \"head_block_time\": \"2019-04-12T19:59:45.500\",\n" + + " \"privileged\": false,\n" + + " \"last_code_update\": \"1970-01-01T00:00:00.000\",\n" + + " \"created\": \"2019-04-09T15:05:50.000\",\n" + + " \"ram_quota\": 9549,\n" + + " \"net_weight\": 1000000,\n" + + " \"cpu_weight\": 1000000,\n" + + " \"net_limit\": {\n" + + " \"used\": 0,\n" + + " \"available\": \"55039480545\",\n" + + " \"max\": \"55039480545\"\n" + + " },\n" + + " \"cpu_limit\": {\n" + + " \"used\": 0,\n" + + " \"available\": \"10497947797\",\n" + + " \"max\": \"10497947797\"\n" + + " },\n" + + " \"ram_usage\": 2996,\n" + + " \"permissions\": [\n" + + " {\n" + + " \"perm_name\": \"active\",\n" + + " \"parent\": \"owner\",\n" + + " \"required_auth\": {\n" + + " \"threshold\": 1,\n" + + " \"keys\": [\n" + + " {\n" + + " \"key\": \"sample key\",\n" + + " \"weight\": 1\n" + + " }\n" + + " ],\n" + + " \"accounts\": [],\n" + + " \"waits\": []\n" + + " }\n" + + " },\n" + + " {\n" + + " \"perm_name\": \"owner\",\n" + + " \"parent\": \"\",\n" + + " \"required_auth\": {\n" + + " \"threshold\": 1,\n" + + " \"keys\": [\n" + + " {\n" + + " \"key\": \"sample key\",\n" + + " \"weight\": 1\n" + + " }\n" + + " ],\n" + + " \"accounts\": [],\n" + + " \"waits\": []\n" + + " }\n" + + " }\n" + + " ],\n" + + " \"total_resources\": {\n" + + " \"owner\": \"test_account\",\n" + + " \"net_weight\": \"100.0000 EOS\",\n" + + " \"cpu_weight\": \"100.0000 EOS\",\n" + + " \"ram_bytes\": 8149\n" + + " },\n" + + " \"self_delegated_bandwidth\": null,\n" + + " \"refund_request\": null,\n" + + " \"voter_info\": null\n" + + "}"; + + public static final String PUSH_TRANSACTIONS_REQUEST = "[\n" + + "\t{\n" + + "\t\t\"signatures\": [\n" + + "\t\t\t\"signature 1\"\n" + + "\t\t],\n" + + "\t\t\"compression\": 0,\n" + + "\t\t\"packed_context_free_data\": \"\",\n" + + "\t\t\"packed_trx\": \"transaction 1\"\n" + + "\t},\n" + + "\t{\n" + + "\t\t\"signatures\": [\n" + + "\t\t\t\"signature 2\"\n" + + "\t\t],\n" + + "\t\t\"compression\": 0,\n" + + "\t\t\"packed_context_free_data\": \"\",\n" + + "\t\t\"packed_trx\": \"transaction 2\"\n" + + "\t}\n" + + "]"; + + public static final String PUSH_TRANSACTIONS_RESPONSE = "[" + + SEND_TRANSACTION_RESPONSE + "," + + SEND_TRANSACTION_RESPONSE + + "]"; + + public static final String GET_BLOCK_HEADER_STATE_REQUEST = "{\n" + + "\"block_num_or_id\" : \"34341092\"\n" + + "}"; + + public static final String GET_BLOCK_HEADER_STATE_RESPONSE = "{\n" + + " \"id\": \"020c00e41e66ca6a0fa489c9b2df391fd06089426a3daed5e4859cebc1d41b73\",\n" + + " \"block_num\": 34341092,\n" + + " \"header\": {\n" + + " \"timestamp\": \"2019-04-15T13:27:49.500\",\n" + + " \"producer\": \"blkproducer3\",\n" + + " \"confirmed\": 0,\n" + + " \"previous\": \"020c00e3f28a0b2527e99dbd4a3fa9ee5741da5da54a6c24eebebdd3e4982d02\",\n" + + " \"transaction_mroot\": \"0000000000000000000000000000000000000000000000000000000000000000\",\n" + + " \"action_mroot\": \"aceb0c73b6339dd384a8ad88687717f031098ce686181827f5d3dba4cc713f48\",\n" + + " \"schedule_version\": 3,\n" + + " \"header_extensions\": [],\n" + + " \"producer_signature\": \"SIG_K1_K3F1T4GQw94Qj9FB2LcxErbkhScbCMKxS7VTbGnJFHuMzLTRWrbBgRsypsa2e95368AfNY7qynyNG9FuvD5WiJZSteraze\"\n" + + " },\n" + + " \"dpos_proposed_irreversible_blocknum\": 34341076,\n" + + " \"dpos_irreversible_blocknum\": 34341052,\n" + + " \"bft_irreversible_blocknum\": 0,\n" + + " \"pending_schedule_lib_num\": 21818600,\n" + + " \"pending_schedule_hash\": \"a978d8d8f20419e226a3c6a1d38ae67a922950b06aa318b2612be9c13f1ede67\",\n" + + " \"pending_schedule\": {\n" + + " \"version\": 3,\n" + + " \"producers\": []\n" + + " },\n" + + " \"active_schedule\": {\n" + + " \"version\": 3,\n" + + " \"producers\": [\n" + + " {\n" + + " \"producer_name\": \"blkproducer1\",\n" + + " \"block_signing_key\": \"EOS5DgtLq5fSqsc6SD3SD98Tu5P7dirfNdnD3pjCLtURiDWTQ6pzV\"\n" + + " },\n" + + " {\n" + + " \"producer_name\": \"blkproducer2\",\n" + + " \"block_signing_key\": \"EOS8QEPQ1wiZrdHavectXNpMy3TpcyYGXSVfkVGhyVTaJ7FT8bzCZ\"\n" + + " },\n" + + " {\n" + + " \"producer_name\": \"blkproducer3\",\n" + + " \"block_signing_key\": \"EOS7YTjjzt7coagRE5i64JhZB4ucH23Nz5mDhXdzU6QC7gfXwy8M9\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"blockroot_merkle\": {\n" + + " \"_active_nodes\": [\n" + + " \"020c00e3f28a0b2527e99dbd4a3fa9ee5741da5da54a6c24eebebdd3e4982d02\",\n" + + " \"0880dd1f0cc29ef284d6ec727efebd6369c0df6265d3483c45308877f7198af5\",\n" + + " \"d2b8eddf6f9e5493183b66e6a2443aa349ed00feabd7a830344ba6cc157285ca\",\n" + + " \"40ff3c15876905f6835eb00b792c53d7507149d24128a4b4444641a6be89b21a\",\n" + + " \"796459e92ba4b2118d1651e6823de7fda882726ec2697c32a5324c555891f95a\",\n" + + " \"e12e1f5104074d76612e49a3166c65ae9ee3198d22c35fa1d1c79e8cb6e53f8f\",\n" + + " \"d9d005c528ecfda513f954d0b7164b33bb2289f5271ac7a0d93234ae5a0ba59c\",\n" + + " \"f541345de34d499b2bf108c5bbf797c7081e3437263ec69cc420fe4668f20910\",\n" + + " \"2168cb08f341c52ae3267461f8cc859dde530782fe7d6ed17dad50d126b55d89\"\n" + + " ],\n" + + " \"_node_count\": 34341091\n" + + " },\n" + + " \"producer_to_last_produced\": [\n" + + " [\n" + + " \"blkproducer1\",\n" + + " 34341076\n" + + " ],\n" + + " [\n" + + " \"blkproducer2\",\n" + + " 34341088\n" + + " ],\n" + + " [\n" + + " \"blkproducer3\",\n" + + " 34341092\n" + + " ]\n" + + " ],\n" + + " \"producer_to_last_implied_irb\": [\n" + + " [\n" + + " \"blkproducer1\",\n" + + " 34341052\n" + + " ],\n" + + " [\n" + + " \"blkproducer2\",\n" + + " 34341064\n" + + " ],\n" + + " [\n" + + " \"blkproducer3\",\n" + + " 34341076\n" + + " ]\n" + + " ],\n" + + " \"block_signing_key\": \"EOS7YTjjzt7coagRE5i64JhZB4ucH23Nz5mDhXdzU6QC7gfXwy8M9\",\n" + + " \"confirm_count\": [\n" + + " 1,\n" + + " 1,\n" + + " 1,\n" + + " 1,\n" + + " 1,\n" + + " 1,\n" + + " 1,\n" + + " 1,\n" + + " 1,\n" + + " 1,\n" + + " 1,\n" + + " 1,\n" + + " 2,\n" + + " 2,\n" + + " 2,\n" + + " 2\n" + + " ],\n" + + " \"confirmations\": []\n" + + "}"; + + public static final String GET_ABI_REQUEST = "{\n" + + "\"account_name\" : \"eosio.token\"\n" + + "}"; + public static final String GET_ABI_RESPONSE = "{\n" + + " \"account_name\": \"eosio.token\",\n" + + " \"abi\": {\n" + + " \"version\": \"eosio::abi/1.0\",\n" + + " \"types\": [\n" + + " {\n" + + " \"new_type_name\": \"account_name\",\n" + + " \"type\": \"name\"\n" + + " }\n" + + " ],\n" + + " \"structs\": [\n" + + " {\n" + + " \"name\": \"transfer\",\n" + + " \"base\": \"\",\n" + + " \"fields\": [\n" + + " {\n" + + " \"name\": \"from\",\n" + + " \"type\": \"account_name\"\n" + + " },\n" + + " {\n" + + " \"name\": \"to\",\n" + + " \"type\": \"account_name\"\n" + + " },\n" + + " {\n" + + " \"name\": \"quantity\",\n" + + " \"type\": \"asset\"\n" + + " },\n" + + " {\n" + + " \"name\": \"memo\",\n" + + " \"type\": \"string\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"name\": \"create\",\n" + + " \"base\": \"\",\n" + + " \"fields\": [\n" + + " {\n" + + " \"name\": \"issuer\",\n" + + " \"type\": \"account_name\"\n" + + " },\n" + + " {\n" + + " \"name\": \"maximum_supply\",\n" + + " \"type\": \"asset\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"name\": \"issue\",\n" + + " \"base\": \"\",\n" + + " \"fields\": [\n" + + " {\n" + + " \"name\": \"to\",\n" + + " \"type\": \"account_name\"\n" + + " },\n" + + " {\n" + + " \"name\": \"quantity\",\n" + + " \"type\": \"asset\"\n" + + " },\n" + + " {\n" + + " \"name\": \"memo\",\n" + + " \"type\": \"string\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"name\": \"account\",\n" + + " \"base\": \"\",\n" + + " \"fields\": [\n" + + " {\n" + + " \"name\": \"balance\",\n" + + " \"type\": \"asset\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " {\n" + + " \"name\": \"currency_stats\",\n" + + " \"base\": \"\",\n" + + " \"fields\": [\n" + + " {\n" + + " \"name\": \"supply\",\n" + + " \"type\": \"asset\"\n" + + " },\n" + + " {\n" + + " \"name\": \"max_supply\",\n" + + " \"type\": \"asset\"\n" + + " },\n" + + " {\n" + + " \"name\": \"issuer\",\n" + + " \"type\": \"account_name\"\n" + + " }\n" + + " ]\n" + + " }\n" + + " ],\n" + + " \"actions\": [\n" + + " {\n" + + " \"name\": \"transfer\",\n" + + " \"type\": \"transfer\",\n" + + " \"ricardian_contract\": \"---\\ntitle: Token Transfer\\nsummary: Transfer tokens from one account to another.\\nicon: https://cdn.testnet.dev.b1ops.net/token-transfer.png#ce51ef9f9eeca3434e85507e0ed49e76fff1265422bded0255f3196ea59c8b0c\\n---\\n\\n## Transfer Terms & Conditions\\n\\nI, {{from}}, certify the following to be true to the best of my knowledge:\\n\\n1. I certify that {{quantity}} is not the proceeds of fraudulent or violent activities.\\n2. I certify that, to the best of my knowledge, {{to}} is not supporting initiation of violence against others.\\n3. I have disclosed any contractual terms & conditions with respect to {{quantity}} to {{to}}.\\n\\nI understand that funds transfers are not reversible after the {{$transaction.delay_sec}} seconds or other delay as configured by {{from}}'s permissions.\\n\\nIf this action fails to be irreversibly confirmed after receiving goods or services from '{{to}}', I agree to either return the goods or services or resend {{quantity}} in a timely manner.\"\n" + + " },\n" + + " {\n" + + " \"name\": \"issue\",\n" + + " \"type\": \"issue\",\n" + + " \"ricardian_contract\": \"\"\n" + + " },\n" + + " {\n" + + " \"name\": \"create\",\n" + + " \"type\": \"create\",\n" + + " \"ricardian_contract\": \"\"\n" + + " }\n" + + " ],\n" + + " \"tables\": [\n" + + " {\n" + + " \"name\": \"accounts\",\n" + + " \"index_type\": \"i64\",\n" + + " \"key_names\": [\n" + + " \"currency\"\n" + + " ],\n" + + " \"key_types\": [\n" + + " \"uint64\"\n" + + " ],\n" + + " \"type\": \"account\"\n" + + " },\n" + + " {\n" + + " \"name\": \"stat\",\n" + + " \"index_type\": \"i64\",\n" + + " \"key_names\": [\n" + + " \"currency\"\n" + + " ],\n" + + " \"key_types\": [\n" + + " \"uint64\"\n" + + " ],\n" + + " \"type\": \"currency_stats\"\n" + + " }\n" + + " ],\n" + + " \"ricardian_clauses\": [],\n" + + " \"error_messages\": [],\n" + + " \"abi_extensions\": [],\n" + + " \"variants\": []\n" + + " }\n" + + "}"; + + public static final String GET_CURRENT_BALANCE_REQUEST = "{\n" + + "\t\"code\" : \"eosio.token\"\n" + + "\t\"account\" : \"test_account\"\n" + + "}"; + public static final String GET_CURRENT_BALANCE_RESPONSE = "[\n" + + " \"1.0000 EOS\"\n" + + "]"; + + public static final String GET_CURRENT_STATS_REQUEST = "{\n" + + "\t\"code\" : \"eosio.token\"\n" + + "\t\"symbol\" : \"EOS\"\n" + + "}"; + + public static final String GET_CURRENT_STATS_RESPONSE = "{\n" + + " \"EOS\": {\n" + + " \"supply\": \"100000000.0000 EOS\",\n" + + " \"max_supply\": \"10000000000.0000 EOS\",\n" + + " \"issuer\": \"eosio\"\n" + + " }\n" + + "}"; + + public static final String GET_PRODUCER_REQUEST = "{\"limit\":\"10\",\"lower_bound\":\"blkproducer2\",\"json\":true}"; + + public static final String GET_PRODUCER_RESPONSE = "{\n" + + " \"rows\": [\n" + + " {\n" + + " \"owner\": \"blkproducer2\",\n" + + " \"total_votes\": \"0.00000000000000000\",\n" + + " \"producer_key\": \"EOS8QEPQ1wiZrdHavectXNpMy3TpcyYGXSVfkVGhyVTaJ7FT8bzCZ\",\n" + + " \"is_active\": 1,\n" + + " \"url\": \"\",\n" + + " \"unpaid_blocks\": 0,\n" + + " \"last_claim_time\": \"1970-01-01T00:00:00.000\",\n" + + " \"location\": 0\n" + + " },\n" + + " {\n" + + " \"owner\": \"blkproducer3\",\n" + + " \"total_votes\": \"0.00000000000000000\",\n" + + " \"producer_key\": \"EOS7YTjjzt7coagRE5i64JhZB4ucH23Nz5mDhXdzU6QC7gfXwy8M9\",\n" + + " \"is_active\": 1,\n" + + " \"url\": \"\",\n" + + " \"unpaid_blocks\": 0,\n" + + " \"last_claim_time\": \"2019-01-31T22:50:21.500\",\n" + + " \"location\": 0\n" + + " }\n" + + " ],\n" + + " \"total_producer_vote_weight\": \"0.00000000000000000\",\n" + + " \"more\": \"\"\n" + + "}"; + + public static final String GET_RAW_CODE_AND_ABI_REQUEST = "{{\n" + + "\"account_name\" : \"eosio.token\"\n" + + "}"; + public static final String GET_RAW_CODE_AND_ABI_RESPONSE = "{\n" + + " \"account_name\": \"eosio.token\",\n" + + " \"wasm\": \"AGFzbQEAAAABfhVgA39+fwBgBX9+fn9/AGAEf35/fwBgAABgAAF+YAJ+fgBgAX4AYAJ/fwBgBH5+fn4Bf2AGfn5+fn9/AX9gA39/fwF/YAF+AX9gAX8AYAABf2ACf38Bf2ABfwF/YAR/f39/AGAEf35/fgBgBH5+f38AYAN/fn8Bf2ADfn5+AALFAhEDZW52BWFib3J0AAMDZW52EGFjdGlvbl9kYXRhX3NpemUADQNlbnYQY3VycmVudF9yZWNlaXZlcgAEA2VudgxjdXJyZW50X3RpbWUABANlbnYLZGJfZmluZF9pNjQACANlbnYKZGJfZ2V0X2k2NAAKA2Vudg1kYl9yZW1vdmVfaTY0AAwDZW52DGRiX3N0b3JlX2k2NAAJA2Vudg1kYl91cGRhdGVfaTY0AAIDZW52DGVvc2lvX2Fzc2VydAAHA2Vudgppc19hY2NvdW50AAsDZW52Bm1lbWNweQAKA2VudhByZWFkX2FjdGlvbl9kYXRhAA4DZW52DHJlcXVpcmVfYXV0aAAGA2Vudg1yZXF1aXJlX2F1dGgyAAUDZW52EXJlcXVpcmVfcmVjaXBpZW50AAYDZW52C3NlbmRfaW5saW5lAAcDMTAODg4NDAAODwcQBwIREgcHBw4ODg4QARMAEwcUDg4OBwcODgcPDAwHDA4KDw4PDAMEBQFwAQQEBQMBAAEH9wMPBm1lbW9yeQIAFl9aZXFSSzExY2hlY2tzdW0yNTZTMV8AERZfWmVxUksxMWNoZWNrc3VtMTYwUzFfABIWX1puZVJLMTFjaGVja3N1bTE2MFMxXwATA25vdwAUMF9aTjVlb3NpbzEycmVxdWlyZV9hdXRoRVJLTlNfMTZwZXJtaXNzaW9uX2xldmVsRQAVIl9aTjVlb3NpbzV0b2tlbjZjcmVhdGVFeU5TXzVhc3NldEUAFmFfWk41ZW9zaW81dG9rZW41aXNzdWVFeU5TXzVhc3NldEVOU3QzX18xMTJiYXNpY19zdHJpbmdJY05TMl8xMWNoYXJfdHJhaXRzSWNFRU5TMl85YWxsb2NhdG9ySWNFRUVFABwpX1pONWVvc2lvNXRva2VuMTFhZGRfYmFsYW5jZUV5TlNfNWFzc2V0RXkAHWVfWk41ZW9zaW81dG9rZW44dHJhbnNmZXJFeXlOU181YXNzZXRFTlN0M19fMTEy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QQgQCxogB0F4cUEIR0GAAxAJIAogA0EIakEIEAsaIAUgATYCFCAJIAU2AhggCSAFQQhqKQMAQgiIIgg3AxAgCSAFKAIUIgc2AgwCQAJAIABBHGoiASgCACIGIABBIGooAgBPDQAgBiAINwMIIAYgBzYCECAJQQA2AhggBiAFNgIAIAEgBkEYajYCAAwBCyACIAlBGGogCUEQaiAJQQxqECYLIAkoAhghBiAJQQA2AhggBkUNACAGEDYLQQAgCUEgajYCBCAFC6oDAQR/AkACQCAAKAIEIAAoAgAiBmtBGG0iBEEBaiIFQavVqtUATw0AQarVqtUAIQcCQAJAIAAoAgggBmtBGG0iBkHUqtUqSw0AIAUgBkEBdCIHIAcgBUkbIgdFDQELIAdBGGwQNSEGDAILQQAhB0EAIQYMAQsgABA5AAsgASgCACEFIAFBADYCACAGIARBGGxqIgEgBTYCACABIAIpAwA3AwggASADKAIANgIQIAYgB0EYbGohBCABQRhqIQUCQAJAIABBBGooAgAiBiAAKAIAIgdGDQADQCAGQWhqIgIoAgAhAyACQQA2AgAgAUFoaiADNgIAIAFBeGogBkF4aigCADYCACABQXRqIAZBdGooAgA2AgAgAUFwaiAGQXBqKAIANgIAIAFBaGohASACIQYgByACRw0ACyAAQQRqKAIAIQcgACgCACEGDAELIAchBgsgACABNgIAIABBBGogBTYCACAAQQhqIAQ2AgACQCAHIAZGDQADQCAHQWhqIgcoAgAhASAHQQA2AgACQCABRQ0AIAEQNgsgBiAHRw0ACwsCQCAGRQ0AIAYQNgsLogUGAX4BfwF+AX8BfgJ/QQBBACgCBEHwAGsiCzYCBCABIAJSQeAHEAkgARANIAIQCkGACBAJIAMpAwghBUEAIQggC0HoAGpBADYCACALIAVCCIgiCTcDUCALQn83A1ggC0IANwNgIAsgACkDADcDSCALQcgAaiAJQaAIECghBiABEA8gAhAPAkAgAykDACIHQv//////////P3xC/v//////////AFYNAEEAIQoCQANAIAmnQRh0Qf////97akH+///XAUsNAQJAIAlCCIgiCUL/AYNCAFINAANAIAlCCIgiCUL/AYNCAFINAyAKQQFqIgpBB0gNAAsLQQEhCCAKQQFqIgpBB0gNAAwCCwtBACEI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YXNzZWQgdG8gbW9kaWZ5IGlzIG5vdCBpbiBtdWx0aV9pbmRleAAAQbAFCzNjYW5ub3QgbW9kaWZ5IG9iamVjdHMgaW4gdGFibGUgb2YgYW5vdGhlciBjb250cmFjdAAAQfAFCythdHRlbXB0IHRvIGFkZCBhc3NldCB3aXRoIGRpZmZlcmVudCBzeW1ib2wAAEGgBgsTYWRkaXRpb24gdW5kZXJmbG93AABBwAYLEmFkZGl0aW9uIG92ZXJmbG93AABB4AYLO3VwZGF0ZXIgY2Fubm90IGNoYW5nZSBwcmltYXJ5IGtleSB3aGVuIG1vZGlmeWluZyBhbiBvYmplY3QAAEGgBwsHYWN0aXZlAABBsAcLI2Nhbm5vdCBwYXNzIGVuZCBpdGVyYXRvciB0byBtb2RpZnkAAEHgBwsYY2Fubm90IHRyYW5zZmVyIHRvIHNlbGYAAEGACAsadG8gYWNjb3VudCBkb2VzIG5vdCBleGlzdAAAQaAICxN1bmFibGUgdG8gZmluZCBrZXkAAEHACAsgbXVzdCB0cmFuc2ZlciBwb3NpdGl2ZSBxdWFudGl0eQAAQeAICxhubyBiYWxhbmNlIG9iamVjdCBmb3VuZAAAQYAJCxJvdmVyZHJhd24gYmFsYW5jZQAAQaAJCzBhdHRlbXB0IHRvIHN1YnRyYWN0IGFzc2V0IHdpdGggZGlmZmVyZW50IHN5bWJvbAAAQdAJCxZzdWJ0cmFjdGlvbiB1bmRlcmZsb3cAAEHwCQsVc3VidHJhY3Rpb24gb3ZlcmZsb3cAAEGQCgstb2JqZWN0IHBhc3NlZCB0byBlcmFzZSBpcyBub3QgaW4gbXVsdGlfaW5kZXgAAEHACgsyY2Fubm90IGVyYXNlIG9iamVjdHMgaW4gdGFibGUgb2YgYW5vdGhlciBjb250cmFjdAAAQYALCzVhdHRlbXB0IHRvIHJlbW92ZSBvYmplY3QgdGhhdCB3YXMgbm90IGluIG11bHRpX2luZGV4AABBwAsLCG9uZXJyb3IAAEHQCwsGZW9zaW8AAEHgCwtAb25lcnJvciBhY3Rpb24ncyBhcmUgb25seSB2YWxpZCBmcm9tIHRoZSAiZW9zaW8iIHN5c3RlbSBhY2NvdW50AABBoAwLBGdldAAAQYDOAAtWbWFsbG9jX2Zyb21fZnJlZWQgd2FzIGRlc2lnbmVkIHRvIG9ubHkgYmUgY2FsbGVkIGFmdGVyIF9oZWFwIHdhcyBjb21wbGV0ZWx5IGFsbG9jYXRlZAA==\",\n" + + " \"abi\": \"DmVvc2lvOjphYmkvMS4wAQxhY2NvdW50X25hbWUEbmFtZQUIdHJhbnNmZXIABARmcm9tDGFjY291bnRfbmFtZQJ0bwxhY2NvdW50X25hbWUIcXVhbnRpdHkFYXNzZXQEbWVtbwZzdHJpbmcGY3JlYXRlAAIGaXNzdWVyDGFjY291bnRfbmFtZQ5tYXhpbXVtX3N1cHBseQVhc3NldAVpc3N1ZQADAnRvDGFjY291bnRfbmFtZQhxdWFudGl0eQVhc3NldARtZW1vBnN0cmluZwdhY2NvdW50AAEHYmFsYW5jZQVhc3NldA5jdXJyZW5jeV9zdGF0cwADBnN1cHBseQVhc3NldAptYXhfc3VwcGx5BWFzc2V0Bmlzc3VlcgxhY2NvdW50X25hbWUDAAAAVy08zc0IdHJhbnNmZXK8By0tLQp0aXRsZTogVG9rZW4gVHJhbnNmZXIKc3VtbWFyeTogVHJhbnNmZXIgdG9rZW5zIGZyb20gb25lIGFjY291bnQgdG8gYW5vdGhlci4KaWNvbjogaHR0cHM6Ly9jZG4udGVzdG5ldC5kZXYuYjFvcHMubmV0L3Rva2VuLXRyYW5zZmVyLnBuZyNjZTUxZWY5ZjllZWNhMzQzNGU4NTUwN2UwZWQ0OWU3NmZmZjEyNjU0MjJiZGVkMDI1NWYzMTk2ZWE1OWM4YjBjCi0tLQoKIyMgVHJhbnNmZXIgVGVybXMgJiBDb25kaXRpb25zCgpJLCB7e2Zyb219fSwgY2VydGlmeSB0aGUgZm9sbG93aW5nIHRvIGJlIHRydWUgdG8gdGhlIGJlc3Qgb2YgbXkga25vd2xlZGdlOgoKMS4gSSBjZXJ0aWZ5IHRoYXQge3txdWFudGl0eX19IGlzIG5vdCB0aGUgcHJvY2VlZHMgb2YgZnJhdWR1bGVudCBvciB2aW9sZW50IGFjdGl2aXRpZXMuCjIuIEkgY2VydGlmeSB0aGF0LCB0byB0aGUgYmVzdCBvZiBteSBrbm93bGVkZ2UsIHt7dG99fSBpcyBub3Qgc3VwcG9ydGluZyBpbml0aWF0aW9uIG9mIHZpb2xlbmNlIGFnYWluc3Qgb3RoZXJzLgozLiBJIGhhdmUgZGlzY2xvc2VkIGFueSBjb250cmFjdHVhbCB0ZXJtcyAmIGNvbmRpdGlvbnMgd2l0aCByZXNwZWN0IHRvIHt7cXVhbnRpdHl9fSB0byB7e3RvfX0uCgpJIHVuZGVyc3RhbmQgdGhhdCBmdW5kcyB0cmFuc2ZlcnMgYXJlIG5vdCByZXZlcnNpYmxlIGFmdGVyIHRoZSB7eyR0cmFuc2FjdGlvbi5kZWxheV9zZWN9fSBzZWNvbmRzIG9yIG90aGVyIGRlbGF5IGFzIGNvbmZpZ3VyZWQgYnkge3tmcm9tfX0ncyBwZXJtaXNzaW9ucy4KCklmIHRoaXMgYWN0aW9uIGZhaWxzIHRvIGJlIGlycmV2ZXJzaWJseSBjb25maXJtZWQgYWZ0ZXIgcmVjZWl2aW5nIGdvb2RzIG9yIHNlcnZpY2VzIGZyb20gJ3t7dG99fScsIEkgYWdyZWUgdG8gZWl0aGVyIHJldHVybiB0aGUgZ29vZHMgb3Igc2VydmljZXMgb3IgcmVzZW5kIHt7cXVhbnRpdHl9fSBpbiBhIHRpbWVseSBtYW5uZXIuAAAAAAClMXYFaXNzdWUAAAAAAKhs1EUGY3JlYXRlAAIAAAA4T00RMgNpNjQBCGN1cnJlbmN5AQZ1aW50NjQHYWNjb3VudAAAAAAAkE3GA2k2NAEIY3VycmVuY3kBBnVpbnQ2NA5jdXJyZW5jeV9zdGF0cwAAAAA==\"\n" + + "}"; + + public static final String GET_TABLE_ROWS_REQUEST = "{\n" + + "\t\"scope\" : \"test_account\"\n" + + "\t\"code\" : \"eosio.token\"\n" + + "\t\"table\" : \"accounts\"\n" + + "\t\"json\" : true\n" + + "\t\"limit\" : 10\n" + + "}"; + public static final String GET_TABLE_ROWS_RESPONSE = "{\n" + + " \"rows\": [\n" + + " {\n" + + " \"balance\": \"1000.0000 EOS\"\n" + + " }\n" + + " ],\n" + + " \"more\": false\n" + + "}"; + + public static final String GET_TABLE_BY_SCOPE_REQUEST = "{\n" + + "\t\"code\" : \"eosio.token\"\n" + + "\t\"table\" : \"accounts\"\n" + + "\t\"limit\" : 10\n" + + "}"; + + public static final String GET_TABLE_BY_SCOPE_RESPONSE = "{\n" + + " \"rows\": [\n" + + " {\n" + + " \"code\": \"eosio.token\",\n" + + " \"scope\": \"test_account_1\",\n" + + " \"table\": \"accounts\",\n" + + " \"payer\": \"test_account_10\",\n" + + " \"count\": 1\n" + + " },\n" + + " {\n" + + " \"code\": \"eosio.token\",\n" + + " \"scope\": \"test_account_2\",\n" + + " \"table\": \"accounts\",\n" + + " \"payer\": \"eosio\",\n" + + " \"count\": 1\n" + + " },\n" + + " {\n" + + " \"code\": \"eosio.token\",\n" + + " \"scope\": \"test_account_7\",\n" + + " \"table\": \"accounts\",\n" + + " \"payer\": \"eosio\",\n" + + " \"count\": 1\n" + + " },\n" + + " {\n" + + " \"code\": \"eosio.token\",\n" + + " \"scope\": \"test_account_3\",\n" + + " \"table\": \"accounts\",\n" + + " \"payer\": \"cryptkeeper\",\n" + + " \"count\": 1\n" + + " },\n" + + " {\n" + + " \"code\": \"eosio.token\",\n" + + " \"scope\": \"test_account_4\",\n" + + " \"table\": \"accounts\",\n" + + " \"payer\": \"test_account_1\",\n" + + " \"count\": 1\n" + + " },\n" + + " {\n" + + " \"code\": \"eosio.token\",\n" + + " \"scope\": \"test_account_5\",\n" + + " \"table\": \"accounts\",\n" + + " \"payer\": \"eosio\",\n" + + " \"count\": 1\n" + + " },\n" + + " {\n" + + " \"code\": \"eosio.token\",\n" + + " \"scope\": \"test_account_6\",\n" + + " \"table\": \"accounts\",\n" + + " \"payer\": \"eosio\",\n" + + " \"count\": 1\n" + + " },\n" + + " {\n" + + " \"code\": \"eosio.token\",\n" + + " \"scope\": \"test_account_7\",\n" + + " \"table\": \"accounts\",\n" + + " \"payer\": \"eosio\",\n" + + " \"count\": 1\n" + + " },\n" + + " {\n" + + " \"code\": \"eosio.token\",\n" + + " \"scope\": \"test_account_8\",\n" + + " \"table\": \"accounts\",\n" + + " \"payer\": \"eosio\",\n" + + " \"count\": 1\n" + + " },\n" + + " {\n" + + " \"code\": \"eosio.token\",\n" + + " \"scope\": \"eosio\",\n" + + " \"table\": \"accounts\",\n" + + " \"payer\": \"eosio\",\n" + + " \"count\": 1\n" + + " }\n" + + " ],\n" + + " \"more\": \"eosio.ram\"\n" + + "}"; + + public static final String GET_CODE_REQUEST = "{\n" + + "\"account_name\" : \"eosio.token\"\n" + + "}"; + + public static final String GET_CODE_RESPONSE = "{\n" + + " \"code\": 500,\n" + + " \"message\": \"Internal Service Error\",\n" + + " \"error\": {\n" + + " \"code\": 3100008,\n" + + " \"name\": \"unsupported_feature\",\n" + + " \"what\": \"Feature is currently unsupported\",\n" + + " \"details\": [\n" + + " {\n" + + " \"message\": \"Returning WAST from get_code is no longer supported\",\n" + + " \"file\": \"chain_plugin.cpp\",\n" + + " \"line_number\": 1682,\n" + + " \"method\": \"get_code\"\n" + + " }\n" + + " ]\n" + + " }\n" + + "}"; + + public static final String GET_ACTIONS_REQUEST = "{\n" + + "\t\"pos\": 100,\n" + + "\t\"offset\": 50,\n" + + "\t\"account_name\" : \"eosio.token\"\n" + + "}"; + + public static final String GET_ACTIONS_RESPONSE = "{\n" + + " \"actions\": [],\n" + + " \"last_irreversible_block\": 34394836\n" + + "}"; + + public static final String GET_TRANSACTION_REQUEST = "{\n" + + "\t\"id\": \"transaction id\",\n" + + "\t\t\"block_num_hint\": 49420058\n" + + "}"; + + public static final String GET_TRANSACTION_RESPONSE = "{\n" + + " \"id\": \"transaction id\",\n" + + " \"trx\": {\n" + + " \"receipt\": {\n" + + " \"status\": \"executed\",\n" + + " \"cpu_usage_us\": 112,\n" + + " \"net_usage_words\": 0,\n" + + " \"trx\": [\n" + + " 0,\n" + + " \"transaction id\"\n" + + " ]\n" + + " }\n" + + " },\n" + + " \"block_time\": \"2019-03-25T06:08:05.000\",\n" + + " \"block_num\": 49420058,\n" + + " \"last_irreversible_block\": 53153351,\n" + + " \"traces\": [\n" + + " {\n" + + " \"receipt\": {\n" + + " \"receiver\": \"receiver1\",\n" + + " \"act_digest\": \"digest\",\n" + + " \"global_sequence\": \"5768776417\",\n" + + " \"recv_sequence\": 142,\n" + + " \"auth_sequence\": [\n" + + " [\n" + + " \"receiver2\",\n" + + " 2366\n" + + " ]\n" + + " ],\n" + + " \"code_sequence\": 2,\n" + + " \"abi_sequence\": 2\n" + + " },\n" + + " \"act\": {\n" + + " \"account\": \"eosio.token\",\n" + + " \"name\": \"transfer\",\n" + + " \"authorization\": [\n" + + " {\n" + + " \"actor\": \"receiver2\",\n" + + " \"permission\": \"active\"\n" + + " }\n" + + " ],\n" + + " \"data\": {\n" + + " \"from\": \"receiver2\",\n" + + " \"to\": \"receiver1\",\n" + + " \"quantity\": \"330.0000 EOS\",\n" + + " \"memo\": \"2018-3 payroll\"\n" + + " },\n" + + " \"hex_data\": \"hex data\"\n" + + " },\n" + + " \"context_free\": false,\n" + + " \"elapsed\": 6,\n" + + " \"console\": \"\",\n" + + " \"trx_id\": \"transaction id\",\n" + + " \"block_num\": 49420058,\n" + + " \"block_time\": \"2019-03-25T06:08:05.000\",\n" + + " \"producer_block_id\": \"block id\",\n" + + " \"account_ram_deltas\": [],\n" + + " \"except\": null,\n" + + " \"inline_traces\": []\n" + + " }\n" + + " ]\n" + + "}"; + + public static final String GET_KEY_ACCOUNTS_REQUEST = "{\n"+ + "\t\"public_key\": \"EOS public key\"\n"+ + "}"; + + public static final String GET_KEY_ACCOUNTS_RESPONSE = "{\n" + + " \"account_names\": [\n" + + " \"test_account\"\n" + + " ]\n" + + "}"; + + public static final String GET_CONTROLLED_ACCOUNTS_REQUEST = "{\n" + + "\t\"controlling_account\": \"test_account\"\n" + + "}"; + + public static final String GET_CONTROLLED_ACCOUNTS_RESPONSE = "{\n" + + " \"controlled_accounts\": []\n" + + "}"; +} + diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..f6b961f Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..e6378d8 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Thu May 09 11:17:39 EDT 2019 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..cccdd3d --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..e95643d --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/img/java-logo.png b/img/java-logo.png new file mode 100644 index 0000000..dec305f Binary files /dev/null and b/img/java-logo.png differ diff --git a/pipeline.yml b/pipeline.yml new file mode 100644 index 0000000..597c439 --- /dev/null +++ b/pipeline.yml @@ -0,0 +1,21 @@ +steps: + + - command: | + bash .scripts/artifactory.sh + gradle assemble artifactoryPublish + label: "Build Library" + agents: + - "queue=automation-android-builder-fleet" + + - command: | + bash .scripts/artifactory.sh + gradle test + label: "Run Tests" + agents: + - "queue=automation-android-builder-fleet" + - wait + + - command: "echo 'Success!!'" + label: ":trophy: Success" + agents: + - "queue=automation-android-builder-fleet" diff --git a/scripts/deploy-artifactory.sh b/scripts/deploy-artifactory.sh new file mode 100755 index 0000000..ceaacb5 --- /dev/null +++ b/scripts/deploy-artifactory.sh @@ -0,0 +1,5 @@ +DEST_REPO=$1 && \ +echo "publishing to $DEST_REPO on Artifactory" && \ +cat gradle.properties && \ +./gradlew properties && \ +./gradlew clean artifactoryPublish -Partifactory_repo=$DEST_REPO \ No newline at end of file diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..83e0ac1 --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include ':eosiojavarpcprovider' \ No newline at end of file