diff --git a/CHANGELOG.md b/CHANGELOG.md index b745eb23b..213315ac8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,22 @@ As this project is pre 1.0, breaking changes may happen for minor version bumps. A breaking change will get clearly notified in this log. +## 0.32.0 (Pending) + +* Update XDR definitions and auto-generated classes to support upcoming protocol 19 release ([#416](https://github.com/stellar/java-stellar-sdk/pull/416)). +* Extend StrKey implementation to handle [CAP 40 Payload Signer](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0040.md). +* Extended Transaction submission settings, additional new Preconditions can be added now, refer to [CAP 21 Transaction Preconditions](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0021.md). + +### Breaking changes + +* org.stellar.sdk.Transaction.Builder + * deprecated `addTimeBounds()` use `addPreconditions()` instead + * deprecated `setTimeout()` use `addPreconditions()` instead + * deprecated `Transaction.Builder` use TransactionBuilder instead +* org.stellar.sdk.Transaction + * `getSignatures()` returns an ImmutableList of signatures, do NOT add signatures to the collection returned. + use `addSignature(DecoratedSignature signature)` instead. + ## 0.31.0 * Fixed NPE on TrustlineCreatedEffectResponse.getAsset() for liquidity pool asset type. diff --git a/build.gradle b/build.gradle index 6b46d6e8b..2217248a4 100644 --- a/build.gradle +++ b/build.gradle @@ -1,37 +1,50 @@ buildscript { - ext.okhttpclientVersion="3.11.0" - repositories { - jcenter() - } - dependencies { - classpath 'com.github.ben-manes:gradle-versions-plugin:0.20.0' - classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4' - } + ext.okhttpclientVersion= '3.11.0' } -apply plugin: "com.github.johnrengelman.shadow" // provides shading -apply plugin: 'java' -apply plugin: 'maven' // needed to add the install task for jitpack.io -apply plugin: 'com.github.ben-manes.versions' // gradle dependencyUpdates -Drevision=release -apply plugin: 'project-report' // gradle htmlDependencyReport +plugins { + id "io.freefair.lombok" version "6.4.1" + id "com.github.johnrengelman.shadow" version "7.1.2" + id "java" + id "com.github.ben-manes.versions" version "0.42.0" + id "project-report" + id "maven-publish" + id "java-library" +} sourceCompatibility = 1.6 -version = '0.31.0' +version = '0.32.0' group = 'stellar' +jar.enabled = false -jar { - manifest { - attributes 'Implementation-Title': 'stellar-sdk', - 'Implementation-Version': version +publishing { + publications { + sdkLibrary(MavenPublication) { publication -> + project.shadow.component(publication) + } } - archiveName 'stellar-sdk.jar' - duplicatesStrategy DuplicatesStrategy.EXCLUDE - from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } } -artifacts { - // make sure the non shaded jar is not - archives shadowJar +shadowJar { + manifest { + attributes ( + "Implementation-Title" : "stellar-sdk", + "Implementation-Version" : project.getVersion() + ) + } + duplicatesStrategy DuplicatesStrategy.EXCLUDE + archiveClassifier.set('') + archiveBaseName.set('stellar-sdk') + relocate 'com.','shadow.com.' + relocate 'net.','shadow.net.' + relocate 'javax.annotation', 'shadow.javax.annotation' + relocate 'org.apache','shadow.org.apache' + relocate 'org.jvnet','shadow.org.jvnet' + relocate 'org.codehaus','shadow.org.codehaus' + relocate 'org.threeten','shadow.org.threeten' + relocate 'org.checkerframework','shadow.org.checkerframework' + relocate 'okhttp3','shadow.okhttp3' + relocate 'okio','shadow.okio' } repositories { @@ -39,52 +52,22 @@ repositories { } dependencies { - compile "com.squareup.okhttp3:okhttp:${okhttpclientVersion}" - compile "com.squareup.okhttp3:okhttp-sse:${okhttpclientVersion}" - compile 'com.moandjiezana.toml:toml4j:0.7.2' + implementation "com.squareup.okhttp3:okhttp:${okhttpclientVersion}" + implementation "com.squareup.okhttp3:okhttp-sse:${okhttpclientVersion}" + implementation 'com.moandjiezana.toml:toml4j:0.7.2' // use the android version because we don't want java 8 stuff - compile 'com.google.guava:guava:26.0-android' - compile 'com.google.code.gson:gson:2.8.5' - compile 'commons-io:commons-io:2.6' - compile 'net.i2p.crypto:eddsa:0.3.0' - compile 'org.threeten:threetenbp:1.4.4' - - testCompile 'org.mockito:mockito-core:2.21.0' - testCompile "com.squareup.okhttp3:mockwebserver:${okhttpclientVersion}" - testCompile 'junit:junit:4.12' - testCompile 'javax.xml.bind:jaxb-api:2.3.0' -} + implementation 'com.google.guava:guava:26.0-android' + implementation 'com.google.code.gson:gson:2.8.5' + implementation 'commons-io:commons-io:2.6' + implementation 'net.i2p.crypto:eddsa:0.3.0' + implementation 'org.threeten:threetenbp:1.4.4' -project.configurations.compile -jar.enabled = false - -// make sure the install task creates the shadowjar; this is called by jitpack.ios -install.dependsOn(shadowJar); - -// we need this so we can get to the installer and deployer below so we can remove the dependencies -uploadArchives { - repositories { - mavenDeployer { - } - } + testImplementation 'org.mockito:mockito-core:2.21.0' + testImplementation "com.squareup.okhttp3:mockwebserver:${okhttpclientVersion}" + testImplementation 'junit:junit:4.12' + testImplementation 'javax.xml.bind:jaxb-api:2.3.0' + testImplementation group: 'org.junit.vintage', name: 'junit-vintage-engine', version: '4.12.1' } - -def installer = install.repositories.mavenInstaller -def deployer = uploadArchives.repositories.mavenDeployer -[installer, deployer]*.pom*.whenConfigured {pom -> - // force pom dependencies to be empty because we are shading everything - pom.dependencies = [] -} - -shadowJar { - archiveName 'stellar-sdk.jar' - relocate 'com.','shadow.com.' - relocate 'net.','shadow.net.' - relocate 'javax.annotation', 'shadow.javax.annotation' - relocate 'org.apache','shadow.org.apache' - relocate 'org.jvnet','shadow.org.jvnet' - relocate 'org.codehaus','shadow.org.codehaus' - relocate 'org.checkerframework','shadow.org.checkerframework' - relocate 'okhttp3','shadow.okhttp3' - relocate 'okio','shadow.okio' +tasks.named('test') { task -> + useJUnitPlatform() } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 29953ea14..41d9927a4 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index e0b3fb8d7..00e33edef 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index cccdd3d51..1b6c78733 100755 --- a/gradlew +++ b/gradlew @@ -1,78 +1,129 @@ -#!/usr/bin/env sh +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ############################################################################## -## -## Gradle start up script for UN*X -## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# ############################################################################## # 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 +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${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="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # 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 - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | 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" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -81,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + 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 @@ -89,84 +140,95 @@ 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 +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac 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 +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# 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\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=$((i+1)) + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg 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 +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index e95643d6a..ac1b06f93 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,3 +1,19 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @@ -13,15 +29,18 @@ if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @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= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @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 +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,28 +64,14 @@ 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% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/readme.md b/readme.md index 2cb0a606b..a1a2c1202 100644 --- a/readme.md +++ b/readme.md @@ -38,3 +38,9 @@ For information on how to contribute, please refer to our [contribution guide](h ## License java-stellar-sdk is licensed under an Apache-2.0 license. See the [LICENSE](https://github.com/stellar/java-stellar-sdk/blob/master/LICENSE) file for details. + +## xdr to jave code generation +All the java source files in org.stellar.sdk.xdr package are generated using the `xdrgen` command from the [stellar/xdrgen](https://github.com/stellar/xdrgen) +``` +xdrgen -o ./src/main/java/org/stellar/sdk/xdr -l java -n org.stellar.sdk.xdr ./xdr/Stellar-types.x ./xdr/Stellar-SCP.x ./xdr/Stellar-overlay.x ./xdr/Stellar-ledger-entries.x ./xdr/Stellar-ledger.x ./xdr/Stellar-transaction.x +``` \ No newline at end of file diff --git a/src/main/java/org/stellar/sdk/AbstractTransaction.java b/src/main/java/org/stellar/sdk/AbstractTransaction.java index 99de3c7cb..500930be0 100644 --- a/src/main/java/org/stellar/sdk/AbstractTransaction.java +++ b/src/main/java/org/stellar/sdk/AbstractTransaction.java @@ -1,7 +1,14 @@ package org.stellar.sdk; +import com.google.common.collect.ImmutableList; import com.google.common.io.BaseEncoding; -import org.stellar.sdk.xdr.*; +import org.stellar.sdk.xdr.DecoratedSignature; +import org.stellar.sdk.xdr.Hash; +import org.stellar.sdk.xdr.SignatureHint; +import org.stellar.sdk.xdr.TransactionEnvelope; +import org.stellar.sdk.xdr.TransactionSignaturePayload; +import org.stellar.sdk.xdr.XdrDataInputStream; +import org.stellar.sdk.xdr.XdrDataOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -75,14 +82,34 @@ public String hashHex() { */ public abstract byte[] signatureBase(); + /** + * Gets the Network string for this transaction. + * + * @return the Network string + */ public Network getNetwork() { return mNetwork; } + /** + * Gets read only list(immutable) of the signatures on transaction. + * + * @return immutable list of signatures + */ public List getSignatures() { - return mSignatures; + return ImmutableList.copyOf(mSignatures); } + /** + * Adds an additional signature to the transaction's existing list of signatures. + * + * @param signature the signature to add + */ + public void addSignature(DecoratedSignature signature) { + mSignatures.add(signature); + } + + public abstract TransactionEnvelope toEnvelopeXdr(); /** diff --git a/src/main/java/org/stellar/sdk/Account.java b/src/main/java/org/stellar/sdk/Account.java index 1ab4531b3..9e399cbf2 100644 --- a/src/main/java/org/stellar/sdk/Account.java +++ b/src/main/java/org/stellar/sdk/Account.java @@ -7,7 +7,7 @@ /** * Represents an account in Stellar network with it's sequence number. * Account object is required to build a {@link Transaction}. - * @see org.stellar.sdk.Transaction.Builder + * @see TransactionBuilder */ public class Account implements TransactionBuilderAccount { private final String mAccountId; @@ -38,6 +38,11 @@ public Long getSequenceNumber() { return mSequenceNumber; } + @Override + public void setSequenceNumber(long seqNum) { + mSequenceNumber = seqNum; + } + @Override public Long getIncrementedSequenceNumber() { return mSequenceNumber + 1; diff --git a/src/main/java/org/stellar/sdk/FeeBumpTransaction.java b/src/main/java/org/stellar/sdk/FeeBumpTransaction.java index afc048c02..0720cbc21 100644 --- a/src/main/java/org/stellar/sdk/FeeBumpTransaction.java +++ b/src/main/java/org/stellar/sdk/FeeBumpTransaction.java @@ -2,7 +2,12 @@ import com.google.common.base.Objects; import com.google.common.collect.Lists; -import org.stellar.sdk.xdr.*; +import org.stellar.sdk.xdr.DecoratedSignature; +import org.stellar.sdk.xdr.EnvelopeType; +import org.stellar.sdk.xdr.FeeBumpTransactionEnvelope; +import org.stellar.sdk.xdr.Int64; +import org.stellar.sdk.xdr.TransactionEnvelope; +import org.stellar.sdk.xdr.TransactionSignaturePayload; import java.util.Arrays; @@ -111,23 +116,20 @@ public static class Builder { * Construct a new fee bump transaction builder. * * @param accountConverter The AccountConverter which will be used to encode the fee account. - * @param inner The inner transaction which will be fee bumped. + * @param inner The inner transaction which will be fee bumped. read-only, the */ - public Builder(AccountConverter accountConverter, Transaction inner) { - inner = checkNotNull(inner, "inner cannot be null"); + public Builder(AccountConverter accountConverter, final Transaction inner) { + checkNotNull(inner, "inner cannot be null"); EnvelopeType txType = inner.toEnvelopeXdr().getDiscriminant(); this.mAccountConverter = checkNotNull(accountConverter, "accountConverter cannot be null"); if (inner.toEnvelopeXdr().getDiscriminant() == EnvelopeType.ENVELOPE_TYPE_TX_V0) { - this.mInner = new Transaction( - inner.accountConverter, - inner.getSourceAccount(), - inner.getFee(), - inner.getSequenceNumber(), - inner.getOperations(), - inner.getMemo(), - inner.getTimeBounds(), - inner.getNetwork() - ); + this.mInner = new TransactionBuilder(inner.accountConverter, new Account(inner.getSourceAccount(), inner.getSequenceNumber() - 1), inner.getNetwork()) + .setBaseFee((int)inner.getFee()) + .addOperations(Arrays.asList(inner.getOperations())) + .addMemo(inner.getMemo()) + .addPreconditions(new TransactionPreconditions.TransactionPreconditionsBuilder().timeBounds(inner.getTimeBounds()).build()) + .build(); + this.mInner.mSignatures = Lists.newArrayList(inner.mSignatures); } else { this.mInner = inner; diff --git a/src/main/java/org/stellar/sdk/KeyPair.java b/src/main/java/org/stellar/sdk/KeyPair.java index 40ff0bfb5..0696eadb0 100644 --- a/src/main/java/org/stellar/sdk/KeyPair.java +++ b/src/main/java/org/stellar/sdk/KeyPair.java @@ -9,8 +9,14 @@ import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable; import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec; import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec; - -import org.stellar.sdk.xdr.*; +import org.stellar.sdk.xdr.DecoratedSignature; +import org.stellar.sdk.xdr.PublicKey; +import org.stellar.sdk.xdr.PublicKeyType; +import org.stellar.sdk.xdr.SignatureHint; +import org.stellar.sdk.xdr.SignerKey; +import org.stellar.sdk.xdr.SignerKeyType; +import org.stellar.sdk.xdr.Uint256; +import org.stellar.sdk.xdr.XdrDataOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -21,6 +27,7 @@ import java.util.Arrays; import static com.google.common.base.Preconditions.checkNotNull; +import static java.lang.System.arraycopy; /** * Holds a Stellar keypair. @@ -227,7 +234,9 @@ public byte[] sign(byte[] data) { /** * Sign the provided data with the keypair's private key and returns {@link DecoratedSignature}. - * @param data + * + * @param data the data to sign + * @return DecoratedSignature */ public DecoratedSignature signDecorated(byte[] data) { byte[] signatureBytes = this.sign(data); @@ -241,6 +250,34 @@ public DecoratedSignature signDecorated(byte[] data) { return decoratedSignature; } + /** + * Sign the provided payload data for payload signer where the input is the data being signed. + * Per the + * {@link DecoratedSignature}. + * + * @param signerPayload the payload signers raw data to sign + * @return DecoratedSignature + */ + public DecoratedSignature signPayloadDecorated(byte[] signerPayload) { + DecoratedSignature payloadSignature = signDecorated(signerPayload); + + byte[] hint = new byte[4]; + + // copy the last four bytes of the payload into the new hint + if (signerPayload.length >= hint.length) { + arraycopy(signerPayload, signerPayload.length - hint.length, hint, 0, hint.length); + } else { + arraycopy(signerPayload, 0, hint, 0, signerPayload.length); + } + + //XOR the new hint with this keypair's public key hint + for (int i = 0; i < hint.length; i++) { + hint[i] ^= payloadSignature.getHint().getSignatureHint()[i]; + } + payloadSignature.getHint().setSignatureHint(hint); + return payloadSignature; + } + /** * Verify the provided data and signature match this keypair's public key. * @param data The data that was signed. diff --git a/src/main/java/org/stellar/sdk/LedgerBounds.java b/src/main/java/org/stellar/sdk/LedgerBounds.java new file mode 100644 index 000000000..9fb891458 --- /dev/null +++ b/src/main/java/org/stellar/sdk/LedgerBounds.java @@ -0,0 +1,26 @@ +package org.stellar.sdk; + +import lombok.Value; +import org.stellar.sdk.xdr.Uint32; + +@Value +@lombok.Builder +/** + * LedgerBounds are Preconditions of a transaction per CAP-21 + */ +public class LedgerBounds { + int minLedger; + int maxLedger; + + public static LedgerBounds fromXdr(org.stellar.sdk.xdr.LedgerBounds xdrLedgerBounds) { + return new LedgerBoundsBuilder() + .minLedger(xdrLedgerBounds.getMinLedger().getUint32()) + .maxLedger(xdrLedgerBounds.getMaxLedger().getUint32()).build(); + } + + public org.stellar.sdk.xdr.LedgerBounds toXdr() { + return new org.stellar.sdk.xdr.LedgerBounds.Builder() + .maxLedger(new Uint32(maxLedger)) + .minLedger(new Uint32(minLedger)).build(); + } +} diff --git a/src/main/java/org/stellar/sdk/Predicate.java b/src/main/java/org/stellar/sdk/Predicate.java index 045fc1eec..892aec016 100644 --- a/src/main/java/org/stellar/sdk/Predicate.java +++ b/src/main/java/org/stellar/sdk/Predicate.java @@ -4,7 +4,10 @@ import com.google.common.collect.Lists; import org.stellar.sdk.xdr.ClaimPredicate; import org.stellar.sdk.xdr.ClaimPredicateType; +import org.stellar.sdk.xdr.Duration; import org.stellar.sdk.xdr.Int64; +import org.stellar.sdk.xdr.TimePoint; +import org.stellar.sdk.xdr.Uint64; import org.threeten.bp.Instant; import java.util.List; @@ -177,19 +180,25 @@ public ClaimPredicate toXdr() { } } + /** + * Represents a predicate based on a maximum date and time. + */ public static class AbsBefore extends Predicate { - private final long epochSeconds; + private final TimePoint timePoint; - public AbsBefore(long epochSeconds) { - this.epochSeconds = epochSeconds; + public AbsBefore(TimePoint timePoint) { + this.timePoint = timePoint; } + public AbsBefore(long epochSeconds) { + this(new TimePoint(new Uint64(epochSeconds))); + } public long getTimestampSeconds() { - return epochSeconds; + return timePoint.getTimePoint().getUint64(); } public Instant getDate() { - return Instant.ofEpochSecond(epochSeconds); + return Instant.ofEpochSecond(timePoint.getTimePoint().getUint64()); } @Override @@ -197,34 +206,39 @@ public boolean equals(Object o) { if (this == o) { return true; } - return (getClass() == o.getClass()) && Objects.equal(epochSeconds, ((AbsBefore)o).epochSeconds); + return (getClass() == o.getClass()) && Objects.equal(timePoint, ((AbsBefore)o).timePoint); } @Override public int hashCode() { - return Objects.hashCode(epochSeconds); + return Objects.hashCode(timePoint); } @Override public ClaimPredicate toXdr() { org.stellar.sdk.xdr.ClaimPredicate xdr = new org.stellar.sdk.xdr.ClaimPredicate(); xdr.setDiscriminant(ClaimPredicateType.CLAIM_PREDICATE_BEFORE_ABSOLUTE_TIME); - Int64 t = new Int64(); - t.setInt64(epochSeconds); - xdr.setAbsBefore(t); + xdr.setAbsBefore(new Int64(timePoint.getTimePoint().getUint64())); return xdr; } } + /** + * Represents predicate based on maximum length of time + */ public static class RelBefore extends Predicate { - private final long secondsSinceClose; + private final Duration duration; + + public RelBefore(Duration secondsSinceClose) { + this.duration = secondsSinceClose; + } public RelBefore(long secondsSinceClose) { - this.secondsSinceClose = secondsSinceClose; + this(new Duration(new Uint64(secondsSinceClose))); } public long getSecondsSinceClose() { - return secondsSinceClose; + return duration.getDuration().getUint64(); } @Override @@ -232,21 +246,19 @@ public boolean equals(Object o) { if (this == o) { return true; } - return (getClass() == o.getClass()) && Objects.equal(secondsSinceClose, ((RelBefore)o).secondsSinceClose); + return (getClass() == o.getClass()) && Objects.equal(duration, ((RelBefore)o).duration); } @Override public int hashCode() { - return Objects.hashCode(secondsSinceClose); + return Objects.hashCode(duration); } @Override public ClaimPredicate toXdr() { org.stellar.sdk.xdr.ClaimPredicate xdr = new org.stellar.sdk.xdr.ClaimPredicate(); xdr.setDiscriminant(ClaimPredicateType.CLAIM_PREDICATE_BEFORE_RELATIVE_TIME); - Int64 t = new Int64(); - t.setInt64(secondsSinceClose); - xdr.setRelBefore(t); + xdr.setRelBefore(new Int64(duration.getDuration().getUint64())); return xdr; } } diff --git a/src/main/java/org/stellar/sdk/Sep10Challenge.java b/src/main/java/org/stellar/sdk/Sep10Challenge.java index 50f97e2f3..32ce27085 100644 --- a/src/main/java/org/stellar/sdk/Sep10Challenge.java +++ b/src/main/java/org/stellar/sdk/Sep10Challenge.java @@ -11,7 +11,12 @@ import java.io.IOException; import java.security.SecureRandom; -import java.util.*; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; public class Sep10Challenge { static final int GRACE_PERIOD_SECONDS = 5 * 60; @@ -88,7 +93,7 @@ public static Transaction newChallenge( .setSourceAccount(sourceAccount.getAccountId()) .build(); - Transaction.Builder builder = new Transaction.Builder(AccountConverter.enableMuxed(), sourceAccount, network) + TransactionBuilder builder = new TransactionBuilder(AccountConverter.enableMuxed(), sourceAccount, network) .addTimeBounds(timebounds) .setBaseFee(100) .addOperation(domainNameOperation) @@ -157,11 +162,6 @@ public static ChallengeTransaction readChallengeTransaction(String challengeXdr, throw new InvalidSep10ChallengeException("The transaction sequence number should be zero."); } - // verify that transaction has time bounds set, and that current time is between the minimum and maximum bounds. - if (transaction.getTimeBounds() == null) { - throw new InvalidSep10ChallengeException("Transaction requires timebounds."); - } - long maxTime = transaction.getTimeBounds().getMaxTime(); long minTime = transaction.getTimeBounds().getMinTime(); if (maxTime == 0L) { diff --git a/src/main/java/org/stellar/sdk/SignedPayloadSigner.java b/src/main/java/org/stellar/sdk/SignedPayloadSigner.java new file mode 100644 index 000000000..b5fcc4035 --- /dev/null +++ b/src/main/java/org/stellar/sdk/SignedPayloadSigner.java @@ -0,0 +1,68 @@ +package org.stellar.sdk; + +import org.stellar.sdk.xdr.AccountID; +import org.stellar.sdk.xdr.PublicKey; +import org.stellar.sdk.xdr.PublicKeyType; +import org.stellar.sdk.xdr.Uint256; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * Data model for the signed payload signer + */ +public class SignedPayloadSigner { + public static final int SIGNED_PAYLOAD_MAX_PAYLOAD_LENGTH = 64; + + private AccountID signerAccountId; + private byte[] payload; + + /** + * constructor + * + * @param signerAccountId - the xdr AccountID + * @param payload - the raw payload for a signed payload + */ + public SignedPayloadSigner(AccountID signerAccountId, byte[] payload) { + checkNotNull(payload, "payload cannot be null"); + checkNotNull(signerAccountId, "accountId cannot be null"); + if (payload.length > SIGNED_PAYLOAD_MAX_PAYLOAD_LENGTH) { + throw new IllegalArgumentException("invalid payload length, must be less than " + SIGNED_PAYLOAD_MAX_PAYLOAD_LENGTH); + } + if (signerAccountId.getAccountID().getDiscriminant() == null || + !signerAccountId.getAccountID().getDiscriminant().equals(PublicKeyType.PUBLIC_KEY_TYPE_ED25519)) { + throw new IllegalArgumentException("invalid payload signer, only ED25519 public key accounts are supported currently"); + } + this.signerAccountId = checkNotNull(signerAccountId); + this.payload = checkNotNull(payload); + } + + /** + * constructor + * + * @param signerED25519PublicKey raw bytes of a ED25519 public key for the signer account + * @param payload the raw payload for a signed payload + */ + public SignedPayloadSigner(byte[] signerED25519PublicKey, byte[] payload ) { + this(new AccountID( + new PublicKey.Builder() + .discriminant(PublicKeyType.PUBLIC_KEY_TYPE_ED25519) + .ed25519(new Uint256(signerED25519PublicKey)).build()), payload); + } + + /** + * get the account that represents the signed payload signer + * @return stellar account + */ + public AccountID getSignerAccountId() { + return signerAccountId; + } + + /** + * get the payload that signatures are produced from. + * @see + * @return + */ + public byte[] getPayload() { + return payload; + } +} diff --git a/src/main/java/org/stellar/sdk/Signer.java b/src/main/java/org/stellar/sdk/Signer.java index 8f1e91ecf..b5fd69b21 100644 --- a/src/main/java/org/stellar/sdk/Signer.java +++ b/src/main/java/org/stellar/sdk/Signer.java @@ -4,6 +4,7 @@ import org.stellar.sdk.xdr.SignerKeyType; import org.stellar.sdk.xdr.Uint256; +import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; /** @@ -72,6 +73,25 @@ public static SignerKey preAuthTx(byte[] hash) { return signerKey; } + /** + * Create SignerKey {@link org.stellar.sdk.xdr.SignerKey} from {@link org.stellar.sdk.SignedPayloadSigner} + * + * @param signedPayloadSigner - signed payload values + * @return org.stellar.sdk.xdr.SignerKey + */ + public static SignerKey signedPayload(SignedPayloadSigner signedPayloadSigner) { + + SignerKey signerKey = new SignerKey(); + SignerKey.SignerKeyEd25519SignedPayload payloadSigner = new SignerKey.SignerKeyEd25519SignedPayload(); + payloadSigner.setPayload(signedPayloadSigner.getPayload()); + payloadSigner.setEd25519(signedPayloadSigner.getSignerAccountId().getAccountID().getEd25519()); + + signerKey.setDiscriminant(SignerKeyType.SIGNER_KEY_TYPE_ED25519_SIGNED_PAYLOAD); + signerKey.setEd25519SignedPayload(payloadSigner); + + return signerKey; + } + private static Uint256 createUint256(byte[] hash) { if (hash.length != 32) { throw new RuntimeException("hash must be 32 bytes long"); diff --git a/src/main/java/org/stellar/sdk/StrKey.java b/src/main/java/org/stellar/sdk/StrKey.java index 438814718..0342cac2e 100644 --- a/src/main/java/org/stellar/sdk/StrKey.java +++ b/src/main/java/org/stellar/sdk/StrKey.java @@ -1,12 +1,25 @@ package org.stellar.sdk; -import com.google.common.io.BaseEncoding; import com.google.common.base.Optional; +import com.google.common.io.BaseEncoding; import com.google.common.primitives.Bytes; import com.google.common.primitives.Longs; -import org.stellar.sdk.xdr.*; - -import java.io.*; +import org.stellar.sdk.xdr.AccountID; +import org.stellar.sdk.xdr.CryptoKeyType; +import org.stellar.sdk.xdr.MuxedAccount; +import org.stellar.sdk.xdr.PublicKey; +import org.stellar.sdk.xdr.PublicKeyType; +import org.stellar.sdk.xdr.SignerKey; +import org.stellar.sdk.xdr.Uint256; +import org.stellar.sdk.xdr.Uint64; +import org.stellar.sdk.xdr.XdrDataInputStream; +import org.stellar.sdk.xdr.XdrDataOutputStream; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.CharArrayWriter; +import java.io.IOException; +import java.io.OutputStream; import java.util.Arrays; class StrKey { @@ -18,7 +31,8 @@ public enum VersionByte { MUXED((byte)(12 << 3)), // M SEED((byte)(18 << 3)), // S PRE_AUTH_TX((byte)(19 << 3)), // T - SHA256_HASH((byte)(23 << 3)); // X + SHA256_HASH((byte)(23 << 3)), // X + SIGNED_PAYLOAD((byte)(15 << 3)); // P private final byte value; VersionByte(byte value) { this.value = value; @@ -49,6 +63,22 @@ public static String encodeStellarAccountId(AccountID accountID) { return String.valueOf(encoded); } + public static String encodeSignedPayload(SignedPayloadSigner signedPayloadSigner) { + try { + SignerKey.SignerKeyEd25519SignedPayload xdrPayloadSigner = new SignerKey.SignerKeyEd25519SignedPayload(); + xdrPayloadSigner.setPayload(signedPayloadSigner.getPayload()); + xdrPayloadSigner.setEd25519(signedPayloadSigner.getSignerAccountId().getAccountID().getEd25519()); + + ByteArrayOutputStream record = new ByteArrayOutputStream(); + xdrPayloadSigner.encode(new XdrDataOutputStream(record)); + + char[] encoded = encodeCheck(VersionByte.SIGNED_PAYLOAD, record.toByteArray()); + return String.valueOf(encoded); + } catch (Exception ex) { + throw new FormatException(ex.getMessage()); + } + } + public static String encodeStellarMuxedAccount(MuxedAccount muxedAccount) { switch (muxedAccount.getDiscriminant()) { case KEY_TYPE_MUXED_ED25519: @@ -154,6 +184,20 @@ public static byte[] decodeStellarSecretSeed(char[] data) { return decodeCheck(VersionByte.SEED, data); } + public static SignedPayloadSigner decodeSignedPayload(char[] data) { + try { + byte[] signedPayloadRaw = decodeCheck(VersionByte.SIGNED_PAYLOAD, data); + + SignerKey.SignerKeyEd25519SignedPayload xdrPayloadSigner = SignerKey.SignerKeyEd25519SignedPayload.decode( + new XdrDataInputStream(new ByteArrayInputStream(signedPayloadRaw)) + ); + + return new SignedPayloadSigner( xdrPayloadSigner.getEd25519().getUint256(), xdrPayloadSigner.getPayload()); + } catch (Exception ex) { + throw new FormatException(ex.getMessage()); + } + } + public static String encodePreAuthTx(byte[] data) { char[] encoded = encodeCheck(VersionByte.PRE_AUTH_TX, data); return String.valueOf(encoded); @@ -177,20 +221,20 @@ protected static char[] encodeCheck(VersionByte versionByte, byte[] data) { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); outputStream.write(versionByte.getValue()); outputStream.write(data); - byte payload[] = outputStream.toByteArray(); - byte checksum[] = StrKey.calculateChecksum(payload); + byte[] payload = outputStream.toByteArray(); + byte[] checksum = StrKey.calculateChecksum(payload); outputStream.write(checksum); - byte unencoded[] = outputStream.toByteArray(); + byte[] unencoded = outputStream.toByteArray(); if (VersionByte.SEED != versionByte) { - return StrKey.base32Encoding.encode(unencoded).toCharArray(); + return base32Encoding.encode(unencoded).toCharArray(); } // Why not use base32Encoding.encode here? // We don't want secret seed to be stored as String in memory because of security reasons. It's impossible // to erase it from memory when we want it to be erased (ASAP). CharArrayWriter charArrayWriter = new CharArrayWriter(unencoded.length); - OutputStream charOutputStream = StrKey.base32Encoding.encodingStream(charArrayWriter); + OutputStream charOutputStream = base32Encoding.encodingStream(charArrayWriter); charOutputStream.write(unencoded); char[] charsEncoded = charArrayWriter.toCharArray(); @@ -242,7 +286,7 @@ protected static byte[] decodeCheck(VersionByte versionByte, char[] encoded) { } } - byte[] decoded = StrKey.base32Encoding.decode(java.nio.CharBuffer.wrap(encoded)); + byte[] decoded = base32Encoding.decode(java.nio.CharBuffer.wrap(encoded)); byte decodedVersionByte = decoded[0]; byte[] payload = Arrays.copyOfRange(decoded, 0, decoded.length-2); byte[] data = Arrays.copyOfRange(payload, 1, payload.length); diff --git a/src/main/java/org/stellar/sdk/TimeBounds.java b/src/main/java/org/stellar/sdk/TimeBounds.java index 0e037e80f..2d00a3175 100644 --- a/src/main/java/org/stellar/sdk/TimeBounds.java +++ b/src/main/java/org/stellar/sdk/TimeBounds.java @@ -25,7 +25,7 @@ public TimeBounds(long minTime, long maxTime) { throw new IllegalArgumentException("maxTime cannot be negative"); } - if (maxTime != 0 && minTime > maxTime) { + if (maxTime != TransactionPreconditions.TIMEOUT_INFINITE && minTime > maxTime) { throw new IllegalArgumentException("minTime must be >= maxTime"); } diff --git a/src/main/java/org/stellar/sdk/Transaction.java b/src/main/java/org/stellar/sdk/Transaction.java index fc90f502f..b7b7d2192 100644 --- a/src/main/java/org/stellar/sdk/Transaction.java +++ b/src/main/java/org/stellar/sdk/Transaction.java @@ -1,14 +1,25 @@ package org.stellar.sdk; import com.google.common.base.Objects; -import org.stellar.sdk.xdr.*; +import org.stellar.sdk.xdr.ClaimableBalanceID; +import org.stellar.sdk.xdr.ClaimableBalanceIDType; +import org.stellar.sdk.xdr.DecoratedSignature; +import org.stellar.sdk.xdr.EnvelopeType; +import org.stellar.sdk.xdr.Hash; +import org.stellar.sdk.xdr.Int64; +import org.stellar.sdk.xdr.OperationID; +import org.stellar.sdk.xdr.SequenceNumber; +import org.stellar.sdk.xdr.TransactionEnvelope; +import org.stellar.sdk.xdr.TransactionSignaturePayload; +import org.stellar.sdk.xdr.TransactionV0; +import org.stellar.sdk.xdr.TransactionV0Envelope; +import org.stellar.sdk.xdr.TransactionV1Envelope; +import org.stellar.sdk.xdr.Uint32; +import org.stellar.sdk.xdr.XdrDataOutputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; -import java.util.List; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; @@ -22,7 +33,7 @@ public class Transaction extends AbstractTransaction { private final long mSequenceNumber; private final Operation[] mOperations; private final Memo mMemo; - private final TimeBounds mTimeBounds; + private final TransactionPreconditions mPreconditions; private EnvelopeType envelopeType = EnvelopeType.ENVELOPE_TYPE_TX; Transaction( @@ -32,18 +43,17 @@ public class Transaction extends AbstractTransaction { long sequenceNumber, Operation[] operations, Memo memo, - TimeBounds timeBounds, + TransactionPreconditions preconditions, Network network ) { super(accountConverter, network); this.mSourceAccount = checkNotNull(sourceAccount, "sourceAccount cannot be null"); - this.mSequenceNumber = checkNotNull(sequenceNumber, "sequenceNumber cannot be null"); + this.mSequenceNumber = sequenceNumber; this.mOperations = checkNotNull(operations, "operations cannot be null"); checkArgument(operations.length > 0, "At least one operation required"); - + this.mPreconditions = preconditions; this.mFee = fee; this.mMemo = memo != null ? memo : Memo.none(); - this.mTimeBounds = timeBounds; } // setEnvelopeType is only used in tests which is why this method is package protected @@ -74,10 +84,21 @@ public Memo getMemo() { } /** - * @return TimeBounds, or null (representing no time restrictions) + * Get the pre-conditions for the transaction + * + * @return TransactionPreconditions + */ + public TransactionPreconditions getPreconditions() { + return mPreconditions; + } + + /** + * Gets the time bounds defined for the transaction. + * + * @return TimeBounds */ public TimeBounds getTimeBounds() { - return mTimeBounds; + return mPreconditions.getTimeBounds(); } /** @@ -157,7 +178,7 @@ private TransactionV0 toXdr() { transaction.setSourceAccountEd25519(StrKey.encodeToXDRAccountId(this.mSourceAccount).getAccountID().getEd25519()); transaction.setOperations(operations); transaction.setMemo(mMemo.toXdr()); - transaction.setTimeBounds(mTimeBounds == null ? null : mTimeBounds.toXdr()); + transaction.setTimeBounds(getTimeBounds() == null ? null : getTimeBounds().toXdr()); transaction.setExt(ext); return transaction; } @@ -181,14 +202,13 @@ private org.stellar.sdk.xdr.Transaction toV1Xdr(AccountConverter accountConverte org.stellar.sdk.xdr.Transaction.TransactionExt ext = new org.stellar.sdk.xdr.Transaction.TransactionExt(); ext.setDiscriminant(0); - org.stellar.sdk.xdr.Transaction v1Tx = new org.stellar.sdk.xdr.Transaction(); v1Tx.setFee(fee); v1Tx.setSeqNum(sequenceNumber); v1Tx.setSourceAccount(accountConverter.encode(mSourceAccount)); v1Tx.setOperations(operations); v1Tx.setMemo(mMemo.toXdr()); - v1Tx.setTimeBounds(mTimeBounds == null ? null : mTimeBounds.toXdr()); + v1Tx.setCond(mPreconditions.toXdr()); v1Tx.setExt(ext); return v1Tx; @@ -212,7 +232,7 @@ public static Transaction fromV0EnvelopeXdr(AccountConverter accountConverter, T mSequenceNumber, mOperations, mMemo, - mTimeBounds, + TransactionPreconditions.builder().timeBounds(mTimeBounds).build(), network ); transaction.setEnvelopeType(EnvelopeType.ENVELOPE_TYPE_TX_V0); @@ -230,7 +250,6 @@ public static Transaction fromV1EnvelopeXdr(AccountConverter accountConverter, T int mFee = envelope.getTx().getFee().getUint32(); Long mSequenceNumber = envelope.getTx().getSeqNum().getSequenceNumber().getInt64(); Memo mMemo = Memo.fromXdr(envelope.getTx().getMemo()); - TimeBounds mTimeBounds = TimeBounds.fromXdr(envelope.getTx().getTimeBounds()); Operation[] mOperations = new Operation[envelope.getTx().getOperations().length]; for (int i = 0; i < envelope.getTx().getOperations().length; i++) { @@ -244,7 +263,7 @@ public static Transaction fromV1EnvelopeXdr(AccountConverter accountConverter, T mSequenceNumber, mOperations, mMemo, - mTimeBounds, + TransactionPreconditions.fromXdr(envelope.getTx().getCond()), network ); @@ -285,172 +304,6 @@ public TransactionEnvelope toEnvelopeXdr() { return xdr; } - /** - * Builds a new Transaction object. - */ - public static class Builder { - private final TransactionBuilderAccount mSourceAccount; - private final AccountConverter mAccountConverter; - private Memo mMemo; - private TimeBounds mTimeBounds; - List mOperations; - private boolean timeoutSet; - private Integer mBaseFee; - private Network mNetwork; - - public static final long TIMEOUT_INFINITE = 0; - - /** - * Construct a new transaction builder. - * @param sourceAccount The source account for this transaction. This account is the account - * who will use a sequence number. When build() is called, the account object's sequence number - * will be incremented. - */ - public Builder(AccountConverter accountConverter, TransactionBuilderAccount sourceAccount, Network network) { - mAccountConverter = checkNotNull(accountConverter, "accountConverter cannot be null"); - mSourceAccount = checkNotNull(sourceAccount, "sourceAccount cannot be null"); - mOperations = Collections.synchronizedList(new ArrayList()); - mNetwork = checkNotNull(network, "Network cannot be null"); - } - - /** - * Construct a new transaction builder. - * @param sourceAccount The source account for this transaction. This account is the account - * who will use a sequence number. When build() is called, the account object's sequence number - * will be incremented. - */ - public Builder(TransactionBuilderAccount sourceAccount, Network network) { - this(AccountConverter.enableMuxed(), sourceAccount, network); - } - - public int getOperationsCount() { - return mOperations.size(); - } - - /** - * Adds a new operation to this transaction. - * @param operation - * @return Builder object so you can chain methods. - * @see Operation - */ - public Builder addOperation(Operation operation) { - checkNotNull(operation, "operation cannot be null"); - mOperations.add(operation); - return this; - } - - /** - * Adds a memo to this transaction. - * @param memo - * @return Builder object so you can chain methods. - * @see Memo - */ - public Builder addMemo(Memo memo) { - if (mMemo != null) { - throw new RuntimeException("Memo has been already added."); - } - checkNotNull(memo, "memo cannot be null"); - mMemo = memo; - return this; - } - - /** - * Adds a time-bounds to this transaction. - * @param timeBounds - * @return Builder object so you can chain methods. - * @see TimeBounds - */ - public Builder addTimeBounds(TimeBounds timeBounds) { - if (mTimeBounds != null) { - throw new RuntimeException("TimeBounds has been already added."); - } - checkNotNull(timeBounds, "timeBounds cannot be null"); - mTimeBounds = timeBounds; - return this; - } - - /** - * Because of the distributed nature of the Stellar network it is possible that the status of your transaction - * will be determined after a long time if the network is highly congested. - * If you want to be sure to receive the status of the transaction within a given period you should set the - * {@link TimeBounds} with maxTime on the transaction (this is what setTimeout does - * internally; if there's minTime set but no maxTime it will be added). - * Call to Builder.setTimeout is required if Transaction does not have max_time set. - * If you don't want to set timeout, use TIMEOUT_INFINITE. In general you should set - * TIMEOUT_INFINITE only in smart contracts. - * Please note that Horizon may still return 504 Gateway Timeout error, even for short timeouts. - * In such case you need to resubmit the same transaction again without making any changes to receive a status. - * This method is using the machine system time (UTC), make sure it is set correctly. - * @param timeout Timeout in seconds. - * @see TimeBounds - * @return - */ - public Builder setTimeout(long timeout) { - if (mTimeBounds != null && mTimeBounds.getMaxTime() > 0) { - throw new RuntimeException("TimeBounds.max_time has been already set - setting timeout would overwrite it."); - } - - if (timeout < 0) { - throw new RuntimeException("timeout cannot be negative"); - } - - timeoutSet = true; - if (timeout > 0) { - long timeoutTimestamp = System.currentTimeMillis() / 1000L + timeout; - if (mTimeBounds == null) { - mTimeBounds = new TimeBounds(0, timeoutTimestamp); - } else { - mTimeBounds = new TimeBounds(mTimeBounds.getMinTime(), timeoutTimestamp); - } - } - - return this; - } - - public Builder setBaseFee(int baseFee) { - if (baseFee < MIN_BASE_FEE) { - throw new IllegalArgumentException("baseFee cannot be smaller than the BASE_FEE (" + MIN_BASE_FEE + "): " + baseFee); - } - - this.mBaseFee = baseFee; - return this; - } - - /** - * Builds a transaction. It will increment sequence number of the source account. - */ - public Transaction build() { - // Ensure setTimeout called or maxTime is set - if ((mTimeBounds == null || mTimeBounds != null && mTimeBounds.getMaxTime() == 0) && !timeoutSet) { - throw new RuntimeException("TimeBounds has to be set or you must call setTimeout(TIMEOUT_INFINITE)."); - } - - if (mBaseFee == null) { - throw new RuntimeException("mBaseFee has to be set. you must call setBaseFee()."); - } - - if (mNetwork == null) { - throw new NoNetworkSelectedException(); - } - - Operation[] operations = new Operation[mOperations.size()]; - operations = mOperations.toArray(operations); - Transaction transaction = new Transaction( - mAccountConverter, - mSourceAccount.getAccountId(), - operations.length * mBaseFee, - mSourceAccount.getIncrementedSequenceNumber(), - operations, - mMemo, - mTimeBounds, - mNetwork - ); - // Increment sequence number when there were no exceptions when creating a transaction - mSourceAccount.incrementSequenceNumber(); - return transaction; - } - } - @Override public int hashCode() { return Objects.hashCode( @@ -460,7 +313,7 @@ public int hashCode() { this.mSequenceNumber, Arrays.hashCode(this.mOperations), this.mMemo, - this.mTimeBounds, + this.mPreconditions, this.mSignatures, this.mNetwork ); @@ -479,8 +332,24 @@ public boolean equals(Object object) { Objects.equal(this.mSequenceNumber, other.mSequenceNumber) && Arrays.equals(this.mOperations, other.mOperations) && Objects.equal(this.mMemo, other.mMemo) && - Objects.equal(this.mTimeBounds, other.mTimeBounds) && + Objects.equal(this.mPreconditions, other.mPreconditions) && Objects.equal(this.mNetwork, other.mNetwork) && Objects.equal(this.mSignatures, other.mSignatures); } + + /** + * Maintain backwards compatibility references to Transaction.Builder + * + * @deprecated will be removed in upcoming releases. Use TransactionBuilder instead. + * @see org.stellar.sdk.TransactionBuilder + */ + public static class Builder extends TransactionBuilder { + public Builder(AccountConverter accountConverter, TransactionBuilderAccount sourceAccount, Network network) { + super(accountConverter, sourceAccount, network); + } + + public Builder(TransactionBuilderAccount sourceAccount, Network network) { + super(sourceAccount, network); + } + } } diff --git a/src/main/java/org/stellar/sdk/TransactionBuilder.java b/src/main/java/org/stellar/sdk/TransactionBuilder.java new file mode 100644 index 000000000..7564a9749 --- /dev/null +++ b/src/main/java/org/stellar/sdk/TransactionBuilder.java @@ -0,0 +1,228 @@ +package org.stellar.sdk; + +import com.google.common.base.Function; +import org.stellar.sdk.TransactionPreconditions.TransactionPreconditionsBuilder; +import org.stellar.sdk.xdr.TimePoint; +import org.stellar.sdk.xdr.Uint64; + +import java.util.Collection; +import java.util.List; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.Lists.newArrayList; +import static org.stellar.sdk.TransactionPreconditions.TIMEOUT_INFINITE; + +/** + * Builds a new Transaction object. + */ +public class TransactionBuilder { + private final TransactionBuilderAccount mSourceAccount; + private final AccountConverter mAccountConverter; + private Memo mMemo; + private List mOperations; + private Integer mBaseFee; + private Network mNetwork; + private TransactionPreconditions mPreconditions; + + /** + * Construct a new transaction builder. + * + * @param accountConverter the account id formatter, choose to support muxed or not. + * @param sourceAccount the source account for this transaction. This account is the account + * who will use a sequence number. When build() is called, the account object's sequence number + * will be incremented. + * @param network the testnet or pubnet network to use + */ + public TransactionBuilder(AccountConverter accountConverter, TransactionBuilderAccount sourceAccount, Network network) { + mAccountConverter = checkNotNull(accountConverter, "accountConverter cannot be null"); + mSourceAccount = checkNotNull(sourceAccount, "sourceAccount cannot be null"); + mNetwork = checkNotNull(network, "Network cannot be null"); + mOperations = newArrayList(); + mPreconditions = TransactionPreconditions.builder().build(); + } + + /** + * Construct a new transaction builder. + * + * @param sourceAccount the source account for this transaction. This account is the account + * who will use a sequence number. When build() is called, the account object's sequence number + * will be incremented. + * @param network the testnet or pubnet network to use + */ + public TransactionBuilder(TransactionBuilderAccount sourceAccount, Network network) { + this(AccountConverter.enableMuxed(), sourceAccount, network); + } + + public int getOperationsCount() { + return mOperations.size(); + } + + /** + * Adds a new operation to this transaction. + * + * @param operation + * @return Builder object so you can chain methods. + * @see Operation + */ + public TransactionBuilder addOperation(Operation operation) { + checkNotNull(operation, "operation cannot be null"); + mOperations.add(operation); + return this; + } + + /** + * Adds operation to this transaction. + * + * @param operations list of operations + * @return Builder object so you can chain methods. + * @see Operation + */ + public TransactionBuilder addOperations(Collection operations) { + checkNotNull(operations, "operations cannot be null"); + mOperations.addAll(operations); + return this; + } + + /** + * Adds preconditions. + * For details of all preconditions on transaction refer to CAP-21 + * + * @param preconditions the tx PreConditions + * @return updated Builder object + */ + public TransactionBuilder addPreconditions(TransactionPreconditions preconditions) { + checkNotNull(preconditions, "preconditions cannot be null"); + this.mPreconditions = preconditions; + return this; + } + + /** + * Adds a memo to this transaction. + * + * @param memo + * @return Builder object so you can chain methods. + * @see Memo + */ + public TransactionBuilder addMemo(Memo memo) { + if (mMemo != null) { + throw new RuntimeException("Memo has been already added."); + } + checkNotNull(memo, "memo cannot be null"); + mMemo = memo; + return this; + } + + /** + * Adds a time-bounds to this transaction. + * + * @param timeBounds tx can be accepted within this time bound range + * @return Builder object so you can chain methods. + * @see TimeBounds + * @deprecated this method will be removed in upcoming releases, use addPreconditions() instead for more control over preconditions. + */ + public TransactionBuilder addTimeBounds(TimeBounds timeBounds) { + checkNotNull(timeBounds, "timeBounds cannot be null"); + if (mPreconditions.getTimeBounds() != null) { + throw new RuntimeException("TimeBounds already set."); + } + + mPreconditions = mPreconditions.toBuilder().timeBounds(timeBounds).build(); + return this; + } + + /** + * Because of the distributed nature of the Stellar network it is possible that the status of your transaction + * will be determined after a long time if the network is highly congested. + * If you want to be sure to receive the status of the transaction within a given period you should set the + * {@link TimeBounds} with maxTime on the transaction (this is what setTimeout does + * internally; if there's minTime set but no maxTime it will be added). + * Call to Builder.setTimeout is required if Transaction does not have max_time set. + * If you don't want to set timeout, use TIMEOUT_INFINITE. In general you should set + * TIMEOUT_INFINITE only in smart contracts. + * Please note that Horizon may still return 504 Gateway Timeout error, even for short timeouts. + * In such case you need to resubmit the same transaction again without making any changes to receive a status. + * This method is using the machine system time (UTC), make sure it is set correctly. + * + * @param timeout Timeout in seconds. + * @return updated Builder + * @see TimeBounds + * @deprecated this method will be removed in upcoming releases, use addPreconditions() with TimeBound + * set instead for more control over preconditions. + */ + public TransactionBuilder setTimeout(long timeout) { + if (mPreconditions.getTimeBounds() != null && mPreconditions.getTimeBounds().getMaxTime() != TIMEOUT_INFINITE) { + throw new RuntimeException("TimeBounds.max_time has been already set - setting timeout would overwrite it."); + } + + if (timeout < 0) { + throw new RuntimeException("timeout cannot be negative"); + } + + long timeoutTimestamp = timeout != TIMEOUT_INFINITE ? System.currentTimeMillis() / 1000L + timeout : TIMEOUT_INFINITE; + + TransactionPreconditionsBuilder preconditionsBuilder = mPreconditions.toBuilder(); + if (mPreconditions.getTimeBounds() == null) { + preconditionsBuilder.timeBounds(new TimeBounds(0, timeoutTimestamp)); + } else { + preconditionsBuilder.timeBounds( new TimeBounds(mPreconditions.getTimeBounds().getMinTime(), timeoutTimestamp)); + } + mPreconditions = preconditionsBuilder.build(); + return this; + } + + public TransactionBuilder setBaseFee(int baseFee) { + if (baseFee < AbstractTransaction.MIN_BASE_FEE) { + throw new IllegalArgumentException("baseFee cannot be smaller than the BASE_FEE (" + AbstractTransaction.MIN_BASE_FEE + "): " + baseFee); + } + + this.mBaseFee = baseFee; + return this; + } + + /** + * Builds a transaction and increments the sequence number on the source account after transaction is constructed. + */ + public Transaction build() { + mPreconditions.isValid(); + + if (mBaseFee == null) { + throw new FormatException("mBaseFee has to be set. you must call setBaseFee()."); + } + + if (mNetwork == null) { + throw new NoNetworkSelectedException(); + } + + long sequenceNumber = mSourceAccount.getIncrementedSequenceNumber(); + Operation[] operations = new Operation[mOperations.size()]; + operations = mOperations.toArray(operations); + Transaction transaction = new Transaction( + mAccountConverter, + mSourceAccount.getAccountId(), + operations.length * mBaseFee, + sequenceNumber, + operations, + mMemo, + mPreconditions, + mNetwork + ); + mSourceAccount.setSequenceNumber(sequenceNumber); + return transaction; + } + + /** + * A default implementation of sequence number generation which will derive a sequence number based on + * sourceAccount's current sequence number + 1. + */ + public static Function IncrementedSequenceNumberFunc = new Function() { + @Override + public Long apply(TransactionBuilderAccount sourceAccount) { + return sourceAccount.getIncrementedSequenceNumber(); + } + }; + + public static org.stellar.sdk.xdr.TimeBounds buildTimeBounds(long minTime, long maxTime) { + return new org.stellar.sdk.xdr.TimeBounds.Builder().minTime(new TimePoint(new Uint64(minTime))) + .maxTime(new TimePoint(new Uint64(maxTime))).build(); + } +} diff --git a/src/main/java/org/stellar/sdk/TransactionBuilderAccount.java b/src/main/java/org/stellar/sdk/TransactionBuilderAccount.java index 86a2308ea..a11ca967a 100644 --- a/src/main/java/org/stellar/sdk/TransactionBuilderAccount.java +++ b/src/main/java/org/stellar/sdk/TransactionBuilderAccount.java @@ -1,7 +1,7 @@ package org.stellar.sdk; /** - * Specifies interface for Account object used in {@link org.stellar.sdk.Transaction.Builder} + * Specifies interface for Account object used in {@link TransactionBuilder} */ public interface TransactionBuilderAccount { /** @@ -19,6 +19,11 @@ public interface TransactionBuilderAccount { */ Long getSequenceNumber(); + /** + * Set current sequence number on this Account. + */ + void setSequenceNumber(long seqNum); + /** * Returns sequence number incremented by one, but does not increment internal counter. */ diff --git a/src/main/java/org/stellar/sdk/TransactionPreconditions.java b/src/main/java/org/stellar/sdk/TransactionPreconditions.java new file mode 100644 index 000000000..5a7ebadfd --- /dev/null +++ b/src/main/java/org/stellar/sdk/TransactionPreconditions.java @@ -0,0 +1,127 @@ +package org.stellar.sdk; + +import lombok.Builder; +import lombok.NonNull; +import lombok.Singular; +import lombok.Value; +import org.stellar.sdk.xdr.Duration; +import org.stellar.sdk.xdr.Int64; +import org.stellar.sdk.xdr.PreconditionType; +import org.stellar.sdk.xdr.Preconditions; +import org.stellar.sdk.xdr.PreconditionsV2; +import org.stellar.sdk.xdr.SequenceNumber; +import org.stellar.sdk.xdr.SignerKey; +import org.stellar.sdk.xdr.Uint32; +import org.stellar.sdk.xdr.Uint64; + +import java.util.Arrays; +import java.util.List; + +@Value +@Builder(toBuilder=true) +/** + * Preconditions of a transaction per CAP-21 + */ +public class TransactionPreconditions { + public static final long MAX_EXTRA_SIGNERS_COUNT = 2; + public static final long TIMEOUT_INFINITE = 0; + + LedgerBounds ledgerBounds; + Long minSeqNumber; + long minSeqAge; + int minSeqLedgerGap; + @Singular + @NonNull + List extraSigners; + TimeBounds timeBounds; + + public void isValid() { + if (timeBounds == null) { + throw new FormatException("Invalid preconditions, must define timebounds"); + } + + if (extraSigners.size() > MAX_EXTRA_SIGNERS_COUNT) { + throw new FormatException("Invalid preconditions, too many extra signers, can only have up to " + MAX_EXTRA_SIGNERS_COUNT); + } + } + + public boolean hasV2() { + return (ledgerBounds != null || + (minSeqLedgerGap > 0) || + (minSeqAge > 0) || + minSeqNumber != null || + !extraSigners.isEmpty()); + } + + public static TransactionPreconditions fromXdr(Preconditions preconditions) { + TransactionPreconditionsBuilder builder = new TransactionPreconditionsBuilder(); + + if (preconditions.getDiscriminant().equals(PreconditionType.PRECOND_V2)) { + if (preconditions.getV2().getTimeBounds() != null) { + builder.timeBounds(new TimeBounds( + preconditions.getV2().getTimeBounds().getMinTime().getTimePoint().getUint64(), + preconditions.getV2().getTimeBounds().getMaxTime().getTimePoint().getUint64())); + } + if (preconditions.getV2().getExtraSigners() != null && preconditions.getV2().getExtraSigners().length > 0) { + builder.extraSigners(Arrays.asList(preconditions.getV2().getExtraSigners())); + } + if (preconditions.getV2().getMinSeqAge() != null) { + builder.minSeqAge(preconditions.getV2().getMinSeqAge().getDuration().getUint64()); + } + if (preconditions.getV2().getLedgerBounds() != null) { + builder.ledgerBounds(LedgerBounds.fromXdr(preconditions.getV2().getLedgerBounds())); + } + if (preconditions.getV2().getMinSeqNum() != null) { + builder.minSeqNumber(preconditions.getV2().getMinSeqNum().getSequenceNumber().getInt64()); + } + if (preconditions.getV2().getMinSeqLedgerGap() != null) { + builder.minSeqLedgerGap(preconditions.getV2().getMinSeqLedgerGap().getUint32()); + } + } else { + if (preconditions.getTimeBounds() != null) { + builder.timeBounds(new TimeBounds(preconditions.getTimeBounds().getMinTime().getTimePoint().getUint64(), + preconditions.getTimeBounds().getMaxTime().getTimePoint().getUint64())); + } + } + + return builder.build(); + } + + public Preconditions toXdr() { + Preconditions.Builder preconditionsBuilder = new Preconditions.Builder(); + + if (hasV2()) { + preconditionsBuilder.discriminant(PreconditionType.PRECOND_V2); + PreconditionsV2.Builder v2Builder = new PreconditionsV2.Builder(); + + v2Builder.extraSigners(extraSigners.toArray(new SignerKey[]{})); + v2Builder.minSeqAge(new Duration(new Uint64(minSeqAge))); + + if (ledgerBounds != null) { + v2Builder.ledgerBounds(new org.stellar.sdk.xdr.LedgerBounds.Builder() + .minLedger(new Uint32(ledgerBounds.getMinLedger())) + .maxLedger(new Uint32(ledgerBounds.getMaxLedger())) + .build()); + } + if (minSeqNumber != null) { + v2Builder.minSeqNum(new SequenceNumber(new Int64(minSeqNumber))); + } + + v2Builder.minSeqLedgerGap(new Uint32(minSeqLedgerGap)); + + if (timeBounds != null) { + v2Builder.timeBounds(timeBounds.toXdr()); + } + preconditionsBuilder.v2(v2Builder.build()); + } else { + if (timeBounds == null) { + preconditionsBuilder.discriminant(PreconditionType.PRECOND_NONE); + } else { + preconditionsBuilder.discriminant(PreconditionType.PRECOND_TIME); + preconditionsBuilder.timeBounds(timeBounds.toXdr()); + } + } + + return preconditionsBuilder.build(); + } +} diff --git a/src/main/java/org/stellar/sdk/responses/AccountResponse.java b/src/main/java/org/stellar/sdk/responses/AccountResponse.java index fc33840e7..109b2abd8 100644 --- a/src/main/java/org/stellar/sdk/responses/AccountResponse.java +++ b/src/main/java/org/stellar/sdk/responses/AccountResponse.java @@ -25,6 +25,10 @@ public class AccountResponse extends Response implements org.stellar.sdk.Transac private Long sequenceNumber; @SerializedName("subentry_count") private Integer subentryCount; + @SerializedName("sequence_ledger") + private Long sequenceUpdatedAtLedger; + @SerializedName("sequence_time") + private Long sequenceUpdatedAtTime; @SerializedName("inflation_destination") private String inflationDestination; @SerializedName("home_domain") @@ -74,6 +78,11 @@ public Long getSequenceNumber() { return sequenceNumber; } + @Override + public void setSequenceNumber(long seqNum) { + sequenceNumber = seqNum; + } + @Override public Long getIncrementedSequenceNumber() { return new Long(sequenceNumber + 1); @@ -83,7 +92,15 @@ public Long getIncrementedSequenceNumber() { public void incrementSequenceNumber() { sequenceNumber++; } - + + public Long getSequenceUpdatedAtLedger() { + return sequenceUpdatedAtLedger; + } + + public Long getSequenceUpdatedAtTime() { + return sequenceUpdatedAtTime; + } + public Integer getSubentryCount() { return subentryCount; } diff --git a/src/main/java/org/stellar/sdk/responses/PredicateDeserializer.java b/src/main/java/org/stellar/sdk/responses/PredicateDeserializer.java index 6c129750f..a6795a799 100644 --- a/src/main/java/org/stellar/sdk/responses/PredicateDeserializer.java +++ b/src/main/java/org/stellar/sdk/responses/PredicateDeserializer.java @@ -3,6 +3,10 @@ import com.google.common.collect.Lists; import com.google.gson.*; import org.stellar.sdk.Predicate; +import org.stellar.sdk.xdr.Duration; +import org.stellar.sdk.xdr.Int64; +import org.stellar.sdk.xdr.TimePoint; +import org.stellar.sdk.xdr.Uint64; import org.threeten.bp.Instant; import java.lang.reflect.Type; @@ -39,15 +43,14 @@ public Predicate deserialize(JsonElement json, Type typeOfT, JsonDeserialization // backwards compatible for abs before, uses the newer abs_before_epoch if available from server // otherwise if abs_before_epoch is absent, it will fall back to original attempt to parse abs_before date string if (obj.has("abs_before_epoch")) { - return new Predicate.AbsBefore(obj.get("abs_before_epoch").getAsLong()); + return new Predicate.AbsBefore(new TimePoint(new Uint64(obj.get("abs_before_epoch").getAsLong()))); } else if (obj.has("abs_before")) { String formattedDate = obj.get("abs_before").getAsString(); - return new Predicate.AbsBefore(Instant.parse(formattedDate).getEpochSecond()); + return new Predicate.AbsBefore(new TimePoint(new Uint64(Instant.parse(formattedDate).getEpochSecond()))); } if (obj.has("rel_before")) { - Long relBefore = obj.get("rel_before").getAsLong(); - return new Predicate.RelBefore(relBefore); + return new Predicate.RelBefore(new Duration(new Uint64(obj.get("rel_before").getAsLong()))); } throw new IllegalArgumentException("Unsupported predicate: "+json.toString()); diff --git a/src/main/java/org/stellar/sdk/xdr/AccountEntryExtensionV2.java b/src/main/java/org/stellar/sdk/xdr/AccountEntryExtensionV2.java index d92131ea2..54ae3dc9f 100644 --- a/src/main/java/org/stellar/sdk/xdr/AccountEntryExtensionV2.java +++ b/src/main/java/org/stellar/sdk/xdr/AccountEntryExtensionV2.java @@ -21,6 +21,8 @@ // { // case 0: // void; +// case 3: +// AccountEntryExtensionV3 v3; // } // ext; // }; @@ -140,18 +142,32 @@ public Integer getDiscriminant() { public void setDiscriminant(Integer value) { this.v = value; } + private AccountEntryExtensionV3 v3; + public AccountEntryExtensionV3 getV3() { + return this.v3; + } + public void setV3(AccountEntryExtensionV3 value) { + this.v3 = value; + } public static final class Builder { private Integer discriminant; + private AccountEntryExtensionV3 v3; public Builder discriminant(Integer discriminant) { this.discriminant = discriminant; return this; } + public Builder v3(AccountEntryExtensionV3 v3) { + this.v3 = v3; + return this; + } + public AccountEntryExtensionV2Ext build() { AccountEntryExtensionV2Ext val = new AccountEntryExtensionV2Ext(); val.setDiscriminant(discriminant); + val.setV3(v3); return val; } } @@ -163,6 +179,9 @@ public static void encode(XdrDataOutputStream stream, AccountEntryExtensionV2Ext switch (encodedAccountEntryExtensionV2Ext.getDiscriminant()) { case 0: break; + case 3: + AccountEntryExtensionV3.encode(stream, encodedAccountEntryExtensionV2Ext.v3); + break; } } public void encode(XdrDataOutputStream stream) throws IOException { @@ -175,12 +194,15 @@ public static AccountEntryExtensionV2Ext decode(XdrDataInputStream stream) throw switch (decodedAccountEntryExtensionV2Ext.getDiscriminant()) { case 0: break; + case 3: + decodedAccountEntryExtensionV2Ext.v3 = AccountEntryExtensionV3.decode(stream); + break; } return decodedAccountEntryExtensionV2Ext; } @Override public int hashCode() { - return Objects.hashCode(this.v); + return Objects.hashCode(this.v3, this.v); } @Override public boolean equals(Object object) { @@ -189,7 +211,7 @@ public boolean equals(Object object) { } AccountEntryExtensionV2Ext other = (AccountEntryExtensionV2Ext) object; - return Objects.equal(this.v, other.v); + return Objects.equal(this.v3, other.v3) && Objects.equal(this.v, other.v); } } diff --git a/src/main/java/org/stellar/sdk/xdr/AccountEntryExtensionV3.java b/src/main/java/org/stellar/sdk/xdr/AccountEntryExtensionV3.java new file mode 100644 index 000000000..44a0890d0 --- /dev/null +++ b/src/main/java/org/stellar/sdk/xdr/AccountEntryExtensionV3.java @@ -0,0 +1,107 @@ +// Automatically generated by xdrgen +// DO NOT EDIT or your changes may be overwritten + +package org.stellar.sdk.xdr; + + +import java.io.IOException; + +import com.google.common.base.Objects; + +// === xdr source ============================================================ + +// struct AccountEntryExtensionV3 +// { +// // We can use this to add more fields, or because it is first, to +// // change AccountEntryExtensionV3 into a union. +// ExtensionPoint ext; +// +// // Ledger number at which `seqNum` took on its present value. +// uint32 seqLedger; +// +// // Time at which `seqNum` took on its present value. +// TimePoint seqTime; +// }; + +// =========================================================================== +public class AccountEntryExtensionV3 implements XdrElement { + public AccountEntryExtensionV3 () {} + private ExtensionPoint ext; + public ExtensionPoint getExt() { + return this.ext; + } + public void setExt(ExtensionPoint value) { + this.ext = value; + } + private Uint32 seqLedger; + public Uint32 getSeqLedger() { + return this.seqLedger; + } + public void setSeqLedger(Uint32 value) { + this.seqLedger = value; + } + private TimePoint seqTime; + public TimePoint getSeqTime() { + return this.seqTime; + } + public void setSeqTime(TimePoint value) { + this.seqTime = value; + } + public static void encode(XdrDataOutputStream stream, AccountEntryExtensionV3 encodedAccountEntryExtensionV3) throws IOException{ + ExtensionPoint.encode(stream, encodedAccountEntryExtensionV3.ext); + Uint32.encode(stream, encodedAccountEntryExtensionV3.seqLedger); + TimePoint.encode(stream, encodedAccountEntryExtensionV3.seqTime); + } + public void encode(XdrDataOutputStream stream) throws IOException { + encode(stream, this); + } + public static AccountEntryExtensionV3 decode(XdrDataInputStream stream) throws IOException { + AccountEntryExtensionV3 decodedAccountEntryExtensionV3 = new AccountEntryExtensionV3(); + decodedAccountEntryExtensionV3.ext = ExtensionPoint.decode(stream); + decodedAccountEntryExtensionV3.seqLedger = Uint32.decode(stream); + decodedAccountEntryExtensionV3.seqTime = TimePoint.decode(stream); + return decodedAccountEntryExtensionV3; + } + @Override + public int hashCode() { + return Objects.hashCode(this.ext, this.seqLedger, this.seqTime); + } + @Override + public boolean equals(Object object) { + if (!(object instanceof AccountEntryExtensionV3)) { + return false; + } + + AccountEntryExtensionV3 other = (AccountEntryExtensionV3) object; + return Objects.equal(this.ext, other.ext) && Objects.equal(this.seqLedger, other.seqLedger) && Objects.equal(this.seqTime, other.seqTime); + } + + public static final class Builder { + private ExtensionPoint ext; + private Uint32 seqLedger; + private TimePoint seqTime; + + public Builder ext(ExtensionPoint ext) { + this.ext = ext; + return this; + } + + public Builder seqLedger(Uint32 seqLedger) { + this.seqLedger = seqLedger; + return this; + } + + public Builder seqTime(TimePoint seqTime) { + this.seqTime = seqTime; + return this; + } + + public AccountEntryExtensionV3 build() { + AccountEntryExtensionV3 val = new AccountEntryExtensionV3(); + val.setExt(ext); + val.setSeqLedger(seqLedger); + val.setSeqTime(seqTime); + return val; + } + } +} diff --git a/src/main/java/org/stellar/sdk/xdr/AllowTrustResultCode.java b/src/main/java/org/stellar/sdk/xdr/AllowTrustResultCode.java index b51667c2d..2da92d696 100644 --- a/src/main/java/org/stellar/sdk/xdr/AllowTrustResultCode.java +++ b/src/main/java/org/stellar/sdk/xdr/AllowTrustResultCode.java @@ -18,10 +18,10 @@ // ALLOW_TRUST_NO_TRUST_LINE = -2, // trustor does not have a trustline // // source account does not require trust // ALLOW_TRUST_TRUST_NOT_REQUIRED = -3, -// ALLOW_TRUST_CANT_REVOKE = -4, // source account can't revoke trust, +// ALLOW_TRUST_CANT_REVOKE = -4, // source account can't revoke trust, // ALLOW_TRUST_SELF_NOT_ALLOWED = -5, // trusting self is not allowed -// ALLOW_TRUST_LOW_RESERVE = -6 // claimable balances can't be created -// // on revoke due to low reserves +// ALLOW_TRUST_LOW_RESERVE = -6 // claimable balances can't be created +// // on revoke due to low reserves // }; // =========================================================================== diff --git a/src/main/java/org/stellar/sdk/xdr/Asset.java b/src/main/java/org/stellar/sdk/xdr/Asset.java index 3093903bf..542c98471 100644 --- a/src/main/java/org/stellar/sdk/xdr/Asset.java +++ b/src/main/java/org/stellar/sdk/xdr/Asset.java @@ -79,44 +79,39 @@ public Asset build() { } public static void encode(XdrDataOutputStream stream, Asset encodedAsset) throws IOException { - //Xdrgen::AST::Identifier - //AssetType - stream.writeInt(encodedAsset.getDiscriminant().getValue()); - switch (encodedAsset.getDiscriminant()) { - case ASSET_TYPE_NATIVE: - break; - case ASSET_TYPE_CREDIT_ALPHANUM4: - AlphaNum4.encode(stream, encodedAsset.alphaNum4); - break; - case ASSET_TYPE_CREDIT_ALPHANUM12: - AlphaNum12.encode(stream, encodedAsset.alphaNum12); - break; - case ASSET_TYPE_POOL_SHARE: - throw new RuntimeException("Invalid asset type"); - } + //Xdrgen::AST::Identifier + //AssetType + stream.writeInt(encodedAsset.getDiscriminant().getValue()); + switch (encodedAsset.getDiscriminant()) { + case ASSET_TYPE_NATIVE: + break; + case ASSET_TYPE_CREDIT_ALPHANUM4: + AlphaNum4.encode(stream, encodedAsset.alphaNum4); + break; + case ASSET_TYPE_CREDIT_ALPHANUM12: + AlphaNum12.encode(stream, encodedAsset.alphaNum12); + break; + } } public void encode(XdrDataOutputStream stream) throws IOException { encode(stream, this); } public static Asset decode(XdrDataInputStream stream) throws IOException { - Asset decodedAsset = new Asset(); - AssetType discriminant = AssetType.decode(stream); - decodedAsset.setDiscriminant(discriminant); - switch (decodedAsset.getDiscriminant()) { - case ASSET_TYPE_NATIVE: - break; - case ASSET_TYPE_CREDIT_ALPHANUM4: - decodedAsset.alphaNum4 = AlphaNum4.decode(stream); - break; - case ASSET_TYPE_CREDIT_ALPHANUM12: - decodedAsset.alphaNum12 = AlphaNum12.decode(stream); - break; - case ASSET_TYPE_POOL_SHARE: - throw new RuntimeException("Invalid asset type"); - } + Asset decodedAsset = new Asset(); + AssetType discriminant = AssetType.decode(stream); + decodedAsset.setDiscriminant(discriminant); + switch (decodedAsset.getDiscriminant()) { + case ASSET_TYPE_NATIVE: + break; + case ASSET_TYPE_CREDIT_ALPHANUM4: + decodedAsset.alphaNum4 = AlphaNum4.decode(stream); + break; + case ASSET_TYPE_CREDIT_ALPHANUM12: + decodedAsset.alphaNum12 = AlphaNum12.decode(stream); + break; + } return decodedAsset; } - @Override public int hashCode() { return Objects.hashCode(this.alphaNum4, this.alphaNum12, this.type); diff --git a/src/main/java/org/stellar/sdk/xdr/ChangeTrustResultCode.java b/src/main/java/org/stellar/sdk/xdr/ChangeTrustResultCode.java index 2495e5100..932d771fa 100644 --- a/src/main/java/org/stellar/sdk/xdr/ChangeTrustResultCode.java +++ b/src/main/java/org/stellar/sdk/xdr/ChangeTrustResultCode.java @@ -20,10 +20,12 @@ // // cannot create with a limit of 0 // CHANGE_TRUST_LOW_RESERVE = // -4, // not enough funds to create a new trust line, -// CHANGE_TRUST_SELF_NOT_ALLOWED = -5, // trusting self is not allowed +// CHANGE_TRUST_SELF_NOT_ALLOWED = -5, // trusting self is not allowed // CHANGE_TRUST_TRUST_LINE_MISSING = -6, // Asset trustline is missing for pool -// CHANGE_TRUST_CANNOT_DELETE = -7, // Asset trustline is still referenced in a pool -// CHANGE_TRUST_NOT_AUTH_MAINTAIN_LIABILITIES = -8 // Asset trustline is deauthorized +// CHANGE_TRUST_CANNOT_DELETE = +// -7, // Asset trustline is still referenced in a pool +// CHANGE_TRUST_NOT_AUTH_MAINTAIN_LIABILITIES = +// -8 // Asset trustline is deauthorized // }; // =========================================================================== diff --git a/src/main/java/org/stellar/sdk/xdr/ClaimableBalanceID.java b/src/main/java/org/stellar/sdk/xdr/ClaimableBalanceID.java index d57036769..b3e261ef2 100644 --- a/src/main/java/org/stellar/sdk/xdr/ClaimableBalanceID.java +++ b/src/main/java/org/stellar/sdk/xdr/ClaimableBalanceID.java @@ -14,8 +14,6 @@ // { // case CLAIMABLE_BALANCE_ID_TYPE_V0: // Hash v0; -// case CLAIMABLE_BALANCE_ID_TYPE_FROM_POOL_REVOKE: -// Hash fromPoolRevoke; // }; // =========================================================================== @@ -35,18 +33,10 @@ public Hash getV0() { public void setV0(Hash value) { this.v0 = value; } - private Hash fromPoolRevoke; - public Hash getFromPoolRevoke() { - return this.fromPoolRevoke; - } - public void setFromPoolRevoke(Hash value) { - this.fromPoolRevoke = value; - } public static final class Builder { private ClaimableBalanceIDType discriminant; private Hash v0; - private Hash fromPoolRevoke; public Builder discriminant(ClaimableBalanceIDType discriminant) { this.discriminant = discriminant; @@ -58,16 +48,10 @@ public Builder v0(Hash v0) { return this; } - public Builder fromPoolRevoke(Hash fromPoolRevoke) { - this.fromPoolRevoke = fromPoolRevoke; - return this; - } - public ClaimableBalanceID build() { ClaimableBalanceID val = new ClaimableBalanceID(); val.setDiscriminant(discriminant); val.setV0(v0); - val.setFromPoolRevoke(fromPoolRevoke); return val; } } @@ -80,9 +64,6 @@ public static void encode(XdrDataOutputStream stream, ClaimableBalanceID encoded case CLAIMABLE_BALANCE_ID_TYPE_V0: Hash.encode(stream, encodedClaimableBalanceID.v0); break; - case CLAIMABLE_BALANCE_ID_TYPE_FROM_POOL_REVOKE: - Hash.encode(stream, encodedClaimableBalanceID.fromPoolRevoke); - break; } } public void encode(XdrDataOutputStream stream) throws IOException { @@ -96,15 +77,12 @@ public static ClaimableBalanceID decode(XdrDataInputStream stream) throws IOExce case CLAIMABLE_BALANCE_ID_TYPE_V0: decodedClaimableBalanceID.v0 = Hash.decode(stream); break; - case CLAIMABLE_BALANCE_ID_TYPE_FROM_POOL_REVOKE: - decodedClaimableBalanceID.fromPoolRevoke = Hash.decode(stream); - break; } return decodedClaimableBalanceID; } @Override public int hashCode() { - return Objects.hashCode(this.v0, this.fromPoolRevoke, this.type); + return Objects.hashCode(this.v0, this.type); } @Override public boolean equals(Object object) { @@ -113,6 +91,6 @@ public boolean equals(Object object) { } ClaimableBalanceID other = (ClaimableBalanceID) object; - return Objects.equal(this.v0, other.v0) && Objects.equal(this.fromPoolRevoke, other.fromPoolRevoke) && Objects.equal(this.type, other.type); + return Objects.equal(this.v0, other.v0) && Objects.equal(this.type, other.type); } } diff --git a/src/main/java/org/stellar/sdk/xdr/ClaimableBalanceIDType.java b/src/main/java/org/stellar/sdk/xdr/ClaimableBalanceIDType.java index 63c44220c..308ad5c89 100644 --- a/src/main/java/org/stellar/sdk/xdr/ClaimableBalanceIDType.java +++ b/src/main/java/org/stellar/sdk/xdr/ClaimableBalanceIDType.java @@ -11,14 +11,12 @@ // enum ClaimableBalanceIDType // { -// CLAIMABLE_BALANCE_ID_TYPE_V0 = 0, -// CLAIMABLE_BALANCE_ID_TYPE_FROM_POOL_REVOKE = 1 +// CLAIMABLE_BALANCE_ID_TYPE_V0 = 0 // }; // =========================================================================== public enum ClaimableBalanceIDType implements XdrElement { CLAIMABLE_BALANCE_ID_TYPE_V0(0), - CLAIMABLE_BALANCE_ID_TYPE_FROM_POOL_REVOKE(1), ; private int mValue; @@ -34,7 +32,6 @@ public static ClaimableBalanceIDType decode(XdrDataInputStream stream) throws IO int value = stream.readInt(); switch (value) { case 0: return CLAIMABLE_BALANCE_ID_TYPE_V0; - case 1: return CLAIMABLE_BALANCE_ID_TYPE_FROM_POOL_REVOKE; default: throw new RuntimeException("Unknown enum value: " + value); } diff --git a/src/main/java/org/stellar/sdk/xdr/CryptoKeyType.java b/src/main/java/org/stellar/sdk/xdr/CryptoKeyType.java index bfaf14e5c..72d7e81a8 100644 --- a/src/main/java/org/stellar/sdk/xdr/CryptoKeyType.java +++ b/src/main/java/org/stellar/sdk/xdr/CryptoKeyType.java @@ -14,6 +14,7 @@ // KEY_TYPE_ED25519 = 0, // KEY_TYPE_PRE_AUTH_TX = 1, // KEY_TYPE_HASH_X = 2, +// KEY_TYPE_ED25519_SIGNED_PAYLOAD = 3, // // MUXED enum values for supported type are derived from the enum values // // above by ORing them with 0x100 // KEY_TYPE_MUXED_ED25519 = 0x100 @@ -24,6 +25,7 @@ public enum CryptoKeyType implements XdrElement { KEY_TYPE_ED25519(0), KEY_TYPE_PRE_AUTH_TX(1), KEY_TYPE_HASH_X(2), + KEY_TYPE_ED25519_SIGNED_PAYLOAD(3), KEY_TYPE_MUXED_ED25519(256), ; private int mValue; @@ -42,6 +44,7 @@ public static CryptoKeyType decode(XdrDataInputStream stream) throws IOException case 0: return KEY_TYPE_ED25519; case 1: return KEY_TYPE_PRE_AUTH_TX; case 2: return KEY_TYPE_HASH_X; + case 3: return KEY_TYPE_ED25519_SIGNED_PAYLOAD; case 256: return KEY_TYPE_MUXED_ED25519; default: throw new RuntimeException("Unknown enum value: " + value); diff --git a/src/main/java/org/stellar/sdk/xdr/Duration.java b/src/main/java/org/stellar/sdk/xdr/Duration.java new file mode 100644 index 000000000..84359c7ec --- /dev/null +++ b/src/main/java/org/stellar/sdk/xdr/Duration.java @@ -0,0 +1,60 @@ +// Automatically generated by xdrgen +// DO NOT EDIT or your changes may be overwritten + +package org.stellar.sdk.xdr; + + +import java.io.IOException; + +import com.google.common.base.Objects; + +// === xdr source ============================================================ + +// typedef uint64 Duration; + +// =========================================================================== +public class Duration implements XdrElement { + private Uint64 Duration; + + public Duration() {} + + public Duration(Uint64 Duration) { + this.Duration = Duration; + } + + public Uint64 getDuration() { + return this.Duration; + } + + public void setDuration(Uint64 value) { + this.Duration = value; + } + + public static void encode(XdrDataOutputStream stream, Duration encodedDuration) throws IOException { + Uint64.encode(stream, encodedDuration.Duration); + } + + public void encode(XdrDataOutputStream stream) throws IOException { + encode(stream, this); + } + public static Duration decode(XdrDataInputStream stream) throws IOException { + Duration decodedDuration = new Duration(); + decodedDuration.Duration = Uint64.decode(stream); + return decodedDuration; + } + + @Override + public int hashCode() { + return Objects.hashCode(this.Duration); + } + + @Override + public boolean equals(Object object) { + if (!(object instanceof Duration)) { + return false; + } + + Duration other = (Duration) object; + return Objects.equal(this.Duration, other.Duration); + } +} diff --git a/src/main/java/org/stellar/sdk/xdr/ExtensionPoint.java b/src/main/java/org/stellar/sdk/xdr/ExtensionPoint.java new file mode 100644 index 000000000..1032c2889 --- /dev/null +++ b/src/main/java/org/stellar/sdk/xdr/ExtensionPoint.java @@ -0,0 +1,80 @@ +// Automatically generated by xdrgen +// DO NOT EDIT or your changes may be overwritten + +package org.stellar.sdk.xdr; + + +import java.io.IOException; + +import com.google.common.base.Objects; + +// === xdr source ============================================================ + +// union ExtensionPoint switch (int v) +// { +// case 0: +// void; +// }; + +// =========================================================================== +public class ExtensionPoint implements XdrElement { + public ExtensionPoint () {} + Integer v; + public Integer getDiscriminant() { + return this.v; + } + public void setDiscriminant(Integer value) { + this.v = value; + } + + public static final class Builder { + private Integer discriminant; + + public Builder discriminant(Integer discriminant) { + this.discriminant = discriminant; + return this; + } + + public ExtensionPoint build() { + ExtensionPoint val = new ExtensionPoint(); + val.setDiscriminant(discriminant); + return val; + } + } + + public static void encode(XdrDataOutputStream stream, ExtensionPoint encodedExtensionPoint) throws IOException { + //Xdrgen::AST::Typespecs::Int + //Integer + stream.writeInt(encodedExtensionPoint.getDiscriminant().intValue()); + switch (encodedExtensionPoint.getDiscriminant()) { + case 0: + break; + } + } + public void encode(XdrDataOutputStream stream) throws IOException { + encode(stream, this); + } + public static ExtensionPoint decode(XdrDataInputStream stream) throws IOException { + ExtensionPoint decodedExtensionPoint = new ExtensionPoint(); + Integer discriminant = stream.readInt(); + decodedExtensionPoint.setDiscriminant(discriminant); + switch (decodedExtensionPoint.getDiscriminant()) { + case 0: + break; + } + return decodedExtensionPoint; + } + @Override + public int hashCode() { + return Objects.hashCode(this.v); + } + @Override + public boolean equals(Object object) { + if (!(object instanceof ExtensionPoint)) { + return false; + } + + ExtensionPoint other = (ExtensionPoint) object; + return Objects.equal(this.v, other.v); + } +} diff --git a/src/main/java/org/stellar/sdk/xdr/HashIDPreimage.java b/src/main/java/org/stellar/sdk/xdr/HashIDPreimage.java new file mode 100644 index 000000000..bb659ebe4 --- /dev/null +++ b/src/main/java/org/stellar/sdk/xdr/HashIDPreimage.java @@ -0,0 +1,327 @@ +// Automatically generated by xdrgen +// DO NOT EDIT or your changes may be overwritten + +package org.stellar.sdk.xdr; + + +import java.io.IOException; + +import com.google.common.base.Objects; + +// === xdr source ============================================================ + +// union HashIDPreimage switch (EnvelopeType type) +// { +// case ENVELOPE_TYPE_OP_ID: +// struct +// { +// AccountID sourceAccount; +// SequenceNumber seqNum; +// uint32 opNum; +// } operationID; +// case ENVELOPE_TYPE_POOL_REVOKE_OP_ID: +// struct +// { +// AccountID sourceAccount; +// SequenceNumber seqNum; +// uint32 opNum; +// PoolID liquidityPoolID; +// Asset asset; +// } revokeID; +// }; + +// =========================================================================== +public class HashIDPreimage implements XdrElement { + public HashIDPreimage () {} + EnvelopeType type; + public EnvelopeType getDiscriminant() { + return this.type; + } + public void setDiscriminant(EnvelopeType value) { + this.type = value; + } + private HashIDPreimageOperationID operationID; + public HashIDPreimageOperationID getOperationID() { + return this.operationID; + } + public void setOperationID(HashIDPreimageOperationID value) { + this.operationID = value; + } + private HashIDPreimageRevokeID revokeID; + public HashIDPreimageRevokeID getRevokeID() { + return this.revokeID; + } + public void setRevokeID(HashIDPreimageRevokeID value) { + this.revokeID = value; + } + + public static final class Builder { + private EnvelopeType discriminant; + private HashIDPreimageOperationID operationID; + private HashIDPreimageRevokeID revokeID; + + public Builder discriminant(EnvelopeType discriminant) { + this.discriminant = discriminant; + return this; + } + + public Builder operationID(HashIDPreimageOperationID operationID) { + this.operationID = operationID; + return this; + } + + public Builder revokeID(HashIDPreimageRevokeID revokeID) { + this.revokeID = revokeID; + return this; + } + + public HashIDPreimage build() { + HashIDPreimage val = new HashIDPreimage(); + val.setDiscriminant(discriminant); + val.setOperationID(operationID); + val.setRevokeID(revokeID); + return val; + } + } + + public static void encode(XdrDataOutputStream stream, HashIDPreimage encodedHashIDPreimage) throws IOException { + //Xdrgen::AST::Identifier + //EnvelopeType + stream.writeInt(encodedHashIDPreimage.getDiscriminant().getValue()); + switch (encodedHashIDPreimage.getDiscriminant()) { + case ENVELOPE_TYPE_OP_ID: + HashIDPreimageOperationID.encode(stream, encodedHashIDPreimage.operationID); + break; + case ENVELOPE_TYPE_POOL_REVOKE_OP_ID: + HashIDPreimageRevokeID.encode(stream, encodedHashIDPreimage.revokeID); + break; + } + } + public void encode(XdrDataOutputStream stream) throws IOException { + encode(stream, this); + } + public static HashIDPreimage decode(XdrDataInputStream stream) throws IOException { + HashIDPreimage decodedHashIDPreimage = new HashIDPreimage(); + EnvelopeType discriminant = EnvelopeType.decode(stream); + decodedHashIDPreimage.setDiscriminant(discriminant); + switch (decodedHashIDPreimage.getDiscriminant()) { + case ENVELOPE_TYPE_OP_ID: + decodedHashIDPreimage.operationID = HashIDPreimageOperationID.decode(stream); + break; + case ENVELOPE_TYPE_POOL_REVOKE_OP_ID: + decodedHashIDPreimage.revokeID = HashIDPreimageRevokeID.decode(stream); + break; + } + return decodedHashIDPreimage; + } + @Override + public int hashCode() { + return Objects.hashCode(this.operationID, this.revokeID, this.type); + } + @Override + public boolean equals(Object object) { + if (!(object instanceof HashIDPreimage)) { + return false; + } + + HashIDPreimage other = (HashIDPreimage) object; + return Objects.equal(this.operationID, other.operationID) && Objects.equal(this.revokeID, other.revokeID) && Objects.equal(this.type, other.type); + } + + public static class HashIDPreimageOperationID { + public HashIDPreimageOperationID () {} + private AccountID sourceAccount; + public AccountID getSourceAccount() { + return this.sourceAccount; + } + public void setSourceAccount(AccountID value) { + this.sourceAccount = value; + } + private SequenceNumber seqNum; + public SequenceNumber getSeqNum() { + return this.seqNum; + } + public void setSeqNum(SequenceNumber value) { + this.seqNum = value; + } + private Uint32 opNum; + public Uint32 getOpNum() { + return this.opNum; + } + public void setOpNum(Uint32 value) { + this.opNum = value; + } + public static void encode(XdrDataOutputStream stream, HashIDPreimageOperationID encodedHashIDPreimageOperationID) throws IOException{ + AccountID.encode(stream, encodedHashIDPreimageOperationID.sourceAccount); + SequenceNumber.encode(stream, encodedHashIDPreimageOperationID.seqNum); + Uint32.encode(stream, encodedHashIDPreimageOperationID.opNum); + } + public void encode(XdrDataOutputStream stream) throws IOException { + encode(stream, this); + } + public static HashIDPreimageOperationID decode(XdrDataInputStream stream) throws IOException { + HashIDPreimageOperationID decodedHashIDPreimageOperationID = new HashIDPreimageOperationID(); + decodedHashIDPreimageOperationID.sourceAccount = AccountID.decode(stream); + decodedHashIDPreimageOperationID.seqNum = SequenceNumber.decode(stream); + decodedHashIDPreimageOperationID.opNum = Uint32.decode(stream); + return decodedHashIDPreimageOperationID; + } + @Override + public int hashCode() { + return Objects.hashCode(this.sourceAccount, this.seqNum, this.opNum); + } + @Override + public boolean equals(Object object) { + if (!(object instanceof HashIDPreimageOperationID)) { + return false; + } + + HashIDPreimageOperationID other = (HashIDPreimageOperationID) object; + return Objects.equal(this.sourceAccount, other.sourceAccount) && Objects.equal(this.seqNum, other.seqNum) && Objects.equal(this.opNum, other.opNum); + } + + public static final class Builder { + private AccountID sourceAccount; + private SequenceNumber seqNum; + private Uint32 opNum; + + public Builder sourceAccount(AccountID sourceAccount) { + this.sourceAccount = sourceAccount; + return this; + } + + public Builder seqNum(SequenceNumber seqNum) { + this.seqNum = seqNum; + return this; + } + + public Builder opNum(Uint32 opNum) { + this.opNum = opNum; + return this; + } + + public HashIDPreimageOperationID build() { + HashIDPreimageOperationID val = new HashIDPreimageOperationID(); + val.setSourceAccount(sourceAccount); + val.setSeqNum(seqNum); + val.setOpNum(opNum); + return val; + } + } + + } + public static class HashIDPreimageRevokeID { + public HashIDPreimageRevokeID () {} + private AccountID sourceAccount; + public AccountID getSourceAccount() { + return this.sourceAccount; + } + public void setSourceAccount(AccountID value) { + this.sourceAccount = value; + } + private SequenceNumber seqNum; + public SequenceNumber getSeqNum() { + return this.seqNum; + } + public void setSeqNum(SequenceNumber value) { + this.seqNum = value; + } + private Uint32 opNum; + public Uint32 getOpNum() { + return this.opNum; + } + public void setOpNum(Uint32 value) { + this.opNum = value; + } + private PoolID liquidityPoolID; + public PoolID getLiquidityPoolID() { + return this.liquidityPoolID; + } + public void setLiquidityPoolID(PoolID value) { + this.liquidityPoolID = value; + } + private Asset asset; + public Asset getAsset() { + return this.asset; + } + public void setAsset(Asset value) { + this.asset = value; + } + public static void encode(XdrDataOutputStream stream, HashIDPreimageRevokeID encodedHashIDPreimageRevokeID) throws IOException{ + AccountID.encode(stream, encodedHashIDPreimageRevokeID.sourceAccount); + SequenceNumber.encode(stream, encodedHashIDPreimageRevokeID.seqNum); + Uint32.encode(stream, encodedHashIDPreimageRevokeID.opNum); + PoolID.encode(stream, encodedHashIDPreimageRevokeID.liquidityPoolID); + Asset.encode(stream, encodedHashIDPreimageRevokeID.asset); + } + public void encode(XdrDataOutputStream stream) throws IOException { + encode(stream, this); + } + public static HashIDPreimageRevokeID decode(XdrDataInputStream stream) throws IOException { + HashIDPreimageRevokeID decodedHashIDPreimageRevokeID = new HashIDPreimageRevokeID(); + decodedHashIDPreimageRevokeID.sourceAccount = AccountID.decode(stream); + decodedHashIDPreimageRevokeID.seqNum = SequenceNumber.decode(stream); + decodedHashIDPreimageRevokeID.opNum = Uint32.decode(stream); + decodedHashIDPreimageRevokeID.liquidityPoolID = PoolID.decode(stream); + decodedHashIDPreimageRevokeID.asset = Asset.decode(stream); + return decodedHashIDPreimageRevokeID; + } + @Override + public int hashCode() { + return Objects.hashCode(this.sourceAccount, this.seqNum, this.opNum, this.liquidityPoolID, this.asset); + } + @Override + public boolean equals(Object object) { + if (!(object instanceof HashIDPreimageRevokeID)) { + return false; + } + + HashIDPreimageRevokeID other = (HashIDPreimageRevokeID) object; + return Objects.equal(this.sourceAccount, other.sourceAccount) && Objects.equal(this.seqNum, other.seqNum) && Objects.equal(this.opNum, other.opNum) && Objects.equal(this.liquidityPoolID, other.liquidityPoolID) && Objects.equal(this.asset, other.asset); + } + + public static final class Builder { + private AccountID sourceAccount; + private SequenceNumber seqNum; + private Uint32 opNum; + private PoolID liquidityPoolID; + private Asset asset; + + public Builder sourceAccount(AccountID sourceAccount) { + this.sourceAccount = sourceAccount; + return this; + } + + public Builder seqNum(SequenceNumber seqNum) { + this.seqNum = seqNum; + return this; + } + + public Builder opNum(Uint32 opNum) { + this.opNum = opNum; + return this; + } + + public Builder liquidityPoolID(PoolID liquidityPoolID) { + this.liquidityPoolID = liquidityPoolID; + return this; + } + + public Builder asset(Asset asset) { + this.asset = asset; + return this; + } + + public HashIDPreimageRevokeID build() { + HashIDPreimageRevokeID val = new HashIDPreimageRevokeID(); + val.setSourceAccount(sourceAccount); + val.setSeqNum(seqNum); + val.setOpNum(opNum); + val.setLiquidityPoolID(liquidityPoolID); + val.setAsset(asset); + return val; + } + } + + } +} diff --git a/src/main/java/org/stellar/sdk/xdr/InnerTransactionResult.java b/src/main/java/org/stellar/sdk/xdr/InnerTransactionResult.java index 5eb00be9e..5af16bdc5 100644 --- a/src/main/java/org/stellar/sdk/xdr/InnerTransactionResult.java +++ b/src/main/java/org/stellar/sdk/xdr/InnerTransactionResult.java @@ -35,6 +35,8 @@ // case txNOT_SUPPORTED: // // txFEE_BUMP_INNER_FAILED is not included // case txBAD_SPONSORSHIP: +// case txBAD_MIN_SEQ_AGE_OR_GAP: +// case txMALFORMED: // void; // } // result; @@ -194,6 +196,8 @@ public static void encode(XdrDataOutputStream stream, InnerTransactionResultResu case txINTERNAL_ERROR: case txNOT_SUPPORTED: case txBAD_SPONSORSHIP: + case txBAD_MIN_SEQ_AGE_OR_GAP: + case txMALFORMED: break; } } @@ -225,6 +229,8 @@ public static InnerTransactionResultResult decode(XdrDataInputStream stream) thr case txINTERNAL_ERROR: case txNOT_SUPPORTED: case txBAD_SPONSORSHIP: + case txBAD_MIN_SEQ_AGE_OR_GAP: + case txMALFORMED: break; } return decodedInnerTransactionResultResult; diff --git a/src/main/java/org/stellar/sdk/xdr/LedgerBounds.java b/src/main/java/org/stellar/sdk/xdr/LedgerBounds.java new file mode 100644 index 000000000..0fc43016f --- /dev/null +++ b/src/main/java/org/stellar/sdk/xdr/LedgerBounds.java @@ -0,0 +1,84 @@ +// Automatically generated by xdrgen +// DO NOT EDIT or your changes may be overwritten + +package org.stellar.sdk.xdr; + + +import java.io.IOException; + +import com.google.common.base.Objects; + +// === xdr source ============================================================ + +// struct LedgerBounds +// { +// uint32 minLedger; +// uint32 maxLedger; // 0 here means no maxLedger +// }; + +// =========================================================================== +public class LedgerBounds implements XdrElement { + public LedgerBounds () {} + private Uint32 minLedger; + public Uint32 getMinLedger() { + return this.minLedger; + } + public void setMinLedger(Uint32 value) { + this.minLedger = value; + } + private Uint32 maxLedger; + public Uint32 getMaxLedger() { + return this.maxLedger; + } + public void setMaxLedger(Uint32 value) { + this.maxLedger = value; + } + public static void encode(XdrDataOutputStream stream, LedgerBounds encodedLedgerBounds) throws IOException{ + Uint32.encode(stream, encodedLedgerBounds.minLedger); + Uint32.encode(stream, encodedLedgerBounds.maxLedger); + } + public void encode(XdrDataOutputStream stream) throws IOException { + encode(stream, this); + } + public static LedgerBounds decode(XdrDataInputStream stream) throws IOException { + LedgerBounds decodedLedgerBounds = new LedgerBounds(); + decodedLedgerBounds.minLedger = Uint32.decode(stream); + decodedLedgerBounds.maxLedger = Uint32.decode(stream); + return decodedLedgerBounds; + } + @Override + public int hashCode() { + return Objects.hashCode(this.minLedger, this.maxLedger); + } + @Override + public boolean equals(Object object) { + if (!(object instanceof LedgerBounds)) { + return false; + } + + LedgerBounds other = (LedgerBounds) object; + return Objects.equal(this.minLedger, other.minLedger) && Objects.equal(this.maxLedger, other.maxLedger); + } + + public static final class Builder { + private Uint32 minLedger; + private Uint32 maxLedger; + + public Builder minLedger(Uint32 minLedger) { + this.minLedger = minLedger; + return this; + } + + public Builder maxLedger(Uint32 maxLedger) { + this.maxLedger = maxLedger; + return this; + } + + public LedgerBounds build() { + LedgerBounds val = new LedgerBounds(); + val.setMinLedger(minLedger); + val.setMaxLedger(maxLedger); + return val; + } + } +} diff --git a/src/main/java/org/stellar/sdk/xdr/LedgerHeaderExtensionV1.java b/src/main/java/org/stellar/sdk/xdr/LedgerHeaderExtensionV1.java index a78303c1d..33cd29320 100644 --- a/src/main/java/org/stellar/sdk/xdr/LedgerHeaderExtensionV1.java +++ b/src/main/java/org/stellar/sdk/xdr/LedgerHeaderExtensionV1.java @@ -12,7 +12,7 @@ // struct LedgerHeaderExtensionV1 // { -// uint32 flags; // UpgradeFlags +// uint32 flags; // LedgerHeaderFlags // // union switch (int v) // { diff --git a/src/main/java/org/stellar/sdk/xdr/LedgerHeaderFlags.java b/src/main/java/org/stellar/sdk/xdr/LedgerHeaderFlags.java index 4c898b73d..99d3c02f7 100644 --- a/src/main/java/org/stellar/sdk/xdr/LedgerHeaderFlags.java +++ b/src/main/java/org/stellar/sdk/xdr/LedgerHeaderFlags.java @@ -10,8 +10,7 @@ // === xdr source ============================================================ // enum LedgerHeaderFlags -// { // masks for each flag -// +// { // DISABLE_LIQUIDITY_POOL_TRADING_FLAG = 0x1, // DISABLE_LIQUIDITY_POOL_DEPOSIT_FLAG = 0x2, // DISABLE_LIQUIDITY_POOL_WITHDRAWAL_FLAG = 0x4 diff --git a/src/main/java/org/stellar/sdk/xdr/LiquidityPoolConstantProductParameters.java b/src/main/java/org/stellar/sdk/xdr/LiquidityPoolConstantProductParameters.java index 32dc06c3b..8b5b40eb1 100644 --- a/src/main/java/org/stellar/sdk/xdr/LiquidityPoolConstantProductParameters.java +++ b/src/main/java/org/stellar/sdk/xdr/LiquidityPoolConstantProductParameters.java @@ -14,7 +14,7 @@ // { // Asset assetA; // assetA < assetB // Asset assetB; -// int32 fee; // Fee is in basis points, so the actual rate is (fee/100)% +// int32 fee; // Fee is in basis points, so the actual rate is (fee/100)% // }; // =========================================================================== diff --git a/src/main/java/org/stellar/sdk/xdr/LiquidityPoolDepositOp.java b/src/main/java/org/stellar/sdk/xdr/LiquidityPoolDepositOp.java index 5d5ff5a1d..04816194e 100644 --- a/src/main/java/org/stellar/sdk/xdr/LiquidityPoolDepositOp.java +++ b/src/main/java/org/stellar/sdk/xdr/LiquidityPoolDepositOp.java @@ -13,10 +13,10 @@ // struct LiquidityPoolDepositOp // { // PoolID liquidityPoolID; -// int64 maxAmountA; // maximum amount of first asset to deposit -// int64 maxAmountB; // maximum amount of second asset to deposit -// Price minPrice; // minimum depositA/depositB -// Price maxPrice; // maximum depositA/depositB +// int64 maxAmountA; // maximum amount of first asset to deposit +// int64 maxAmountB; // maximum amount of second asset to deposit +// Price minPrice; // minimum depositA/depositB +// Price maxPrice; // maximum depositA/depositB // }; // =========================================================================== diff --git a/src/main/java/org/stellar/sdk/xdr/LiquidityPoolDepositResult.java b/src/main/java/org/stellar/sdk/xdr/LiquidityPoolDepositResult.java index 0cffdd31f..c285fc7ba 100644 --- a/src/main/java/org/stellar/sdk/xdr/LiquidityPoolDepositResult.java +++ b/src/main/java/org/stellar/sdk/xdr/LiquidityPoolDepositResult.java @@ -10,8 +10,7 @@ // === xdr source ============================================================ -// union LiquidityPoolDepositResult switch ( -// LiquidityPoolDepositResultCode code) +// union LiquidityPoolDepositResult switch (LiquidityPoolDepositResultCode code) // { // case LIQUIDITY_POOL_DEPOSIT_SUCCESS: // void; diff --git a/src/main/java/org/stellar/sdk/xdr/LiquidityPoolEntry.java b/src/main/java/org/stellar/sdk/xdr/LiquidityPoolEntry.java index 205cc6ea1..d1580e5f3 100644 --- a/src/main/java/org/stellar/sdk/xdr/LiquidityPoolEntry.java +++ b/src/main/java/org/stellar/sdk/xdr/LiquidityPoolEntry.java @@ -24,7 +24,8 @@ // int64 reserveA; // amount of A in the pool // int64 reserveB; // amount of B in the pool // int64 totalPoolShares; // total number of pool shares issued -// int64 poolSharesTrustLineCount; // number of trust lines for the associated pool shares +// int64 poolSharesTrustLineCount; // number of trust lines for the +// // associated pool shares // } constantProduct; // } // body; diff --git a/src/main/java/org/stellar/sdk/xdr/LiquidityPoolWithdrawOp.java b/src/main/java/org/stellar/sdk/xdr/LiquidityPoolWithdrawOp.java index ff3a54855..1eefc51f6 100644 --- a/src/main/java/org/stellar/sdk/xdr/LiquidityPoolWithdrawOp.java +++ b/src/main/java/org/stellar/sdk/xdr/LiquidityPoolWithdrawOp.java @@ -13,9 +13,9 @@ // struct LiquidityPoolWithdrawOp // { // PoolID liquidityPoolID; -// int64 amount; // amount of pool shares to withdraw -// int64 minAmountA; // minimum amount of first asset to withdraw -// int64 minAmountB; // minimum amount of second asset to withdraw +// int64 amount; // amount of pool shares to withdraw +// int64 minAmountA; // minimum amount of first asset to withdraw +// int64 minAmountB; // minimum amount of second asset to withdraw // }; // =========================================================================== diff --git a/src/main/java/org/stellar/sdk/xdr/LiquidityPoolWithdrawResult.java b/src/main/java/org/stellar/sdk/xdr/LiquidityPoolWithdrawResult.java index 070ed976d..106fea64a 100644 --- a/src/main/java/org/stellar/sdk/xdr/LiquidityPoolWithdrawResult.java +++ b/src/main/java/org/stellar/sdk/xdr/LiquidityPoolWithdrawResult.java @@ -10,8 +10,7 @@ // === xdr source ============================================================ -// union LiquidityPoolWithdrawResult switch ( -// LiquidityPoolWithdrawResultCode code) +// union LiquidityPoolWithdrawResult switch (LiquidityPoolWithdrawResultCode code) // { // case LIQUIDITY_POOL_WITHDRAW_SUCCESS: // void; diff --git a/src/main/java/org/stellar/sdk/xdr/LiquidityPoolWithdrawResultCode.java b/src/main/java/org/stellar/sdk/xdr/LiquidityPoolWithdrawResultCode.java index dd8b95831..86b5d564a 100644 --- a/src/main/java/org/stellar/sdk/xdr/LiquidityPoolWithdrawResultCode.java +++ b/src/main/java/org/stellar/sdk/xdr/LiquidityPoolWithdrawResultCode.java @@ -15,14 +15,14 @@ // LIQUIDITY_POOL_WITHDRAW_SUCCESS = 0, // // // codes considered as "failure" for the operation -// LIQUIDITY_POOL_WITHDRAW_MALFORMED = -1, // bad input -// LIQUIDITY_POOL_WITHDRAW_NO_TRUST = -2, // no trust line for one of the -// // assets -// LIQUIDITY_POOL_WITHDRAW_UNDERFUNDED = -3, // not enough balance of the -// // pool share -// LIQUIDITY_POOL_WITHDRAW_LINE_FULL = -4, // would go above limit for one -// // of the assets -// LIQUIDITY_POOL_WITHDRAW_UNDER_MINIMUM = -5 // didn't withdraw enough +// LIQUIDITY_POOL_WITHDRAW_MALFORMED = -1, // bad input +// LIQUIDITY_POOL_WITHDRAW_NO_TRUST = -2, // no trust line for one of the +// // assets +// LIQUIDITY_POOL_WITHDRAW_UNDERFUNDED = -3, // not enough balance of the +// // pool share +// LIQUIDITY_POOL_WITHDRAW_LINE_FULL = -4, // would go above limit for one +// // of the assets +// LIQUIDITY_POOL_WITHDRAW_UNDER_MINIMUM = -5 // didn't withdraw enough // }; // =========================================================================== diff --git a/src/main/java/org/stellar/sdk/xdr/MessageType.java b/src/main/java/org/stellar/sdk/xdr/MessageType.java index c0278ebed..dfd269193 100644 --- a/src/main/java/org/stellar/sdk/xdr/MessageType.java +++ b/src/main/java/org/stellar/sdk/xdr/MessageType.java @@ -33,7 +33,9 @@ // HELLO = 13, // // SURVEY_REQUEST = 14, -// SURVEY_RESPONSE = 15 +// SURVEY_RESPONSE = 15, +// +// SEND_MORE = 16 // }; // =========================================================================== @@ -53,6 +55,7 @@ public enum MessageType implements XdrElement { HELLO(13), SURVEY_REQUEST(14), SURVEY_RESPONSE(15), + SEND_MORE(16), ; private int mValue; @@ -82,6 +85,7 @@ public static MessageType decode(XdrDataInputStream stream) throws IOException { case 13: return HELLO; case 14: return SURVEY_REQUEST; case 15: return SURVEY_RESPONSE; + case 16: return SEND_MORE; default: throw new RuntimeException("Unknown enum value: " + value); } diff --git a/src/main/java/org/stellar/sdk/xdr/OfferEntryFlags.java b/src/main/java/org/stellar/sdk/xdr/OfferEntryFlags.java index 3aa9758f6..3c55d31bd 100644 --- a/src/main/java/org/stellar/sdk/xdr/OfferEntryFlags.java +++ b/src/main/java/org/stellar/sdk/xdr/OfferEntryFlags.java @@ -11,7 +11,8 @@ // enum OfferEntryFlags // { -// // issuer has authorized account to perform transactions with its credit +// // an offer with this flag will not act on and take a reverse offer of equal +// // price // PASSIVE_FLAG = 1 // }; diff --git a/src/main/java/org/stellar/sdk/xdr/PreconditionType.java b/src/main/java/org/stellar/sdk/xdr/PreconditionType.java new file mode 100644 index 000000000..8fa52d098 --- /dev/null +++ b/src/main/java/org/stellar/sdk/xdr/PreconditionType.java @@ -0,0 +1,53 @@ +// Automatically generated by xdrgen +// DO NOT EDIT or your changes may be overwritten + +package org.stellar.sdk.xdr; + + +import java.io.IOException; + + +// === xdr source ============================================================ + +// enum PreconditionType +// { +// PRECOND_NONE = 0, +// PRECOND_TIME = 1, +// PRECOND_V2 = 2 +// }; + +// =========================================================================== +public enum PreconditionType implements XdrElement { + PRECOND_NONE(0), + PRECOND_TIME(1), + PRECOND_V2(2), + ; + private int mValue; + + PreconditionType(int value) { + mValue = value; + } + + public int getValue() { + return mValue; + } + + public static PreconditionType decode(XdrDataInputStream stream) throws IOException { + int value = stream.readInt(); + switch (value) { + case 0: return PRECOND_NONE; + case 1: return PRECOND_TIME; + case 2: return PRECOND_V2; + default: + throw new RuntimeException("Unknown enum value: " + value); + } + } + + public static void encode(XdrDataOutputStream stream, PreconditionType value) throws IOException { + stream.writeInt(value.getValue()); + } + + public void encode(XdrDataOutputStream stream) throws IOException { + encode(stream, this); + } +} diff --git a/src/main/java/org/stellar/sdk/xdr/Preconditions.java b/src/main/java/org/stellar/sdk/xdr/Preconditions.java new file mode 100644 index 000000000..200775af8 --- /dev/null +++ b/src/main/java/org/stellar/sdk/xdr/Preconditions.java @@ -0,0 +1,124 @@ +// Automatically generated by xdrgen +// DO NOT EDIT or your changes may be overwritten + +package org.stellar.sdk.xdr; + + +import java.io.IOException; + +import com.google.common.base.Objects; + +// === xdr source ============================================================ + +// union Preconditions switch (PreconditionType type) +// { +// case PRECOND_NONE: +// void; +// case PRECOND_TIME: +// TimeBounds timeBounds; +// case PRECOND_V2: +// PreconditionsV2 v2; +// }; + +// =========================================================================== +public class Preconditions implements XdrElement { + public Preconditions () {} + PreconditionType type; + public PreconditionType getDiscriminant() { + return this.type; + } + public void setDiscriminant(PreconditionType value) { + this.type = value; + } + private TimeBounds timeBounds; + public TimeBounds getTimeBounds() { + return this.timeBounds; + } + public void setTimeBounds(TimeBounds value) { + this.timeBounds = value; + } + private PreconditionsV2 v2; + public PreconditionsV2 getV2() { + return this.v2; + } + public void setV2(PreconditionsV2 value) { + this.v2 = value; + } + + public static final class Builder { + private PreconditionType discriminant; + private TimeBounds timeBounds; + private PreconditionsV2 v2; + + public Builder discriminant(PreconditionType discriminant) { + this.discriminant = discriminant; + return this; + } + + public Builder timeBounds(TimeBounds timeBounds) { + this.timeBounds = timeBounds; + return this; + } + + public Builder v2(PreconditionsV2 v2) { + this.v2 = v2; + return this; + } + + public Preconditions build() { + Preconditions val = new Preconditions(); + val.setDiscriminant(discriminant); + val.setTimeBounds(timeBounds); + val.setV2(v2); + return val; + } + } + + public static void encode(XdrDataOutputStream stream, Preconditions encodedPreconditions) throws IOException { + //Xdrgen::AST::Identifier + //PreconditionType + stream.writeInt(encodedPreconditions.getDiscriminant().getValue()); + switch (encodedPreconditions.getDiscriminant()) { + case PRECOND_NONE: + break; + case PRECOND_TIME: + TimeBounds.encode(stream, encodedPreconditions.timeBounds); + break; + case PRECOND_V2: + PreconditionsV2.encode(stream, encodedPreconditions.v2); + break; + } + } + public void encode(XdrDataOutputStream stream) throws IOException { + encode(stream, this); + } + public static Preconditions decode(XdrDataInputStream stream) throws IOException { + Preconditions decodedPreconditions = new Preconditions(); + PreconditionType discriminant = PreconditionType.decode(stream); + decodedPreconditions.setDiscriminant(discriminant); + switch (decodedPreconditions.getDiscriminant()) { + case PRECOND_NONE: + break; + case PRECOND_TIME: + decodedPreconditions.timeBounds = TimeBounds.decode(stream); + break; + case PRECOND_V2: + decodedPreconditions.v2 = PreconditionsV2.decode(stream); + break; + } + return decodedPreconditions; + } + @Override + public int hashCode() { + return Objects.hashCode(this.timeBounds, this.v2, this.type); + } + @Override + public boolean equals(Object object) { + if (!(object instanceof Preconditions)) { + return false; + } + + Preconditions other = (Preconditions) object; + return Objects.equal(this.timeBounds, other.timeBounds) && Objects.equal(this.v2, other.v2) && Objects.equal(this.type, other.type); + } +} diff --git a/src/main/java/org/stellar/sdk/xdr/PreconditionsV2.java b/src/main/java/org/stellar/sdk/xdr/PreconditionsV2.java new file mode 100644 index 000000000..545881019 --- /dev/null +++ b/src/main/java/org/stellar/sdk/xdr/PreconditionsV2.java @@ -0,0 +1,208 @@ +// Automatically generated by xdrgen +// DO NOT EDIT or your changes may be overwritten + +package org.stellar.sdk.xdr; + + +import java.io.IOException; + +import com.google.common.base.Objects; +import java.util.Arrays; + +// === xdr source ============================================================ + +// struct PreconditionsV2 +// { +// TimeBounds* timeBounds; +// +// // Transaction only valid for ledger numbers n such that +// // minLedger <= n < maxLedger (if maxLedger == 0, then +// // only minLedger is checked) +// LedgerBounds* ledgerBounds; +// +// // If NULL, only valid when sourceAccount's sequence number +// // is seqNum - 1. Otherwise, valid when sourceAccount's +// // sequence number n satisfies minSeqNum <= n < tx.seqNum. +// // Note that after execution the account's sequence number +// // is always raised to tx.seqNum, and a transaction is not +// // valid if tx.seqNum is too high to ensure replay protection. +// SequenceNumber* minSeqNum; +// +// // For the transaction to be valid, the current ledger time must +// // be at least minSeqAge greater than sourceAccount's seqTime. +// Duration minSeqAge; +// +// // For the transaction to be valid, the current ledger number +// // must be at least minSeqLedgerGap greater than sourceAccount's +// // seqLedger. +// uint32 minSeqLedgerGap; +// +// // For the transaction to be valid, there must be a signature +// // corresponding to every Signer in this array, even if the +// // signature is not otherwise required by the sourceAccount or +// // operations. +// SignerKey extraSigners<2>; +// }; + +// =========================================================================== +public class PreconditionsV2 implements XdrElement { + public PreconditionsV2 () {} + private TimeBounds timeBounds; + public TimeBounds getTimeBounds() { + return this.timeBounds; + } + public void setTimeBounds(TimeBounds value) { + this.timeBounds = value; + } + private LedgerBounds ledgerBounds; + public LedgerBounds getLedgerBounds() { + return this.ledgerBounds; + } + public void setLedgerBounds(LedgerBounds value) { + this.ledgerBounds = value; + } + private SequenceNumber minSeqNum; + public SequenceNumber getMinSeqNum() { + return this.minSeqNum; + } + public void setMinSeqNum(SequenceNumber value) { + this.minSeqNum = value; + } + private Duration minSeqAge; + public Duration getMinSeqAge() { + return this.minSeqAge; + } + public void setMinSeqAge(Duration value) { + this.minSeqAge = value; + } + private Uint32 minSeqLedgerGap; + public Uint32 getMinSeqLedgerGap() { + return this.minSeqLedgerGap; + } + public void setMinSeqLedgerGap(Uint32 value) { + this.minSeqLedgerGap = value; + } + private SignerKey[] extraSigners; + public SignerKey[] getExtraSigners() { + return this.extraSigners; + } + public void setExtraSigners(SignerKey[] value) { + this.extraSigners = value; + } + public static void encode(XdrDataOutputStream stream, PreconditionsV2 encodedPreconditionsV2) throws IOException{ + if (encodedPreconditionsV2.timeBounds != null) { + stream.writeInt(1); + TimeBounds.encode(stream, encodedPreconditionsV2.timeBounds); + } else { + stream.writeInt(0); + } + if (encodedPreconditionsV2.ledgerBounds != null) { + stream.writeInt(1); + LedgerBounds.encode(stream, encodedPreconditionsV2.ledgerBounds); + } else { + stream.writeInt(0); + } + if (encodedPreconditionsV2.minSeqNum != null) { + stream.writeInt(1); + SequenceNumber.encode(stream, encodedPreconditionsV2.minSeqNum); + } else { + stream.writeInt(0); + } + Duration.encode(stream, encodedPreconditionsV2.minSeqAge); + Uint32.encode(stream, encodedPreconditionsV2.minSeqLedgerGap); + int extraSignerssize = encodedPreconditionsV2.getExtraSigners().length; + stream.writeInt(extraSignerssize); + for (int i = 0; i < extraSignerssize; i++) { + SignerKey.encode(stream, encodedPreconditionsV2.extraSigners[i]); + } + } + public void encode(XdrDataOutputStream stream) throws IOException { + encode(stream, this); + } + public static PreconditionsV2 decode(XdrDataInputStream stream) throws IOException { + PreconditionsV2 decodedPreconditionsV2 = new PreconditionsV2(); + int timeBoundsPresent = stream.readInt(); + if (timeBoundsPresent != 0) { + decodedPreconditionsV2.timeBounds = TimeBounds.decode(stream); + } + int ledgerBoundsPresent = stream.readInt(); + if (ledgerBoundsPresent != 0) { + decodedPreconditionsV2.ledgerBounds = LedgerBounds.decode(stream); + } + int minSeqNumPresent = stream.readInt(); + if (minSeqNumPresent != 0) { + decodedPreconditionsV2.minSeqNum = SequenceNumber.decode(stream); + } + decodedPreconditionsV2.minSeqAge = Duration.decode(stream); + decodedPreconditionsV2.minSeqLedgerGap = Uint32.decode(stream); + int extraSignerssize = stream.readInt(); + decodedPreconditionsV2.extraSigners = new SignerKey[extraSignerssize]; + for (int i = 0; i < extraSignerssize; i++) { + decodedPreconditionsV2.extraSigners[i] = SignerKey.decode(stream); + } + return decodedPreconditionsV2; + } + @Override + public int hashCode() { + return Objects.hashCode(this.timeBounds, this.ledgerBounds, this.minSeqNum, this.minSeqAge, this.minSeqLedgerGap, Arrays.hashCode(this.extraSigners)); + } + @Override + public boolean equals(Object object) { + if (!(object instanceof PreconditionsV2)) { + return false; + } + + PreconditionsV2 other = (PreconditionsV2) object; + return Objects.equal(this.timeBounds, other.timeBounds) && Objects.equal(this.ledgerBounds, other.ledgerBounds) && Objects.equal(this.minSeqNum, other.minSeqNum) && Objects.equal(this.minSeqAge, other.minSeqAge) && Objects.equal(this.minSeqLedgerGap, other.minSeqLedgerGap) && Arrays.equals(this.extraSigners, other.extraSigners); + } + + public static final class Builder { + private TimeBounds timeBounds; + private LedgerBounds ledgerBounds; + private SequenceNumber minSeqNum; + private Duration minSeqAge; + private Uint32 minSeqLedgerGap; + private SignerKey[] extraSigners; + + public Builder timeBounds(TimeBounds timeBounds) { + this.timeBounds = timeBounds; + return this; + } + + public Builder ledgerBounds(LedgerBounds ledgerBounds) { + this.ledgerBounds = ledgerBounds; + return this; + } + + public Builder minSeqNum(SequenceNumber minSeqNum) { + this.minSeqNum = minSeqNum; + return this; + } + + public Builder minSeqAge(Duration minSeqAge) { + this.minSeqAge = minSeqAge; + return this; + } + + public Builder minSeqLedgerGap(Uint32 minSeqLedgerGap) { + this.minSeqLedgerGap = minSeqLedgerGap; + return this; + } + + public Builder extraSigners(SignerKey[] extraSigners) { + this.extraSigners = extraSigners; + return this; + } + + public PreconditionsV2 build() { + PreconditionsV2 val = new PreconditionsV2(); + val.setTimeBounds(timeBounds); + val.setLedgerBounds(ledgerBounds); + val.setMinSeqNum(minSeqNum); + val.setMinSeqAge(minSeqAge); + val.setMinSeqLedgerGap(minSeqLedgerGap); + val.setExtraSigners(extraSigners); + return val; + } + } +} diff --git a/src/main/java/org/stellar/sdk/xdr/SendMore.java b/src/main/java/org/stellar/sdk/xdr/SendMore.java new file mode 100644 index 000000000..72b2cc9e7 --- /dev/null +++ b/src/main/java/org/stellar/sdk/xdr/SendMore.java @@ -0,0 +1,67 @@ +// Automatically generated by xdrgen +// DO NOT EDIT or your changes may be overwritten + +package org.stellar.sdk.xdr; + + +import java.io.IOException; + +import com.google.common.base.Objects; + +// === xdr source ============================================================ + +// struct SendMore +// { +// uint32 numMessages; +// }; + +// =========================================================================== +public class SendMore implements XdrElement { + public SendMore () {} + private Uint32 numMessages; + public Uint32 getNumMessages() { + return this.numMessages; + } + public void setNumMessages(Uint32 value) { + this.numMessages = value; + } + public static void encode(XdrDataOutputStream stream, SendMore encodedSendMore) throws IOException{ + Uint32.encode(stream, encodedSendMore.numMessages); + } + public void encode(XdrDataOutputStream stream) throws IOException { + encode(stream, this); + } + public static SendMore decode(XdrDataInputStream stream) throws IOException { + SendMore decodedSendMore = new SendMore(); + decodedSendMore.numMessages = Uint32.decode(stream); + return decodedSendMore; + } + @Override + public int hashCode() { + return Objects.hashCode(this.numMessages); + } + @Override + public boolean equals(Object object) { + if (!(object instanceof SendMore)) { + return false; + } + + SendMore other = (SendMore) object; + return Objects.equal(this.numMessages, other.numMessages); + } + + public static final class Builder { + private Uint32 numMessages; + + public Builder numMessages(Uint32 numMessages) { + this.numMessages = numMessages; + return this; + } + + public SendMore build() { + SendMore val = new SendMore(); + val.setNumMessages(numMessages); + return val; + } + } +} diff --git a/src/main/java/org/stellar/sdk/xdr/SignerKey.java b/src/main/java/org/stellar/sdk/xdr/SignerKey.java index 98a9d64bd..b8ea88953 100644 --- a/src/main/java/org/stellar/sdk/xdr/SignerKey.java +++ b/src/main/java/org/stellar/sdk/xdr/SignerKey.java @@ -7,6 +7,7 @@ import java.io.IOException; import com.google.common.base.Objects; +import java.util.Arrays; // === xdr source ============================================================ @@ -20,6 +21,14 @@ // case SIGNER_KEY_TYPE_HASH_X: // /* Hash of random 256 bit preimage X */ // uint256 hashX; +// case SIGNER_KEY_TYPE_ED25519_SIGNED_PAYLOAD: +// struct +// { +// /* Public key that must sign the payload. */ +// uint256 ed25519; +// /* Payload to be raw signed by ed25519. */ +// opaque payload<64>; +// } ed25519SignedPayload; // }; // =========================================================================== @@ -53,12 +62,20 @@ public Uint256 getHashX() { public void setHashX(Uint256 value) { this.hashX = value; } + private SignerKeyEd25519SignedPayload ed25519SignedPayload; + public SignerKeyEd25519SignedPayload getEd25519SignedPayload() { + return this.ed25519SignedPayload; + } + public void setEd25519SignedPayload(SignerKeyEd25519SignedPayload value) { + this.ed25519SignedPayload = value; + } public static final class Builder { private SignerKeyType discriminant; private Uint256 ed25519; private Uint256 preAuthTx; private Uint256 hashX; + private SignerKeyEd25519SignedPayload ed25519SignedPayload; public Builder discriminant(SignerKeyType discriminant) { this.discriminant = discriminant; @@ -80,12 +97,18 @@ public Builder hashX(Uint256 hashX) { return this; } + public Builder ed25519SignedPayload(SignerKeyEd25519SignedPayload ed25519SignedPayload) { + this.ed25519SignedPayload = ed25519SignedPayload; + return this; + } + public SignerKey build() { SignerKey val = new SignerKey(); val.setDiscriminant(discriminant); val.setEd25519(ed25519); val.setPreAuthTx(preAuthTx); val.setHashX(hashX); + val.setEd25519SignedPayload(ed25519SignedPayload); return val; } } @@ -104,6 +127,9 @@ public static void encode(XdrDataOutputStream stream, SignerKey encodedSignerKey case SIGNER_KEY_TYPE_HASH_X: Uint256.encode(stream, encodedSignerKey.hashX); break; + case SIGNER_KEY_TYPE_ED25519_SIGNED_PAYLOAD: + SignerKeyEd25519SignedPayload.encode(stream, encodedSignerKey.ed25519SignedPayload); + break; } } public void encode(XdrDataOutputStream stream) throws IOException { @@ -123,12 +149,15 @@ public static SignerKey decode(XdrDataInputStream stream) throws IOException { case SIGNER_KEY_TYPE_HASH_X: decodedSignerKey.hashX = Uint256.decode(stream); break; + case SIGNER_KEY_TYPE_ED25519_SIGNED_PAYLOAD: + decodedSignerKey.ed25519SignedPayload = SignerKeyEd25519SignedPayload.decode(stream); + break; } return decodedSignerKey; } @Override public int hashCode() { - return Objects.hashCode(this.ed25519, this.preAuthTx, this.hashX, this.type); + return Objects.hashCode(this.ed25519, this.preAuthTx, this.hashX, this.ed25519SignedPayload, this.type); } @Override public boolean equals(Object object) { @@ -137,6 +166,77 @@ public boolean equals(Object object) { } SignerKey other = (SignerKey) object; - return Objects.equal(this.ed25519, other.ed25519) && Objects.equal(this.preAuthTx, other.preAuthTx) && Objects.equal(this.hashX, other.hashX) && Objects.equal(this.type, other.type); + return Objects.equal(this.ed25519, other.ed25519) && Objects.equal(this.preAuthTx, other.preAuthTx) && Objects.equal(this.hashX, other.hashX) && Objects.equal(this.ed25519SignedPayload, other.ed25519SignedPayload) && Objects.equal(this.type, other.type); + } + + public static class SignerKeyEd25519SignedPayload { + public SignerKeyEd25519SignedPayload () {} + private Uint256 ed25519; + public Uint256 getEd25519() { + return this.ed25519; + } + public void setEd25519(Uint256 value) { + this.ed25519 = value; + } + private byte[] payload; + public byte[] getPayload() { + return this.payload; + } + public void setPayload(byte[] value) { + this.payload = value; + } + public static void encode(XdrDataOutputStream stream, SignerKeyEd25519SignedPayload encodedSignerKeyEd25519SignedPayload) throws IOException{ + Uint256.encode(stream, encodedSignerKeyEd25519SignedPayload.ed25519); + int payloadsize = encodedSignerKeyEd25519SignedPayload.payload.length; + stream.writeInt(payloadsize); + stream.write(encodedSignerKeyEd25519SignedPayload.getPayload(), 0, payloadsize); + } + public void encode(XdrDataOutputStream stream) throws IOException { + encode(stream, this); + } + public static SignerKeyEd25519SignedPayload decode(XdrDataInputStream stream) throws IOException { + SignerKeyEd25519SignedPayload decodedSignerKeyEd25519SignedPayload = new SignerKeyEd25519SignedPayload(); + decodedSignerKeyEd25519SignedPayload.ed25519 = Uint256.decode(stream); + int payloadsize = stream.readInt(); + decodedSignerKeyEd25519SignedPayload.payload = new byte[payloadsize]; + stream.read(decodedSignerKeyEd25519SignedPayload.payload, 0, payloadsize); + return decodedSignerKeyEd25519SignedPayload; + } + @Override + public int hashCode() { + return Objects.hashCode(this.ed25519, Arrays.hashCode(this.payload)); + } + @Override + public boolean equals(Object object) { + if (!(object instanceof SignerKeyEd25519SignedPayload)) { + return false; + } + + SignerKeyEd25519SignedPayload other = (SignerKeyEd25519SignedPayload) object; + return Objects.equal(this.ed25519, other.ed25519) && Arrays.equals(this.payload, other.payload); + } + + public static final class Builder { + private Uint256 ed25519; + private byte[] payload; + + public Builder ed25519(Uint256 ed25519) { + this.ed25519 = ed25519; + return this; + } + + public Builder payload(byte[] payload) { + this.payload = payload; + return this; + } + + public SignerKeyEd25519SignedPayload build() { + SignerKeyEd25519SignedPayload val = new SignerKeyEd25519SignedPayload(); + val.setEd25519(ed25519); + val.setPayload(payload); + return val; + } + } + } } diff --git a/src/main/java/org/stellar/sdk/xdr/SignerKeyType.java b/src/main/java/org/stellar/sdk/xdr/SignerKeyType.java index d5e610028..4000eaf2e 100644 --- a/src/main/java/org/stellar/sdk/xdr/SignerKeyType.java +++ b/src/main/java/org/stellar/sdk/xdr/SignerKeyType.java @@ -13,7 +13,8 @@ // { // SIGNER_KEY_TYPE_ED25519 = KEY_TYPE_ED25519, // SIGNER_KEY_TYPE_PRE_AUTH_TX = KEY_TYPE_PRE_AUTH_TX, -// SIGNER_KEY_TYPE_HASH_X = KEY_TYPE_HASH_X +// SIGNER_KEY_TYPE_HASH_X = KEY_TYPE_HASH_X, +// SIGNER_KEY_TYPE_ED25519_SIGNED_PAYLOAD = KEY_TYPE_ED25519_SIGNED_PAYLOAD // }; // =========================================================================== @@ -21,6 +22,7 @@ public enum SignerKeyType implements XdrElement { SIGNER_KEY_TYPE_ED25519(0), SIGNER_KEY_TYPE_PRE_AUTH_TX(1), SIGNER_KEY_TYPE_HASH_X(2), + SIGNER_KEY_TYPE_ED25519_SIGNED_PAYLOAD(3), ; private int mValue; @@ -38,6 +40,7 @@ public static SignerKeyType decode(XdrDataInputStream stream) throws IOException case 0: return SIGNER_KEY_TYPE_ED25519; case 1: return SIGNER_KEY_TYPE_PRE_AUTH_TX; case 2: return SIGNER_KEY_TYPE_HASH_X; + case 3: return SIGNER_KEY_TYPE_ED25519_SIGNED_PAYLOAD; default: throw new RuntimeException("Unknown enum value: " + value); } diff --git a/src/main/java/org/stellar/sdk/xdr/StellarMessage.java b/src/main/java/org/stellar/sdk/xdr/StellarMessage.java index 0048adb27..8ac2536ca 100644 --- a/src/main/java/org/stellar/sdk/xdr/StellarMessage.java +++ b/src/main/java/org/stellar/sdk/xdr/StellarMessage.java @@ -49,6 +49,8 @@ // SCPEnvelope envelope; // case GET_SCP_STATE: // uint32 getSCPLedgerSeq; // ledger seq requested ; if 0, requests the latest +// case SEND_MORE: +// SendMore sendMoreMessage; // }; // =========================================================================== @@ -159,6 +161,13 @@ public Uint32 getGetSCPLedgerSeq() { public void setGetSCPLedgerSeq(Uint32 value) { this.getSCPLedgerSeq = value; } + private SendMore sendMoreMessage; + public SendMore getSendMoreMessage() { + return this.sendMoreMessage; + } + public void setSendMoreMessage(SendMore value) { + this.sendMoreMessage = value; + } public static final class Builder { private MessageType discriminant; @@ -176,6 +185,7 @@ public static final class Builder { private SCPQuorumSet qSet; private SCPEnvelope envelope; private Uint32 getSCPLedgerSeq; + private SendMore sendMoreMessage; public Builder discriminant(MessageType discriminant) { this.discriminant = discriminant; @@ -252,6 +262,11 @@ public Builder getSCPLedgerSeq(Uint32 getSCPLedgerSeq) { return this; } + public Builder sendMoreMessage(SendMore sendMoreMessage) { + this.sendMoreMessage = sendMoreMessage; + return this; + } + public StellarMessage build() { StellarMessage val = new StellarMessage(); val.setDiscriminant(discriminant); @@ -269,6 +284,7 @@ public StellarMessage build() { val.setQSet(qSet); val.setEnvelope(envelope); val.setGetSCPLedgerSeq(getSCPLedgerSeq); + val.setSendMoreMessage(sendMoreMessage); return val; } } @@ -326,6 +342,9 @@ public static void encode(XdrDataOutputStream stream, StellarMessage encodedStel case GET_SCP_STATE: Uint32.encode(stream, encodedStellarMessage.getSCPLedgerSeq); break; + case SEND_MORE: + SendMore.encode(stream, encodedStellarMessage.sendMoreMessage); + break; } } public void encode(XdrDataOutputStream stream) throws IOException { @@ -384,12 +403,15 @@ public static StellarMessage decode(XdrDataInputStream stream) throws IOExceptio case GET_SCP_STATE: decodedStellarMessage.getSCPLedgerSeq = Uint32.decode(stream); break; + case SEND_MORE: + decodedStellarMessage.sendMoreMessage = SendMore.decode(stream); + break; } return decodedStellarMessage; } @Override public int hashCode() { - return Objects.hashCode(this.error, this.hello, this.auth, this.dontHave, Arrays.hashCode(this.peers), this.txSetHash, this.txSet, this.transaction, this.signedSurveyRequestMessage, this.signedSurveyResponseMessage, this.qSetHash, this.qSet, this.envelope, this.getSCPLedgerSeq, this.type); + return Objects.hashCode(this.error, this.hello, this.auth, this.dontHave, Arrays.hashCode(this.peers), this.txSetHash, this.txSet, this.transaction, this.signedSurveyRequestMessage, this.signedSurveyResponseMessage, this.qSetHash, this.qSet, this.envelope, this.getSCPLedgerSeq, this.sendMoreMessage, this.type); } @Override public boolean equals(Object object) { @@ -398,6 +420,6 @@ public boolean equals(Object object) { } StellarMessage other = (StellarMessage) object; - return Objects.equal(this.error, other.error) && Objects.equal(this.hello, other.hello) && Objects.equal(this.auth, other.auth) && Objects.equal(this.dontHave, other.dontHave) && Arrays.equals(this.peers, other.peers) && Objects.equal(this.txSetHash, other.txSetHash) && Objects.equal(this.txSet, other.txSet) && Objects.equal(this.transaction, other.transaction) && Objects.equal(this.signedSurveyRequestMessage, other.signedSurveyRequestMessage) && Objects.equal(this.signedSurveyResponseMessage, other.signedSurveyResponseMessage) && Objects.equal(this.qSetHash, other.qSetHash) && Objects.equal(this.qSet, other.qSet) && Objects.equal(this.envelope, other.envelope) && Objects.equal(this.getSCPLedgerSeq, other.getSCPLedgerSeq) && Objects.equal(this.type, other.type); + return Objects.equal(this.error, other.error) && Objects.equal(this.hello, other.hello) && Objects.equal(this.auth, other.auth) && Objects.equal(this.dontHave, other.dontHave) && Arrays.equals(this.peers, other.peers) && Objects.equal(this.txSetHash, other.txSetHash) && Objects.equal(this.txSet, other.txSet) && Objects.equal(this.transaction, other.transaction) && Objects.equal(this.signedSurveyRequestMessage, other.signedSurveyRequestMessage) && Objects.equal(this.signedSurveyResponseMessage, other.signedSurveyResponseMessage) && Objects.equal(this.qSetHash, other.qSetHash) && Objects.equal(this.qSet, other.qSet) && Objects.equal(this.envelope, other.envelope) && Objects.equal(this.getSCPLedgerSeq, other.getSCPLedgerSeq) && Objects.equal(this.sendMoreMessage, other.sendMoreMessage) && Objects.equal(this.type, other.type); } } diff --git a/src/main/java/org/stellar/sdk/xdr/StellarValue.java b/src/main/java/org/stellar/sdk/xdr/StellarValue.java index 6954c7e9c..7fd7f1640 100644 --- a/src/main/java/org/stellar/sdk/xdr/StellarValue.java +++ b/src/main/java/org/stellar/sdk/xdr/StellarValue.java @@ -20,7 +20,7 @@ // // this is a vector of encoded 'LedgerUpgrade' so that nodes can drop // // unknown steps during consensus if needed. // // see notes below on 'LedgerUpgrade' for more detail -// // max size is dictated by number of upgrade types ( room for future) +// // max size is dictated by number of upgrade types (+ room for future) // UpgradeType upgrades<6>; // // // reserved for future use diff --git a/src/main/java/org/stellar/sdk/xdr/Transaction.java b/src/main/java/org/stellar/sdk/xdr/Transaction.java index acb2290c9..37b9a7994 100644 --- a/src/main/java/org/stellar/sdk/xdr/Transaction.java +++ b/src/main/java/org/stellar/sdk/xdr/Transaction.java @@ -22,8 +22,8 @@ // // sequence number to consume in the account // SequenceNumber seqNum; // -// // validity range (inclusive) for the last ledger close time -// TimeBounds* timeBounds; +// // validity conditions +// Preconditions cond; // // Memo memo; // @@ -62,12 +62,12 @@ public SequenceNumber getSeqNum() { public void setSeqNum(SequenceNumber value) { this.seqNum = value; } - private TimeBounds timeBounds; - public TimeBounds getTimeBounds() { - return this.timeBounds; + private Preconditions cond; + public Preconditions getCond() { + return this.cond; } - public void setTimeBounds(TimeBounds value) { - this.timeBounds = value; + public void setCond(Preconditions value) { + this.cond = value; } private Memo memo; public Memo getMemo() { @@ -94,12 +94,7 @@ public static void encode(XdrDataOutputStream stream, Transaction encodedTransac MuxedAccount.encode(stream, encodedTransaction.sourceAccount); Uint32.encode(stream, encodedTransaction.fee); SequenceNumber.encode(stream, encodedTransaction.seqNum); - if (encodedTransaction.timeBounds != null) { - stream.writeInt(1); - TimeBounds.encode(stream, encodedTransaction.timeBounds); - } else { - stream.writeInt(0); - } + Preconditions.encode(stream, encodedTransaction.cond); Memo.encode(stream, encodedTransaction.memo); int operationssize = encodedTransaction.getOperations().length; stream.writeInt(operationssize); @@ -116,10 +111,7 @@ public static Transaction decode(XdrDataInputStream stream) throws IOException { decodedTransaction.sourceAccount = MuxedAccount.decode(stream); decodedTransaction.fee = Uint32.decode(stream); decodedTransaction.seqNum = SequenceNumber.decode(stream); - int timeBoundsPresent = stream.readInt(); - if (timeBoundsPresent != 0) { - decodedTransaction.timeBounds = TimeBounds.decode(stream); - } + decodedTransaction.cond = Preconditions.decode(stream); decodedTransaction.memo = Memo.decode(stream); int operationssize = stream.readInt(); decodedTransaction.operations = new Operation[operationssize]; @@ -131,7 +123,7 @@ public static Transaction decode(XdrDataInputStream stream) throws IOException { } @Override public int hashCode() { - return Objects.hashCode(this.sourceAccount, this.fee, this.seqNum, this.timeBounds, this.memo, Arrays.hashCode(this.operations), this.ext); + return Objects.hashCode(this.sourceAccount, this.fee, this.seqNum, this.cond, this.memo, Arrays.hashCode(this.operations), this.ext); } @Override public boolean equals(Object object) { @@ -140,14 +132,14 @@ public boolean equals(Object object) { } Transaction other = (Transaction) object; - return Objects.equal(this.sourceAccount, other.sourceAccount) && Objects.equal(this.fee, other.fee) && Objects.equal(this.seqNum, other.seqNum) && Objects.equal(this.timeBounds, other.timeBounds) && Objects.equal(this.memo, other.memo) && Arrays.equals(this.operations, other.operations) && Objects.equal(this.ext, other.ext); + return Objects.equal(this.sourceAccount, other.sourceAccount) && Objects.equal(this.fee, other.fee) && Objects.equal(this.seqNum, other.seqNum) && Objects.equal(this.cond, other.cond) && Objects.equal(this.memo, other.memo) && Arrays.equals(this.operations, other.operations) && Objects.equal(this.ext, other.ext); } public static final class Builder { private MuxedAccount sourceAccount; private Uint32 fee; private SequenceNumber seqNum; - private TimeBounds timeBounds; + private Preconditions cond; private Memo memo; private Operation[] operations; private TransactionExt ext; @@ -167,8 +159,8 @@ public Builder seqNum(SequenceNumber seqNum) { return this; } - public Builder timeBounds(TimeBounds timeBounds) { - this.timeBounds = timeBounds; + public Builder cond(Preconditions cond) { + this.cond = cond; return this; } @@ -192,7 +184,7 @@ public Transaction build() { val.setSourceAccount(sourceAccount); val.setFee(fee); val.setSeqNum(seqNum); - val.setTimeBounds(timeBounds); + val.setCond(cond); val.setMemo(memo); val.setOperations(operations); val.setExt(ext); diff --git a/src/main/java/org/stellar/sdk/xdr/TransactionResultCode.java b/src/main/java/org/stellar/sdk/xdr/TransactionResultCode.java index ba809fa91..95172b154 100644 --- a/src/main/java/org/stellar/sdk/xdr/TransactionResultCode.java +++ b/src/main/java/org/stellar/sdk/xdr/TransactionResultCode.java @@ -30,7 +30,10 @@ // // txNOT_SUPPORTED = -12, // transaction type not supported // txFEE_BUMP_INNER_FAILED = -13, // fee bump inner transaction failed -// txBAD_SPONSORSHIP = -14 // sponsorship not confirmed +// txBAD_SPONSORSHIP = -14, // sponsorship not confirmed +// txBAD_MIN_SEQ_AGE_OR_GAP = +// -15, // minSeqAge or minSeqLedgerGap conditions not met +// txMALFORMED = -16 // precondition is invalid // }; // =========================================================================== @@ -51,6 +54,8 @@ public enum TransactionResultCode implements XdrElement { txNOT_SUPPORTED(-12), txFEE_BUMP_INNER_FAILED(-13), txBAD_SPONSORSHIP(-14), + txBAD_MIN_SEQ_AGE_OR_GAP(-15), + txMALFORMED(-16), ; private int mValue; @@ -81,6 +86,8 @@ public static TransactionResultCode decode(XdrDataInputStream stream) throws IOE case -12: return txNOT_SUPPORTED; case -13: return txFEE_BUMP_INNER_FAILED; case -14: return txBAD_SPONSORSHIP; + case -15: return txBAD_MIN_SEQ_AGE_OR_GAP; + case -16: return txMALFORMED; default: throw new RuntimeException("Unknown enum value: " + value); } diff --git a/src/main/java/org/stellar/sdk/xdr/TrustLineEntry.java b/src/main/java/org/stellar/sdk/xdr/TrustLineEntry.java index 668c07d37..c22caec9a 100644 --- a/src/main/java/org/stellar/sdk/xdr/TrustLineEntry.java +++ b/src/main/java/org/stellar/sdk/xdr/TrustLineEntry.java @@ -12,10 +12,10 @@ // struct TrustLineEntry // { -// AccountID accountID; // account this trustline belongs to -// TrustLineAsset asset; // type of asset (with issuer) -// int64 balance; // how much of this asset the user has. -// // Asset defines the unit for this; +// AccountID accountID; // account this trustline belongs to +// TrustLineAsset asset; // type of asset (with issuer) +// int64 balance; // how much of this asset the user has. +// // Asset defines the unit for this; // // int64 limit; // balance cannot be above this // uint32 flags; // see TrustLineFlags diff --git a/src/test/java/org/stellar/sdk/ClaimableBalanceIdTest.java b/src/test/java/org/stellar/sdk/ClaimableBalanceIdTest.java index be8e7b1fa..f5b7c8fb7 100644 --- a/src/test/java/org/stellar/sdk/ClaimableBalanceIdTest.java +++ b/src/test/java/org/stellar/sdk/ClaimableBalanceIdTest.java @@ -26,11 +26,11 @@ public void testClaimableBalanceIds() throws IOException { new Predicate.Unconditional() ) )).build(); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), new Account(sourceAccount, 123l), Network.TESTNET) + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), new Account(sourceAccount, 123l), Network.TESTNET) .addOperation(op0) .addOperation(new BumpSequenceOperation.Builder(2l).build()) .addOperation(op0) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) .setBaseFee(Transaction.MIN_BASE_FEE) .build(); @@ -51,18 +51,18 @@ public void testClaimableBalanceIds() throws IOException { new Predicate.Unconditional() ) )).setSourceAccount("GABXJTV7ELEB2TQZKJYEGXBUIG6QODJULKJDI65KZMIZZG2EACJU5EA7").build(); - transaction = new Transaction.Builder(AccountConverter.enableMuxed(), new Account(sourceAccount, 123l), Network.TESTNET) + transaction = new TransactionBuilder(AccountConverter.enableMuxed(), new Account(sourceAccount, 123l), Network.TESTNET) .addOperation(opWithSourceAccount) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) .setBaseFee(Transaction.MIN_BASE_FEE) .build(); // operation source account does not affect claimable balance id assertEquals(expectedIdIndex0, transaction.getClaimableBalanceId(0)); - transaction = new Transaction.Builder(AccountConverter.enableMuxed(), new Account(sourceAccount, 124l), Network.TESTNET) + transaction = new TransactionBuilder(AccountConverter.enableMuxed(), new Account(sourceAccount, 124l), Network.TESTNET) .addOperation(opWithSourceAccount) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) .setBaseFee(Transaction.MIN_BASE_FEE) .build(); @@ -78,10 +78,10 @@ public void testClaimableBalanceIds() throws IOException { muxedAccount.setMed25519(med); - transaction = new Transaction.Builder(AccountConverter.enableMuxed(), new Account(StrKey.encodeStellarMuxedAccount(muxedAccount), 123l), Network.TESTNET) + transaction = new TransactionBuilder(AccountConverter.enableMuxed(), new Account(StrKey.encodeStellarMuxedAccount(muxedAccount), 123l), Network.TESTNET) .addOperation(op0) .addOperation(new BumpSequenceOperation.Builder(2l).build()) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) .setBaseFee(Transaction.MIN_BASE_FEE) .build(); diff --git a/src/test/java/org/stellar/sdk/FeeBumpTransactionTest.java b/src/test/java/org/stellar/sdk/FeeBumpTransactionTest.java index 5d3a5753e..c2ae03995 100644 --- a/src/test/java/org/stellar/sdk/FeeBumpTransactionTest.java +++ b/src/test/java/org/stellar/sdk/FeeBumpTransactionTest.java @@ -5,7 +5,9 @@ import java.io.IOException; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.fail; public class FeeBumpTransactionTest { @@ -13,7 +15,7 @@ private Transaction createInnerTransaction(int baseFee) { KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); Account account = new Account(source.getAccountId(), 2908908335136768L); - Transaction inner = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.TESTNET) + Transaction inner = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) .addOperation(new PaymentOperation.Builder( "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ", new AssetTypeNative(), diff --git a/src/test/java/org/stellar/sdk/KeyPairTest.java b/src/test/java/org/stellar/sdk/KeyPairTest.java index 54d087477..2d9b661f4 100644 --- a/src/test/java/org/stellar/sdk/KeyPairTest.java +++ b/src/test/java/org/stellar/sdk/KeyPairTest.java @@ -2,11 +2,15 @@ import org.junit.Assert; import org.junit.Test; +import org.stellar.sdk.xdr.DecoratedSignature; import java.util.HashMap; import java.util.Map; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; public class KeyPairTest { @@ -86,4 +90,26 @@ public void testSignWithoutSecret() { assertEquals("KeyPair does not contain secret key. Use KeyPair.fromSecretSeed method to create a new KeyPair with a secret key.", e.getMessage()); } } + + @Test + public void testSignPayloadSigner() { + KeyPair keypair = KeyPair.fromSecretSeed(Util.hexToBytes(SEED)); + // the hint from this keypair is [254,66,4,55] + + byte[] payload = new byte[]{1,2,3,4,5}; + DecoratedSignature sig = keypair.signPayloadDecorated(payload); + Assert.assertArrayEquals(sig.getHint().getSignatureHint(), new byte[]{(byte)(0xFF & 252), 65, 0, 50}); + + } + + @Test + public void testSignPayloadSignerLessThanHint() { + KeyPair keypair = KeyPair.fromSecretSeed(Util.hexToBytes(SEED)); + // the hint from this keypair is [254,66,4,55] + + byte[] payload = new byte[]{1,2,3}; + DecoratedSignature sig = keypair.signPayloadDecorated(payload); + // the hint could only be derived off of 3 bytes from payload + Assert.assertArrayEquals(sig.getHint().getSignatureHint(), new byte[]{(byte)(255), 64, 7, 55}); + } } diff --git a/src/test/java/org/stellar/sdk/OperationTest.java b/src/test/java/org/stellar/sdk/OperationTest.java index 4d8531355..c3faec2a2 100644 --- a/src/test/java/org/stellar/sdk/OperationTest.java +++ b/src/test/java/org/stellar/sdk/OperationTest.java @@ -1,13 +1,12 @@ package org.stellar.sdk; import com.google.common.collect.Lists; +import com.google.common.io.BaseEncoding; import org.junit.Test; import org.stellar.sdk.xdr.SignerKey; import org.stellar.sdk.xdr.TrustLineFlags; import org.stellar.sdk.xdr.XdrDataInputStream; -import com.google.common.io.BaseEncoding; - import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.Arrays; @@ -518,9 +517,9 @@ public void testSetOptionsOperationPreAuthTxSigner() { long sequenceNumber = 2908908335136768L; Account account = new Account(source.getAccountId(), sequenceNumber); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.TESTNET) + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) .setBaseFee(Transaction.MIN_BASE_FEE) .build(); @@ -535,21 +534,17 @@ public void testSetOptionsOperationPreAuthTxSigner() { org.stellar.sdk.xdr.Operation xdr = operation.toXdr(AccountConverter.enableMuxed()); SetOptionsOperation parsedOperation = (SetOptionsOperation) SetOptionsOperation.fromXdr(AccountConverter.enableMuxed(), xdr); - assertEquals(null, parsedOperation.getInflationDestination()); - assertEquals(null, parsedOperation.getClearFlags()); - assertEquals(null, parsedOperation.getSetFlags()); - assertEquals(null, parsedOperation.getMasterKeyWeight()); - assertEquals(null, parsedOperation.getLowThreshold()); - assertEquals(null, parsedOperation.getMediumThreshold()); - assertEquals(null, parsedOperation.getHighThreshold()); - assertEquals(null, parsedOperation.getHomeDomain()); + assertEquals(operation.getInflationDestination(), parsedOperation.getInflationDestination()); + assertEquals(operation.getClearFlags(), parsedOperation.getClearFlags()); + assertEquals(operation.getSetFlags(), parsedOperation.getSetFlags()); + assertEquals(operation.getMasterKeyWeight(), parsedOperation.getMasterKeyWeight()); + assertEquals(operation.getLowThreshold(), parsedOperation.getLowThreshold()); + assertEquals(operation.getMediumThreshold(), parsedOperation.getMediumThreshold()); + assertEquals(operation.getHighThreshold(), parsedOperation.getHighThreshold()); + assertEquals(operation.getHomeDomain(), parsedOperation.getHomeDomain()); assertTrue(Arrays.equals(transaction.hash(), parsedOperation.getSigner().getPreAuthTx().getUint256())); - assertEquals(new Integer(10), parsedOperation.getSignerWeight()); - assertEquals(opSource.getAccountId(), parsedOperation.getSourceAccount()); - - assertEquals( - "AAAAAQAAAAC7JAuE3XvquOnbsgv2SRztjuk4RoBVefQ0rlrFMMQvfAAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAB1vRBIRC3w7ZH5rQa17hIBKUwZTvBP4kNmSP7jVyw1fQAAAAK", - operation.toXdrBase64(AccountConverter.enableMuxed())); + assertEquals(operation.getSignerWeight(), parsedOperation.getSignerWeight()); + assertEquals(operation.getSourceAccount(), parsedOperation.getSourceAccount()); } @Test diff --git a/src/test/java/org/stellar/sdk/Sep10ChallengeTest.java b/src/test/java/org/stellar/sdk/Sep10ChallengeTest.java index b20485d81..aed005b31 100644 --- a/src/test/java/org/stellar/sdk/Sep10ChallengeTest.java +++ b/src/test/java/org/stellar/sdk/Sep10ChallengeTest.java @@ -3,6 +3,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.io.BaseEncoding; import org.junit.Test; +import org.stellar.sdk.xdr.DecoratedSignature; import org.stellar.sdk.xdr.EnvelopeType; import org.stellar.sdk.xdr.TransactionEnvelope; @@ -13,7 +14,10 @@ import java.util.HashSet; import java.util.Set; -import static org.junit.Assert.*; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; public class Sep10ChallengeTest { @@ -218,7 +222,7 @@ public void testReadChallengeTransactionRejectsMuxedClient() throws InvalidSep10 long end = now + 300; TimeBounds timeBounds = new TimeBounds(now, end); - Transaction transaction = Sep10Challenge.newChallenge( + final Transaction transaction = Sep10Challenge.newChallenge( server, network, client.getAccountId(), @@ -228,17 +232,16 @@ public void testReadChallengeTransactionRejectsMuxedClient() throws InvalidSep10 ); Operation[] operations = transaction.getOperations(); operations[0].setSourceAccount("MCAAAAAAAAAAAAB7BQ2L7E5NBWMXDUCMZSIPOBKRDSBYVLMXGSSKF6YNPIB7Y77ITKNOG"); - Transaction withMuxedClient = new Transaction( - AccountConverter.disableMuxed(), - transaction.getSourceAccount(), - transaction.getFee(), - transaction.getSequenceNumber(), - operations, - transaction.getMemo(), - transaction.getTimeBounds(), - transaction.getNetwork() - ); - withMuxedClient.getSignatures().addAll(transaction.mSignatures); + Transaction withMuxedClient = new TransactionBuilder(AccountConverter.disableMuxed(), new Account(transaction.getSourceAccount(), 100L), transaction.getNetwork()) + .setBaseFee((int)transaction.getFee()) + .addMemo(transaction.getMemo()) + .addOperations(Arrays.asList(operations)) + .addPreconditions(transaction.getPreconditions()) + .build(); + + for (DecoratedSignature signature : transaction.mSignatures) { + withMuxedClient.addSignature(signature); + } try { Sep10Challenge.readChallengeTransaction( @@ -304,16 +307,12 @@ public void testReadChallengeTransactionInvalidNotSignedByServer() throws IOExce .build(); Operation[] operations = new Operation[]{manageDataOperation1}; - Transaction transaction = new Transaction( - AccountConverter.disableMuxed(), - sourceAccount.getAccountId(), - 100 * operations.length, - sourceAccount.getIncrementedSequenceNumber(), - operations, - Memo.none(), - timeBounds, - network - ); + Transaction transaction = new TransactionBuilder(AccountConverter.disableMuxed(), sourceAccount, network) + .setBaseFee(100 * operations.length) + .addOperations(Arrays.asList(operations)) + .addMemo(Memo.none()) + .addPreconditions(TransactionPreconditions.builder().timeBounds(timeBounds).build()) + .build(); transaction.sign(client); try { @@ -409,16 +408,13 @@ public void testReadChallengeTransactionInvalidSeqNoNotZero() throws IOException .build(); Operation[] operations = new Operation[]{manageDataOperation1}; - Transaction transaction = new Transaction( - AccountConverter.disableMuxed(), - sourceAccount.getAccountId(), - 100 * operations.length, - sourceAccount.getIncrementedSequenceNumber(), - operations, - Memo.none(), - timeBounds, - network - ); + Transaction transaction = new TransactionBuilder(AccountConverter.disableMuxed(), sourceAccount, network) + .setBaseFee(100 * operations.length) + .addOperations(Arrays.asList(operations)) + .addMemo(Memo.none()) + .addPreconditions(TransactionPreconditions.builder().timeBounds(timeBounds).build()) + .build(); + transaction.sign(server); String challenge = transaction.toEnvelopeXdrBase64(); @@ -454,57 +450,14 @@ public void testReadChallengeTransactionInvalidTimeboundsInfinite() throws IOExc .setSourceAccount(client.getAccountId()) .build(); Operation[] operations = new Operation[]{operation}; - Transaction transaction = new Transaction( - AccountConverter.disableMuxed(), - sourceAccount.getAccountId(), - 100 * operations.length, - sourceAccount.getIncrementedSequenceNumber(), - operations, - Memo.none(), - timeBounds, - network - ); - transaction.sign(server); - String challenge = transaction.toEnvelopeXdrBase64(); - try { - Sep10Challenge.readChallengeTransaction(challenge, server.getAccountId(), Network.TESTNET, domainName, webAuthDomain); - fail(); - } catch (InvalidSep10ChallengeException e) { - assertEquals("Transaction requires non-infinite timebounds.", e.getMessage()); - } - } + Transaction transaction = new TransactionBuilder(AccountConverter.disableMuxed(), sourceAccount, network) + .setBaseFee(100 * operations.length) + .addOperations(Arrays.asList(operations)) + .addMemo(Memo.none()) + .addPreconditions(TransactionPreconditions.builder().timeBounds(timeBounds).build()) + .build(); - @Test - public void testReadChallengeTransactionInvalidNoTimeBounds() throws IOException { - KeyPair server = KeyPair.random(); - KeyPair client = KeyPair.random(); - String domainName = "example.com"; - String webAuthDomain = "example.com"; - - Network network = Network.TESTNET; - - byte[] nonce = new byte[48]; - SecureRandom random = new SecureRandom(); - random.nextBytes(nonce); - BaseEncoding base64Encoding = BaseEncoding.base64(); - byte[] encodedNonce = base64Encoding.encode(nonce).getBytes(); - - Account sourceAccount = new Account(server.getAccountId(), -1L); - ManageDataOperation operation = new ManageDataOperation.Builder(domainName + " auth", encodedNonce) - .setSourceAccount(client.getAccountId()) - .build(); - Operation[] operations = new Operation[]{operation}; - Transaction transaction = new Transaction( - AccountConverter.disableMuxed(), - sourceAccount.getAccountId(), - 100 * operations.length, - sourceAccount.getIncrementedSequenceNumber(), - operations, - Memo.none(), - null, - network - ); transaction.sign(server); String challenge = transaction.toEnvelopeXdrBase64(); @@ -512,7 +465,7 @@ public void testReadChallengeTransactionInvalidNoTimeBounds() throws IOException Sep10Challenge.readChallengeTransaction(challenge, server.getAccountId(), Network.TESTNET, domainName, webAuthDomain); fail(); } catch (InvalidSep10ChallengeException e) { - assertEquals("Transaction requires timebounds.", e.getMessage()); + assertEquals("Transaction requires non-infinite timebounds.", e.getMessage()); } } @@ -620,16 +573,13 @@ public void testReadChallengeTransactionInvalidOperationWrongType() throws IOExc .build(); Operation[] operations = new Operation[]{setOptionsOperation}; - Transaction transaction = new Transaction( - AccountConverter.disableMuxed(), - sourceAccount.getAccountId(), - 100 * operations.length, - sourceAccount.getIncrementedSequenceNumber(), - operations, - Memo.none(), - timeBounds, - network - ); + Transaction transaction = new TransactionBuilder(AccountConverter.disableMuxed(), sourceAccount, network) + .setBaseFee(100 * operations.length) + .addOperations(Arrays.asList(operations)) + .addMemo(Memo.none()) + .addPreconditions(TransactionPreconditions.builder().timeBounds(timeBounds).build()) + .build(); + transaction.sign(server); String challenge = transaction.toEnvelopeXdrBase64(); @@ -664,16 +614,13 @@ public void testReadChallengeTransactionInvalidOperationNoSourceAccount() throws .build(); Operation[] operations = new Operation[]{manageDataOperation1}; - Transaction transaction = new Transaction( - AccountConverter.disableMuxed(), - sourceAccount.getAccountId(), - 100 * operations.length, - sourceAccount.getIncrementedSequenceNumber(), - operations, - Memo.none(), - timeBounds, - network - ); + Transaction transaction = new TransactionBuilder(AccountConverter.disableMuxed(), sourceAccount, network) + .setBaseFee(100 * operations.length) + .addOperations(Arrays.asList(operations)) + .addMemo(Memo.none()) + .addPreconditions(TransactionPreconditions.builder().timeBounds(timeBounds).build()) + .build(); + transaction.sign(server); String challenge = transaction.toEnvelopeXdrBase64(); @@ -710,16 +657,12 @@ public void testReadChallengeTransactionInvalidDataValueWrongEncodedLength() thr .build(); Operation[] operations = new Operation[]{manageDataOperation1}; - Transaction transaction = new Transaction( - AccountConverter.disableMuxed(), - sourceAccount.getAccountId(), - 100 * operations.length, - sourceAccount.getIncrementedSequenceNumber(), - operations, - Memo.none(), - timeBounds, - network - ); + Transaction transaction = new TransactionBuilder(AccountConverter.disableMuxed(), sourceAccount, network) + .setBaseFee(100 * operations.length) + .addOperations(Arrays.asList(operations)) + .addMemo(Memo.none()) + .addPreconditions(TransactionPreconditions.builder().timeBounds(timeBounds).build()) + .build(); transaction.sign(server); String challenge = transaction.toEnvelopeXdrBase64(); @@ -751,16 +694,12 @@ public void testReadChallengeTransactionInvalidDataValueCorruptBase64() throws I .build(); Operation[] operations = new Operation[]{manageDataOperation1}; - Transaction transaction = new Transaction( - AccountConverter.disableMuxed(), - sourceAccount.getAccountId(), - 100 * operations.length, - sourceAccount.getIncrementedSequenceNumber(), - operations, - Memo.none(), - timeBounds, - network - ); + Transaction transaction = new TransactionBuilder(AccountConverter.disableMuxed(), sourceAccount, network) + .setBaseFee(100 * operations.length) + .addOperations(Arrays.asList(operations)) + .addMemo(Memo.none()) + .addPreconditions(TransactionPreconditions.builder().timeBounds(timeBounds).build()) + .build(); transaction.sign(server); String challenge = transaction.toEnvelopeXdrBase64(); @@ -798,16 +737,12 @@ public void testReadChallengeTransactionInvalidDataValueWrongByteLength() throws .build(); Operation[] operations = new Operation[]{manageDataOperation1}; - Transaction transaction = new Transaction( - AccountConverter.disableMuxed(), - sourceAccount.getAccountId(), - 100 * operations.length, - sourceAccount.getIncrementedSequenceNumber(), - operations, - Memo.none(), - timeBounds, - network - ); + Transaction transaction = new TransactionBuilder(AccountConverter.disableMuxed(), sourceAccount, network) + .setBaseFee(100 * operations.length) + .addOperations(Arrays.asList(operations)) + .addMemo(Memo.none()) + .addPreconditions(TransactionPreconditions.builder().timeBounds(timeBounds).build()) + .build(); transaction.sign(server); String challenge = transaction.toEnvelopeXdrBase64(); @@ -838,16 +773,12 @@ public void testReadChallengeTransactionInvalidDataValueIsNull() throws IOExcept .build(); Operation[] operations = new Operation[]{manageDataOperation1}; - Transaction transaction = new Transaction( - AccountConverter.disableMuxed(), - sourceAccount.getAccountId(), - 100 * operations.length, - sourceAccount.getIncrementedSequenceNumber(), - operations, - Memo.none(), - timeBounds, - network - ); + Transaction transaction = new TransactionBuilder(AccountConverter.disableMuxed(), sourceAccount, network) + .setBaseFee(100 * operations.length) + .addOperations(Arrays.asList(operations)) + .addMemo(Memo.none()) + .addPreconditions(TransactionPreconditions.builder().timeBounds(timeBounds).build()) + .build(); transaction.sign(server); String challenge = transaction.toEnvelopeXdrBase64(); @@ -886,16 +817,12 @@ public void testReadChallengeTransactionValidAdditionalManageDataOpsWithSourceAc .setSourceAccount(server.getAccountId()) .build(); Operation[] operations = new Operation[]{operation1, operation2}; - Transaction transaction = new Transaction( - AccountConverter.disableMuxed(), - sourceAccount.getAccountId(), - 100 * operations.length, - sourceAccount.getIncrementedSequenceNumber(), - operations, - Memo.none(), - timeBounds, - network - ); + Transaction transaction = new TransactionBuilder(AccountConverter.disableMuxed(), sourceAccount, network) + .setBaseFee(100 * operations.length) + .addOperations(Arrays.asList(operations)) + .addMemo(Memo.none()) + .addPreconditions(TransactionPreconditions.builder().timeBounds(timeBounds).build()) + .build(); transaction.sign(server); String challenge = transaction.toEnvelopeXdrBase64(); @@ -930,16 +857,12 @@ public void testReadChallengeTransactionInvalidAdditionalManageDataOpsWithoutSou .setSourceAccount(client.getAccountId()) .build(); Operation[] operations = new Operation[]{operation1, operation2}; - Transaction transaction = new Transaction( - AccountConverter.disableMuxed(), - sourceAccount.getAccountId(), - 100 * operations.length, - sourceAccount.getIncrementedSequenceNumber(), - operations, - Memo.none(), - timeBounds, - network - ); + Transaction transaction =new TransactionBuilder(AccountConverter.disableMuxed(), sourceAccount, network) + .setBaseFee(100 * operations.length) + .addOperations(Arrays.asList(operations)) + .addMemo(Memo.none()) + .addPreconditions(TransactionPreconditions.builder().timeBounds(timeBounds).build()) + .build(); transaction.sign(server); String challenge = transaction.toEnvelopeXdrBase64(); @@ -976,16 +899,12 @@ public void testReadChallengeTransactionInvalidAdditionalManageDataOpsWithSource .build(); ManageDataOperation operation2 = new ManageDataOperation.Builder("key", "value".getBytes()).build(); Operation[] operations = new Operation[]{operation1, operation2}; - Transaction transaction = new Transaction( - AccountConverter.disableMuxed(), - sourceAccount.getAccountId(), - 100 * operations.length, - sourceAccount.getIncrementedSequenceNumber(), - operations, - Memo.none(), - timeBounds, - network - ); + Transaction transaction = new TransactionBuilder(AccountConverter.disableMuxed(), sourceAccount, network) + .setBaseFee(100 * operations.length) + .addOperations(Arrays.asList(operations)) + .addMemo(Memo.none()) + .addPreconditions(TransactionPreconditions.builder().timeBounds(timeBounds).build()) + .build(); transaction.sign(server); String challenge = transaction.toEnvelopeXdrBase64(); @@ -1024,16 +943,12 @@ public void testReadChallengeTransactionInvalidAdditionalOpsOfOtherTypes() throw .setSourceAccount(server.getAccountId()) .build(); Operation[] operations = new Operation[]{operation1, operation2}; - Transaction transaction = new Transaction( - AccountConverter.disableMuxed(), - sourceAccount.getAccountId(), - 100 * operations.length, - sourceAccount.getIncrementedSequenceNumber(), - operations, - Memo.none(), - timeBounds, - network - ); + Transaction transaction = new TransactionBuilder(AccountConverter.disableMuxed(), sourceAccount, network) + .setBaseFee(100 * operations.length) + .addOperations(Arrays.asList(operations)) + .addMemo(Memo.none()) + .addPreconditions(TransactionPreconditions.builder().timeBounds(timeBounds).build()) + .build(); transaction.sign(server); String challenge = transaction.toEnvelopeXdrBase64(); @@ -1267,16 +1182,12 @@ public void testReadChallengeTransactionInvalidWebAuthDomainOperationValueIsNull .setSourceAccount(server.getAccountId()) .build(); Operation[] operations = new Operation[]{domainNameOperation, webAuthDomainOperation}; - Transaction transaction = new Transaction( - AccountConverter.disableMuxed(), - sourceAccount.getAccountId(), - 100 * operations.length, - sourceAccount.getIncrementedSequenceNumber(), - operations, - Memo.none(), - timeBounds, - network - ); + Transaction transaction = new TransactionBuilder(AccountConverter.disableMuxed(), sourceAccount, network) + .setBaseFee(100 * operations.length) + .addOperations(Arrays.asList(operations)) + .addMemo(Memo.none()) + .addPreconditions(TransactionPreconditions.builder().timeBounds(timeBounds).build()) + .build(); transaction.sign(server); String challenge = transaction.toEnvelopeXdrBase64(); @@ -1318,16 +1229,12 @@ public void testReadChallengeTransactionValidWebAuthDomainAllowSubsequentManageD .setSourceAccount(server.getAccountId()) .build(); Operation[] operations = new Operation[]{domainNameOperation, webAuthDomainOperation, otherDomainOperation}; - Transaction transaction = new Transaction( - AccountConverter.disableMuxed(), - sourceAccount.getAccountId(), - 100 * operations.length, - sourceAccount.getIncrementedSequenceNumber(), - operations, - Memo.none(), - timeBounds, - network - ); + Transaction transaction = new TransactionBuilder(AccountConverter.disableMuxed(), sourceAccount, network) + .setBaseFee(100 * operations.length) + .addOperations(Arrays.asList(operations)) + .addMemo(Memo.none()) + .addPreconditions(TransactionPreconditions.builder().timeBounds(timeBounds).build()) + .build(); transaction.sign(server); String challenge = transaction.toEnvelopeXdrBase64(); @@ -1539,16 +1446,12 @@ public void testVerifyChallengeTransactionThresholdInvalidNotSignedByServer() th .build(); Operation[] operations = new Operation[]{manageDataOperation1}; - Transaction transaction = new Transaction( - AccountConverter.disableMuxed(), - sourceAccount.getAccountId(), - 100 * operations.length, - sourceAccount.getIncrementedSequenceNumber(), - operations, - Memo.none(), - timeBounds, - network - ); + Transaction transaction = new TransactionBuilder(AccountConverter.disableMuxed(), sourceAccount, network) + .setBaseFee(100 * operations.length) + .addOperations(Arrays.asList(operations)) + .addMemo(Memo.none()) + .addPreconditions(TransactionPreconditions.builder().timeBounds(timeBounds).build()) + .build(); transaction.sign(masterClient); @@ -1975,16 +1878,12 @@ public void testVerifyChallengeTransactionSignersInvalidServer() throws IOExcept .build(); Operation[] operations = new Operation[]{manageDataOperation1}; - Transaction transaction = new Transaction( - AccountConverter.disableMuxed(), - sourceAccount.getAccountId(), - 100 * operations.length, - sourceAccount.getIncrementedSequenceNumber(), - operations, - Memo.none(), - timeBounds, - network - ); + Transaction transaction = new TransactionBuilder(AccountConverter.disableMuxed(), sourceAccount, network) + .setBaseFee(100 * operations.length) + .addOperations(Arrays.asList(operations)) + .addMemo(Memo.none()) + .addPreconditions(TransactionPreconditions.builder().timeBounds(timeBounds).build()) + .build(); transaction.sign(masterClient); transaction.sign(signerClient1); @@ -2469,16 +2368,12 @@ public void testVerifyChallengeTransactionValidAdditionalManageDataOpsWithSource .setSourceAccount(server.getAccountId()) .build(); Operation[] operations = new Operation[]{operation1, operation2}; - Transaction transaction = new Transaction( - AccountConverter.disableMuxed(), - sourceAccount.getAccountId(), - 100 * operations.length, - sourceAccount.getIncrementedSequenceNumber(), - operations, - Memo.none(), - timeBounds, - network - ); + Transaction transaction = new TransactionBuilder(AccountConverter.disableMuxed(), sourceAccount, network) + .setBaseFee(100 * operations.length) + .addOperations(Arrays.asList(operations)) + .addMemo(Memo.none()) + .addPreconditions(TransactionPreconditions.builder().timeBounds(timeBounds).build()) + .build(); transaction.sign(server); transaction.sign(masterClient); @@ -2514,16 +2409,12 @@ public void testVerifyChallengeTransactionInvalidAdditionalManageDataOpsWithoutS .setSourceAccount(masterClient.getAccountId()) .build(); Operation[] operations = new Operation[]{operation1, operation2}; - Transaction transaction = new Transaction( - AccountConverter.disableMuxed(), - sourceAccount.getAccountId(), - 100 * operations.length, - sourceAccount.getIncrementedSequenceNumber(), - operations, - Memo.none(), - timeBounds, - network - ); + Transaction transaction = new TransactionBuilder(AccountConverter.disableMuxed(), sourceAccount, network) + .setBaseFee(100 * operations.length) + .addOperations(Arrays.asList(operations)) + .addMemo(Memo.none()) + .addPreconditions(TransactionPreconditions.builder().timeBounds(timeBounds).build()) + .build(); transaction.sign(server); transaction.sign(masterClient); @@ -2561,16 +2452,12 @@ public void testVerifyChallengeTransactionInvalidAdditionalManageDataOpsWithSour .build(); ManageDataOperation operation2 = new ManageDataOperation.Builder("key", "value".getBytes()).build(); Operation[] operations = new Operation[]{operation1, operation2}; - Transaction transaction = new Transaction( - AccountConverter.disableMuxed(), - sourceAccount.getAccountId(), - 100 * operations.length, - sourceAccount.getIncrementedSequenceNumber(), - operations, - Memo.none(), - timeBounds, - network - ); + Transaction transaction = new TransactionBuilder(AccountConverter.disableMuxed(), sourceAccount, network) + .setBaseFee(100 * operations.length) + .addOperations(Arrays.asList(operations)) + .addMemo(Memo.none()) + .addPreconditions(TransactionPreconditions.builder().timeBounds(timeBounds).build()) + .build(); transaction.sign(server); transaction.sign(masterClient); @@ -2610,16 +2497,12 @@ public void testVerifyChallengeTransactionInvalidAdditionalOpsOfOtherTypes() thr .setSourceAccount(server.getAccountId()) .build(); Operation[] operations = new Operation[]{operation1, operation2}; - Transaction transaction = new Transaction( - AccountConverter.disableMuxed(), - sourceAccount.getAccountId(), - 100 * operations.length, - sourceAccount.getIncrementedSequenceNumber(), - operations, - Memo.none(), - timeBounds, - network - ); + Transaction transaction = new TransactionBuilder(AccountConverter.disableMuxed(), sourceAccount, network) + .setBaseFee(100 * operations.length) + .addOperations(Arrays.asList(operations)) + .addMemo(Memo.none()) + .addPreconditions(TransactionPreconditions.builder().timeBounds(timeBounds).build()) + .build(); transaction.sign(server); transaction.sign(masterClient); diff --git a/src/test/java/org/stellar/sdk/ServerTest.java b/src/test/java/org/stellar/sdk/ServerTest.java index c0a3a6d0a..41d07d90d 100644 --- a/src/test/java/org/stellar/sdk/ServerTest.java +++ b/src/test/java/org/stellar/sdk/ServerTest.java @@ -18,7 +18,12 @@ import java.net.URISyntaxException; import java.util.concurrent.TimeUnit; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; public class ServerTest { private final String publicRootResponse = "{\n" + @@ -172,11 +177,11 @@ Transaction buildTransaction(Network network) throws IOException { KeyPair destination = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); Account account = new Account(source.getAccountId(), 2908908335136768L); - Transaction.Builder builder = new Transaction.Builder(AccountConverter.enableMuxed(), account, network) + TransactionBuilder builder = new TransactionBuilder(AccountConverter.enableMuxed(), account, network) .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) .addMemo(Memo.text("Hello world!")) .setBaseFee(Transaction.MIN_BASE_FEE) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE); + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE); assertEquals(1, builder.getOperationsCount()); Transaction transaction = builder.build(); @@ -367,12 +372,12 @@ public void testCheckMemoRequiredWithMemo() throws IOException, AccountRequiresM KeyPair source = KeyPair.fromSecretSeed("SDQXFKA32UVQHUTLYJ42N56ZUEM5PNVVI4XE7EA5QFMLA2DHDCQX3GPY"); Account account = new Account(source.getAccountId(), 1L); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.PUBLIC) + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.PUBLIC) .addOperation(new PaymentOperation.Builder(DESTINATION_ACCOUNT_MEMO_REQUIRED_A, new AssetTypeNative(), "10").build()) .addOperation(new PathPaymentStrictReceiveOperation.Builder(new AssetTypeNative(), "10", DESTINATION_ACCOUNT_MEMO_REQUIRED_B, new AssetTypeCreditAlphaNum4("BTC", "GA7GYB3QGLTZNHNGXN3BMANS6TC7KJT3TCGTR763J4JOU4QHKL37RVV2"), "5").build()) .addOperation(new PathPaymentStrictSendOperation.Builder(new AssetTypeNative(), "10", DESTINATION_ACCOUNT_MEMO_REQUIRED_C, new AssetTypeCreditAlphaNum4("BTC", "GA7GYB3QGLTZNHNGXN3BMANS6TC7KJT3TCGTR763J4JOU4QHKL37RVV2"), "5").build()) .addOperation(new AccountMergeOperation.Builder(DESTINATION_ACCOUNT_MEMO_REQUIRED_D).build()) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) .addMemo(new MemoText("Hello, Stellar.")) .setBaseFee(100) .build(); @@ -391,12 +396,12 @@ public void testCheckMemoRequiredWithMemoIdAddress() throws IOException, Account KeyPair source = KeyPair.fromSecretSeed("SDQXFKA32UVQHUTLYJ42N56ZUEM5PNVVI4XE7EA5QFMLA2DHDCQX3GPY"); Account account = new Account(source.getAccountId(), 1L); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.PUBLIC) + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.PUBLIC) .addOperation(new PaymentOperation.Builder(DESTINATION_ACCOUNT_MEMO_ID, new AssetTypeNative(), "10").build()) .addOperation(new PathPaymentStrictReceiveOperation.Builder(new AssetTypeNative(), "10", DESTINATION_ACCOUNT_MEMO_ID, new AssetTypeCreditAlphaNum4("BTC", "GA7GYB3QGLTZNHNGXN3BMANS6TC7KJT3TCGTR763J4JOU4QHKL37RVV2"), "5").build()) .addOperation(new PathPaymentStrictSendOperation.Builder(new AssetTypeNative(), "10", DESTINATION_ACCOUNT_MEMO_ID, new AssetTypeCreditAlphaNum4("BTC", "GA7GYB3QGLTZNHNGXN3BMANS6TC7KJT3TCGTR763J4JOU4QHKL37RVV2"), "5").build()) .addOperation(new AccountMergeOperation.Builder(DESTINATION_ACCOUNT_MEMO_ID).build()) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) .setBaseFee(100) .build(); @@ -415,12 +420,12 @@ public void testCheckMemoRequiredWithSkipCheck() throws IOException, AccountRequ KeyPair source = KeyPair.fromSecretSeed("SDQXFKA32UVQHUTLYJ42N56ZUEM5PNVVI4XE7EA5QFMLA2DHDCQX3GPY"); Account account = new Account(source.getAccountId(), 1L); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.PUBLIC) + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.PUBLIC) .addOperation(new PaymentOperation.Builder(DESTINATION_ACCOUNT_MEMO_REQUIRED_A, new AssetTypeNative(), "10").build()) .addOperation(new PathPaymentStrictReceiveOperation.Builder(new AssetTypeNative(), "10", DESTINATION_ACCOUNT_NO_MEMO_REQUIRED, new AssetTypeCreditAlphaNum4("BTC", "GA7GYB3QGLTZNHNGXN3BMANS6TC7KJT3TCGTR763J4JOU4QHKL37RVV2"), "5").build()) .addOperation(new PathPaymentStrictSendOperation.Builder(new AssetTypeNative(), "10", DESTINATION_ACCOUNT_NO_MEMO_REQUIRED, new AssetTypeCreditAlphaNum4("BTC", "GA7GYB3QGLTZNHNGXN3BMANS6TC7KJT3TCGTR763J4JOU4QHKL37RVV2"), "5").build()) .addOperation(new AccountMergeOperation.Builder(DESTINATION_ACCOUNT_NO_MEMO_REQUIRED).build()) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) .setBaseFee(100) .build(); transaction.sign(source); @@ -438,12 +443,12 @@ public void testCheckMemoRequiredWithPaymentOperationNoMemo() throws IOException KeyPair source = KeyPair.fromSecretSeed("SDQXFKA32UVQHUTLYJ42N56ZUEM5PNVVI4XE7EA5QFMLA2DHDCQX3GPY"); Account account = new Account(source.getAccountId(), 1L); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.PUBLIC) + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.PUBLIC) .addOperation(new PaymentOperation.Builder(DESTINATION_ACCOUNT_MEMO_REQUIRED_A, new AssetTypeNative(), "10").build()) .addOperation(new PathPaymentStrictReceiveOperation.Builder(new AssetTypeNative(), "10", DESTINATION_ACCOUNT_NO_MEMO_REQUIRED, new AssetTypeCreditAlphaNum4("BTC", "GA7GYB3QGLTZNHNGXN3BMANS6TC7KJT3TCGTR763J4JOU4QHKL37RVV2"), "5").build()) .addOperation(new PathPaymentStrictSendOperation.Builder(new AssetTypeNative(), "10", DESTINATION_ACCOUNT_NO_MEMO_REQUIRED, new AssetTypeCreditAlphaNum4("BTC", "GA7GYB3QGLTZNHNGXN3BMANS6TC7KJT3TCGTR763J4JOU4QHKL37RVV2"), "5").build()) .addOperation(new AccountMergeOperation.Builder(DESTINATION_ACCOUNT_NO_MEMO_REQUIRED).build()) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) .setBaseFee(100) .build(); transaction.sign(source); @@ -476,12 +481,12 @@ public void testCheckMemoRequiredWithPathPaymentStrictReceiveOperationNoMemo() t KeyPair source = KeyPair.fromSecretSeed("SDQXFKA32UVQHUTLYJ42N56ZUEM5PNVVI4XE7EA5QFMLA2DHDCQX3GPY"); Account account = new Account(source.getAccountId(), 1L); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.PUBLIC) + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.PUBLIC) .addOperation(new PaymentOperation.Builder(DESTINATION_ACCOUNT_NO_MEMO_REQUIRED, new AssetTypeNative(), "10").build()) .addOperation(new PathPaymentStrictReceiveOperation.Builder(new AssetTypeNative(), "10", DESTINATION_ACCOUNT_MEMO_REQUIRED_B, new AssetTypeCreditAlphaNum4("BTC", "GA7GYB3QGLTZNHNGXN3BMANS6TC7KJT3TCGTR763J4JOU4QHKL37RVV2"), "5").build()) .addOperation(new PathPaymentStrictSendOperation.Builder(new AssetTypeNative(), "10", DESTINATION_ACCOUNT_NO_MEMO_REQUIRED, new AssetTypeCreditAlphaNum4("BTC", "GA7GYB3QGLTZNHNGXN3BMANS6TC7KJT3TCGTR763J4JOU4QHKL37RVV2"), "5").build()) .addOperation(new AccountMergeOperation.Builder(DESTINATION_ACCOUNT_NO_MEMO_REQUIRED).build()) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) .setBaseFee(100) .build(); transaction.sign(source); @@ -514,12 +519,12 @@ public void testCheckMemoRequiredWithPathPaymentStrictSendOperationNoMemo() thro KeyPair source = KeyPair.fromSecretSeed("SDQXFKA32UVQHUTLYJ42N56ZUEM5PNVVI4XE7EA5QFMLA2DHDCQX3GPY"); Account account = new Account(source.getAccountId(), 1L); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.PUBLIC) + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.PUBLIC) .addOperation(new PaymentOperation.Builder(DESTINATION_ACCOUNT_NO_MEMO_REQUIRED, new AssetTypeNative(), "10").build()) .addOperation(new PathPaymentStrictReceiveOperation.Builder(new AssetTypeNative(), "10", DESTINATION_ACCOUNT_NO_MEMO_REQUIRED, new AssetTypeCreditAlphaNum4("BTC", "GA7GYB3QGLTZNHNGXN3BMANS6TC7KJT3TCGTR763J4JOU4QHKL37RVV2"), "5").build()) .addOperation(new PathPaymentStrictSendOperation.Builder(new AssetTypeNative(), "10", DESTINATION_ACCOUNT_MEMO_REQUIRED_C, new AssetTypeCreditAlphaNum4("BTC", "GA7GYB3QGLTZNHNGXN3BMANS6TC7KJT3TCGTR763J4JOU4QHKL37RVV2"), "5").build()) .addOperation(new AccountMergeOperation.Builder(DESTINATION_ACCOUNT_NO_MEMO_REQUIRED).build()) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) .setBaseFee(100) .build(); transaction.sign(source); @@ -552,12 +557,12 @@ public void testCheckMemoRequiredWithAccountMergeOperationNoMemo() throws IOExce KeyPair source = KeyPair.fromSecretSeed("SDQXFKA32UVQHUTLYJ42N56ZUEM5PNVVI4XE7EA5QFMLA2DHDCQX3GPY"); Account account = new Account(source.getAccountId(), 1L); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.PUBLIC) + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.PUBLIC) .addOperation(new PaymentOperation.Builder(DESTINATION_ACCOUNT_NO_MEMO_REQUIRED, new AssetTypeNative(), "10").build()) .addOperation(new PathPaymentStrictReceiveOperation.Builder(new AssetTypeNative(), "10", DESTINATION_ACCOUNT_NO_MEMO_REQUIRED, new AssetTypeCreditAlphaNum4("BTC", "GA7GYB3QGLTZNHNGXN3BMANS6TC7KJT3TCGTR763J4JOU4QHKL37RVV2"), "5").build()) .addOperation(new PathPaymentStrictSendOperation.Builder(new AssetTypeNative(), "10", DESTINATION_ACCOUNT_NO_MEMO_REQUIRED, new AssetTypeCreditAlphaNum4("BTC", "GA7GYB3QGLTZNHNGXN3BMANS6TC7KJT3TCGTR763J4JOU4QHKL37RVV2"), "5").build()) .addOperation(new AccountMergeOperation.Builder(DESTINATION_ACCOUNT_MEMO_REQUIRED_D).build()) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) .setBaseFee(100) .build(); transaction.sign(source); @@ -590,12 +595,12 @@ public void testCheckMemoRequiredTwoOperationsWithSameDestination() throws IOExc KeyPair source = KeyPair.fromSecretSeed("SDQXFKA32UVQHUTLYJ42N56ZUEM5PNVVI4XE7EA5QFMLA2DHDCQX3GPY"); Account account = new Account(source.getAccountId(), 1L); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.PUBLIC) + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.PUBLIC) .addOperation(new PaymentOperation.Builder(DESTINATION_ACCOUNT_NO_MEMO_REQUIRED, new AssetTypeNative(), "10").build()) .addOperation(new PathPaymentStrictReceiveOperation.Builder(new AssetTypeNative(), "10", DESTINATION_ACCOUNT_NO_MEMO_REQUIRED, new AssetTypeCreditAlphaNum4("BTC", "GA7GYB3QGLTZNHNGXN3BMANS6TC7KJT3TCGTR763J4JOU4QHKL37RVV2"), "5").build()) .addOperation(new PathPaymentStrictSendOperation.Builder(new AssetTypeNative(), "10", DESTINATION_ACCOUNT_MEMO_REQUIRED_C, new AssetTypeCreditAlphaNum4("BTC", "GA7GYB3QGLTZNHNGXN3BMANS6TC7KJT3TCGTR763J4JOU4QHKL37RVV2"), "5").build()) .addOperation(new AccountMergeOperation.Builder(DESTINATION_ACCOUNT_MEMO_REQUIRED_D).build()) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) .setBaseFee(100) .build(); transaction.sign(source); @@ -628,13 +633,13 @@ public void testCheckMemoRequiredNoDestinationOperation() throws IOException { KeyPair source = KeyPair.fromSecretSeed("SDQXFKA32UVQHUTLYJ42N56ZUEM5PNVVI4XE7EA5QFMLA2DHDCQX3GPY"); Account account = new Account(source.getAccountId(), 1L); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.PUBLIC) + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.PUBLIC) .addOperation(new ManageDataOperation.Builder("Hello", "Stellar".getBytes()).build()) .addOperation(new PaymentOperation.Builder(DESTINATION_ACCOUNT_MEMO_REQUIRED_A, new AssetTypeNative(), "10").build()) .addOperation(new PathPaymentStrictReceiveOperation.Builder(new AssetTypeNative(), "10", DESTINATION_ACCOUNT_MEMO_REQUIRED_A, new AssetTypeCreditAlphaNum4("BTC", "GA7GYB3QGLTZNHNGXN3BMANS6TC7KJT3TCGTR763J4JOU4QHKL37RVV2"), "5").build()) .addOperation(new PathPaymentStrictSendOperation.Builder(new AssetTypeNative(), "10", DESTINATION_ACCOUNT_MEMO_REQUIRED_C, new AssetTypeCreditAlphaNum4("BTC", "GA7GYB3QGLTZNHNGXN3BMANS6TC7KJT3TCGTR763J4JOU4QHKL37RVV2"), "5").build()) .addOperation(new AccountMergeOperation.Builder(DESTINATION_ACCOUNT_NO_MEMO_REQUIRED).build()) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) .setBaseFee(100) .build(); transaction.sign(source); @@ -667,12 +672,12 @@ public void testCheckMemoRequiredAccountNotFound() throws IOException, AccountRe KeyPair source = KeyPair.fromSecretSeed("SDQXFKA32UVQHUTLYJ42N56ZUEM5PNVVI4XE7EA5QFMLA2DHDCQX3GPY"); Account account = new Account(source.getAccountId(), 1L); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.PUBLIC) + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.PUBLIC) .addOperation(new PaymentOperation.Builder(DESTINATION_ACCOUNT_NO_FOUND, new AssetTypeNative(), "10").build()) .addOperation(new PathPaymentStrictReceiveOperation.Builder(new AssetTypeNative(), "10", DESTINATION_ACCOUNT_NO_FOUND, new AssetTypeCreditAlphaNum4("BTC", "GA7GYB3QGLTZNHNGXN3BMANS6TC7KJT3TCGTR763J4JOU4QHKL37RVV2"), "5").build()) .addOperation(new PathPaymentStrictSendOperation.Builder(new AssetTypeNative(), "10", DESTINATION_ACCOUNT_NO_FOUND, new AssetTypeCreditAlphaNum4("BTC", "GA7GYB3QGLTZNHNGXN3BMANS6TC7KJT3TCGTR763J4JOU4QHKL37RVV2"), "5").build()) .addOperation(new AccountMergeOperation.Builder(DESTINATION_ACCOUNT_NO_FOUND).build()) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) .setBaseFee(100) .build(); transaction.sign(source); @@ -690,14 +695,14 @@ public void testCheckMemoRequiredFetchAccountError() throws IOException, Account KeyPair source = KeyPair.fromSecretSeed("SDQXFKA32UVQHUTLYJ42N56ZUEM5PNVVI4XE7EA5QFMLA2DHDCQX3GPY"); Account account = new Account(source.getAccountId(), 1L); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.PUBLIC) + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.PUBLIC) .addOperation(new PaymentOperation.Builder(DESTINATION_ACCOUNT_FETCH_ERROR, new AssetTypeNative(), "10").build()) .addOperation(new PaymentOperation.Builder(DESTINATION_ACCOUNT_MEMO_REQUIRED_A, new AssetTypeNative(), "10").build()) .addOperation(new PaymentOperation.Builder(DESTINATION_ACCOUNT_MEMO_REQUIRED_B, new AssetTypeNative(), "10").build()) .addOperation(new PathPaymentStrictReceiveOperation.Builder(new AssetTypeNative(), "10", DESTINATION_ACCOUNT_MEMO_REQUIRED_C, new AssetTypeCreditAlphaNum4("BTC", "GA7GYB3QGLTZNHNGXN3BMANS6TC7KJT3TCGTR763J4JOU4QHKL37RVV2"), "5").build()) .addOperation(new PathPaymentStrictSendOperation.Builder(new AssetTypeNative(), "10", DESTINATION_ACCOUNT_MEMO_REQUIRED_D, new AssetTypeCreditAlphaNum4("BTC", "GA7GYB3QGLTZNHNGXN3BMANS6TC7KJT3TCGTR763J4JOU4QHKL37RVV2"), "5").build()) .addOperation(new AccountMergeOperation.Builder(DESTINATION_ACCOUNT_MEMO_REQUIRED_D).build()) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) .setBaseFee(100) .build(); transaction.sign(source); diff --git a/src/test/java/org/stellar/sdk/SetOptionsOperationTest.java b/src/test/java/org/stellar/sdk/SetOptionsOperationTest.java new file mode 100644 index 000000000..13d0a20b7 --- /dev/null +++ b/src/test/java/org/stellar/sdk/SetOptionsOperationTest.java @@ -0,0 +1,43 @@ +package org.stellar.sdk; + +import com.google.common.io.BaseEncoding; +import org.junit.Test; +import org.stellar.sdk.xdr.SignerKey; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +public class SetOptionsOperationTest { + KeyPair source = KeyPair.fromSecretSeed("SC4CGETADVYTCR5HEAVZRB3DZQY5Y4J7RFNJTRA6ESMHIPEZUSTE2QDK"); + + @Test + public void testPaylodSignerKey() { + SetOptionsOperation.Builder builder = new SetOptionsOperation.Builder(); + String payloadSignerStrKey = "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ"; + + byte[] payload = BaseEncoding.base16().decode("0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20".toUpperCase()); + SignedPayloadSigner signedPayloadSigner = new SignedPayloadSigner(StrKey.decodeStellarAccountId(payloadSignerStrKey), payload); + SignerKey signerKey = Signer.signedPayload(signedPayloadSigner); + + builder.setSigner(signerKey, 1); + builder.setSourceAccount(source.getAccountId()); + + SetOptionsOperation operation = builder.build(); + + org.stellar.sdk.xdr.Operation xdr = operation.toXdr(AccountConverter.enableMuxed()); + SetOptionsOperation parsedOperation = (SetOptionsOperation) Operation.fromXdr(AccountConverter.enableMuxed(), xdr); + + // verify round trip between xdr and pojo + assertEquals(source.getAccountId(), parsedOperation.getSourceAccount()); + assertEquals(signedPayloadSigner.getSignerAccountId().getAccountID().getEd25519(), parsedOperation.getSigner().getEd25519SignedPayload().getEd25519()); + assertArrayEquals(signedPayloadSigner.getPayload(), parsedOperation.getSigner().getEd25519SignedPayload().getPayload()); + + // verify serialized xdr emitted with signed payload + assertEquals( + "AAAAAQAAAAC7JAuE3XvquOnbsgv2SRztjuk4RoBVefQ0rlrFMMQvfAAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAEAAAADPww0v5OtDZlx0EzMkPcFURyDiq2XNKSi+w16A/x/6JoAAAAgAQIDBAUGBwgJCgsMDQ4PEBES" + + "ExQVFhcYGRobHB0eHyAAAAAB", + operation.toXdrBase64(AccountConverter.enableMuxed())); + } + +} diff --git a/src/test/java/org/stellar/sdk/SignedPayloadSignerTest.java b/src/test/java/org/stellar/sdk/SignedPayloadSignerTest.java new file mode 100644 index 000000000..ddb539e67 --- /dev/null +++ b/src/test/java/org/stellar/sdk/SignedPayloadSignerTest.java @@ -0,0 +1,46 @@ +package org.stellar.sdk; + +import com.google.common.io.BaseEncoding; +import org.junit.Test; +import org.stellar.sdk.xdr.AccountID; +import org.stellar.sdk.xdr.PublicKey; +import org.stellar.sdk.xdr.PublicKeyType; +import org.stellar.sdk.xdr.Uint256; + +import javax.net.ssl.ExtendedSSLSession; + +import static org.junit.Assert.fail; + +public class SignedPayloadSignerTest { + @Test + public void itFailsWhenAccoutIDIsNull() { + try { + new SignedPayloadSigner( + (AccountID)null, + new byte[]{}); + fail("should not create when accountid is null"); + } catch (NullPointerException ignored){} + } + + @Test + public void itFailsWhenPayloadLengthTooBig() { + String accountStrKey = "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ"; + byte[] payload = BaseEncoding.base16().decode("0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f200102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2001".toUpperCase()); + try { + new SignedPayloadSigner(StrKey.decodeStellarAccountId(accountStrKey), payload); + fail("should not create a payload signer if payload > max length"); + } catch (IllegalArgumentException ignored) {} + + } + + @Test + public void itFailsWhenSignerNotED25519() { + try { + new SignedPayloadSigner(new AccountID( + new PublicKey.Builder() + .ed25519(new Uint256(new byte[]{})).build()), new byte[]{}); + fail("should not create a payload signer if signer wasn't ed25519 type"); + } catch (IllegalArgumentException ignored) {} + + } +} diff --git a/src/test/java/org/stellar/sdk/SignerTest.java b/src/test/java/org/stellar/sdk/SignerTest.java new file mode 100644 index 000000000..d537db128 --- /dev/null +++ b/src/test/java/org/stellar/sdk/SignerTest.java @@ -0,0 +1,23 @@ +package org.stellar.sdk; + +import com.google.common.io.BaseEncoding; +import org.junit.Test; +import org.stellar.sdk.xdr.SignerKey; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +public class SignerTest { + + @Test + public void itCreatesSignedPayloadSigner() { + String accountStrKey = "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ"; + + byte[] payload = BaseEncoding.base16().decode("0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20".toUpperCase()); + SignedPayloadSigner signedPayloadSigner = new SignedPayloadSigner(StrKey.decodeStellarAccountId(accountStrKey), payload); + SignerKey signerKey = Signer.signedPayload(signedPayloadSigner); + + assertArrayEquals(signerKey.getEd25519SignedPayload().getPayload(), payload); + assertEquals(signerKey.getEd25519SignedPayload().getEd25519(),signedPayloadSigner.getSignerAccountId().getAccountID().getEd25519()); + } +} diff --git a/src/test/java/org/stellar/sdk/StrKeyTest.java b/src/test/java/org/stellar/sdk/StrKeyTest.java index 689ba0a52..8c937a2a2 100644 --- a/src/test/java/org/stellar/sdk/StrKeyTest.java +++ b/src/test/java/org/stellar/sdk/StrKeyTest.java @@ -1,5 +1,6 @@ package org.stellar.sdk; +import com.google.common.io.BaseEncoding; import org.junit.Test; import org.stellar.sdk.xdr.AccountID; import org.stellar.sdk.xdr.CryptoKeyType; @@ -7,7 +8,10 @@ import java.io.IOException; -import static org.junit.Assert.*; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + public class StrKeyTest { @Test @@ -45,6 +49,7 @@ public void testDecodedVersionByte() { assertEquals(StrKey.decodeVersionByte("MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVAAAAAAAAAAAAAJLK"), StrKey.VersionByte.MUXED); assertEquals(StrKey.decodeVersionByte("TAQCSRX2RIDJNHFIFHWD63X7D7D6TRT5Y2S6E3TEMXTG5W3OECHZ2OG4"), StrKey.VersionByte.PRE_AUTH_TX); assertEquals(StrKey.decodeVersionByte("XDRPF6NZRR7EEVO7ESIWUDXHAOMM2QSKIQQBJK6I2FB7YKDZES5UCLWD"), StrKey.VersionByte.SHA256_HASH); + assertEquals(StrKey.decodeVersionByte("PDPYP7E6NEYZSVOTV6M23OFM2XRIMPDUJABHGHHH2Y67X7JL25GW6AAAAAAAAAAAAAAJEVA"), StrKey.VersionByte.SIGNED_PAYLOAD); } @Test() @@ -129,6 +134,45 @@ public void testRoundTripHashXFromBytes() { assertArrayEquals(data, StrKey.decodeCheck(StrKey.VersionByte.SHA256_HASH, hashX.toCharArray())); } + @Test + public void testValidSignedPayloadEncode() { + // Valid signed payload with an ed25519 public key and a 32-byte payload. + byte[] payload = BaseEncoding.base16().decode("0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20".toUpperCase()); + SignedPayloadSigner signedPayloadSigner = new SignedPayloadSigner(StrKey.decodeStellarAccountId("GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ"), payload); + String encoded = StrKey.encodeSignedPayload(signedPayloadSigner); + assertEquals(encoded, "PA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAQACAQDAQCQMBYIBEFAWDANBYHRAEISCMKBKFQXDAMRUGY4DUPB6IBZGM"); + + // Valid signed payload with an ed25519 public key and a 29-byte payload. + payload = BaseEncoding.base16().decode("0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d".toUpperCase()); + signedPayloadSigner = new SignedPayloadSigner(StrKey.decodeStellarAccountId("GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ"), payload); + encoded = StrKey.encodeSignedPayload(signedPayloadSigner); + assertEquals(encoded, "PA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAOQCAQDAQCQMBYIBEFAWDANBYHRAEISCMKBKFQXDAMRUGY4DUAAAAFGBU"); + } + + @Test + public void testRoundTripSignedPayloadVersionByte() { + byte[] data = rawBytes( + // ed25519 + 0x36, 0x3e, 0xaa, 0x38, 0x67, 0x84, 0x1f, 0xba, + 0xd0, 0xf4, 0xed, 0x88, 0xc7, 0x79, 0xe4, 0xfe, + 0x66, 0xe5, 0x6a, 0x24, 0x70, 0xdc, 0x98, 0xc0, + 0xec, 0x9c, 0x07, 0x3d, 0x05, 0xc7, 0xb1, 0x03, + // payload length + 0x00, 0x00, 0x00, 0x09, + // payload + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, + // padding + 0x00, 0x00, 0x00); + + String hashX = "PA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQGAAAAAEQAAAAAAAAAAAAAAAAAABBXA"; + assertEquals( + hashX, + String.valueOf(StrKey.encodeCheck(StrKey.VersionByte.SIGNED_PAYLOAD, data)) + ); + assertArrayEquals(data, StrKey.decodeCheck(StrKey.VersionByte.SIGNED_PAYLOAD, hashX.toCharArray())); + } + @Test public void testDecodeEmpty() { try { diff --git a/src/test/java/org/stellar/sdk/TransactionBuilderTest.java b/src/test/java/org/stellar/sdk/TransactionBuilderTest.java new file mode 100644 index 000000000..88934d834 --- /dev/null +++ b/src/test/java/org/stellar/sdk/TransactionBuilderTest.java @@ -0,0 +1,720 @@ +package org.stellar.sdk; + +import com.google.common.io.BaseEncoding; +import org.junit.Test; +import org.stellar.sdk.xdr.Int64; +import org.stellar.sdk.xdr.PreconditionsV2; +import org.stellar.sdk.xdr.SequenceNumber; +import org.stellar.sdk.xdr.SignerKey; +import org.stellar.sdk.xdr.SignerKeyType; +import org.stellar.sdk.xdr.Uint256; +import org.stellar.sdk.xdr.XdrDataInputStream; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + +import static com.google.common.collect.Lists.newArrayList; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class TransactionBuilderTest { + + @Test + public void testMissingOperationFee() { + long sequenceNumber = 2908908335136768L; + Account account = new Account("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR", sequenceNumber); + try { + new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR", "2000").build()) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) + .build(); + fail("expected RuntimeException"); + } catch (RuntimeException e) { + // expected + } + } + + @Test + public void testBuilderSuccessTestnet() throws Exception { + // GBPMKIRA2OQW2XZZQUCQILI5TMVZ6JNRKM423BSAISDM7ZFWQ6KWEBC4 + KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); + KeyPair destination = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); + + long sequenceNumber = 2908908335136768L; + Account account = new Account(source.getAccountId(), sequenceNumber); + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) + .setBaseFee(Transaction.MIN_BASE_FEE) + .build(); + + transaction.sign(source); + + assertEquals(transaction.getSourceAccount(), source.getAccountId()); + assertEquals(transaction.getSequenceNumber(), sequenceNumber + 1); + assertEquals(transaction.getFee(), 100); + + assertEquals( + "AAAAAgAAAABexSIg06FtXzmFBQQtHZsrnyWxUzmthkBEhs/ktoeVYgAAAGQAClWjAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAADt4FJhvNwvlQqjuhc7bjLVyRf5e4K2QOzI0c6nWfVvEAAAAASoF8gAAAAAAAAAAAG2h5ViAAAAQLJxvwao6eyNHaDX2QFhgdqlxJUqkpgA03UUOqf4DwOXSV9GN4ZWut2uzRuza4DWyVGBEHmmnQX+SQKFo0Sb/wA=", + transaction.toEnvelopeXdrBase64()); + + // Convert transaction to binary XDR and back again to make sure correctly xdr de/serialized. + XdrDataInputStream is = new XdrDataInputStream( + new ByteArrayInputStream( + javax.xml.bind.DatatypeConverter.parseBase64Binary(transaction.toEnvelopeXdrBase64()) + ) + ); + org.stellar.sdk.xdr.TransactionEnvelope decodedTransaction = org.stellar.sdk.xdr.TransactionEnvelope.decode(is); + Transaction transaction2 = (Transaction)Transaction.fromEnvelopeXdr(AccountConverter.enableMuxed(), decodedTransaction, Network.TESTNET); + assertEquals(transaction, transaction2); + } + + @Test + public void testBuilderMemoText() throws Exception { + // GBPMKIRA2OQW2XZZQUCQILI5TMVZ6JNRKM423BSAISDM7ZFWQ6KWEBC4 + KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); + KeyPair destination = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); + + Account account = new Account(source.getAccountId(), 2908908335136768L); + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) + .addMemo(Memo.text("Hello world!")) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) + .setBaseFee(Transaction.MIN_BASE_FEE) + .build(); + + transaction.sign(source); + + // Convert transaction to binary XDR and back again to make sure correctly xdr de/serialized. + XdrDataInputStream is = new XdrDataInputStream( + new ByteArrayInputStream( + javax.xml.bind.DatatypeConverter.parseBase64Binary(transaction.toEnvelopeXdrBase64()) + ) + ); + org.stellar.sdk.xdr.TransactionEnvelope decodedTransaction = org.stellar.sdk.xdr.TransactionEnvelope.decode(is); + Transaction transaction2 = (Transaction)Transaction.fromEnvelopeXdr(AccountConverter.enableMuxed(), decodedTransaction, Network.TESTNET); + assertEquals(transaction, transaction2); + + assertEquals( + "AAAAAgAAAABexSIg06FtXzmFBQQtHZsrnyWxUzmthkBEhs/ktoeVYgAAAGQAClWjAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAxIZWxsbyB3b3JsZCEAAAABAAAAAAAAAAAAAAAA7eBSYbzcL5UKo7oXO24y1ckX+XuCtkDsyNHOp1n1bxAAAAAEqBfIAAAAAAAAAAABtoeVYgAAAEA2U3MBHRAxe/nYUTFsL14hgWxcq1Z0yFcEd2LSEt+TbXbVXHl77k/sjLdUGw/0qMZMOn2n50MY+w1pnx6mjfsM", + transaction.toEnvelopeXdrBase64()); + } + + @Test + public void testBuilderTimeBounds() throws FormatException, IOException { + // GBPMKIRA2OQW2XZZQUCQILI5TMVZ6JNRKM423BSAISDM7ZFWQ6KWEBC4 + KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); + KeyPair destination = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); + + Account account = new Account(source.getAccountId(), 2908908335136768L); + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) + .addTimeBounds(new TimeBounds(42, 1337)) + .addMemo(Memo.hash("abcdef")) + .setBaseFee(Transaction.MIN_BASE_FEE) + .build(); + + transaction.sign(source); + + // Convert transaction to binary XDR and back again to make sure timebounds are correctly de/serialized. + XdrDataInputStream is = new XdrDataInputStream( + new ByteArrayInputStream( + javax.xml.bind.DatatypeConverter.parseBase64Binary(transaction.toEnvelopeXdrBase64()) + ) + ); + org.stellar.sdk.xdr.TransactionEnvelope decodedTransaction = org.stellar.sdk.xdr.TransactionEnvelope.decode(is); + + assertEquals(decodedTransaction.getV1().getTx().getCond().getTimeBounds().getMinTime().getTimePoint().getUint64().longValue(), 42); + assertEquals(decodedTransaction.getV1().getTx().getCond().getTimeBounds().getMaxTime().getTimePoint().getUint64().longValue(), 1337); + + Transaction transaction2 = (Transaction)Transaction.fromEnvelopeXdr(AccountConverter.enableMuxed(), decodedTransaction, Network.TESTNET); + assertEquals(transaction, transaction2); + } + + @Test + public void testBuilderBaseFee() throws Exception { + // GBPMKIRA2OQW2XZZQUCQILI5TMVZ6JNRKM423BSAISDM7ZFWQ6KWEBC4 + KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); + KeyPair destination = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); + + Account account = new Account(source.getAccountId(), 2908908335136768L); + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) + .setBaseFee(200) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) + .build(); + + transaction.sign(source); + + // Convert transaction to binary XDR and back again to make sure correctly xdr de/serialized. + XdrDataInputStream is = new XdrDataInputStream( + new ByteArrayInputStream( + javax.xml.bind.DatatypeConverter.parseBase64Binary(transaction.toEnvelopeXdrBase64()) + ) + ); + org.stellar.sdk.xdr.TransactionEnvelope decodedTransaction = org.stellar.sdk.xdr.TransactionEnvelope.decode(is); + Transaction transaction2 = (Transaction)Transaction.fromEnvelopeXdr(AccountConverter.enableMuxed(), decodedTransaction, Network.TESTNET); + assertEquals(transaction, transaction2); + + assertEquals( + "AAAAAgAAAABexSIg06FtXzmFBQQtHZsrnyWxUzmthkBEhs/ktoeVYgAAAMgAClWjAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAADt4FJhvNwvlQqjuhc7bjLVyRf5e4K2QOzI0c6nWfVvEAAAAASoF8gAAAAAAAAAAAG2h5ViAAAAQAIeBLnUSyzqnFYWPm0Y06/v78VquGfjQokPrMBCeOZRM4WqPLOI5/Mgn1+djGFBOVCKB+HUevtqN2DMhnhYmg8=", + transaction.toEnvelopeXdrBase64()); + } + + @Test + public void testBuilderBaseFeeThrows() throws FormatException { + // GBPMKIRA2OQW2XZZQUCQILI5TMVZ6JNRKM423BSAISDM7ZFWQ6KWEBC4 + KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); + + Account account = new Account(source.getAccountId(), 2908908335136768L); + TransactionBuilder builder = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET); + try { + builder.setBaseFee(99); + fail("expected IllegalArgumentException"); + } catch (IllegalArgumentException e) { + // expected + } + } + + @Test + public void testBuilderTimebounds() throws IOException { + Account account = new Account(KeyPair.random().getAccountId(), 2908908335136768L); + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(KeyPair.random().getAccountId(), "2000").build()) + .addTimeBounds(new TimeBounds(42, 1337)) + .addMemo(Memo.hash("abcdef")) + .setBaseFee(Transaction.MIN_BASE_FEE) + .build(); + + assertEquals(42, transaction.getTimeBounds().getMinTime()); + assertEquals(1337, transaction.getTimeBounds().getMaxTime()); + + // Convert transaction to binary XDR and back again to make sure correctly xdr de/serialized. + XdrDataInputStream is = new XdrDataInputStream( + new ByteArrayInputStream( + javax.xml.bind.DatatypeConverter.parseBase64Binary(transaction.toEnvelopeXdrBase64()) + ) + ); + org.stellar.sdk.xdr.TransactionEnvelope decodedTransaction = org.stellar.sdk.xdr.TransactionEnvelope.decode(is); + Transaction transaction2 = (Transaction)Transaction.fromEnvelopeXdr(AccountConverter.enableMuxed(), decodedTransaction, Network.TESTNET); + assertEquals(transaction, transaction2); + } + + @Test + public void testBuilderRequiresTimeoutOrTimeBounds() throws IOException { + Account account = new Account(KeyPair.random().getAccountId(), 2908908335136768L); + try { + new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(KeyPair.random().getAccountId(), "2000").build()) + .addMemo(Memo.hash("abcdef")) + .setBaseFee(Transaction.MIN_BASE_FEE) + .build(); + fail(); + } catch (FormatException ignored) {} + } + + + @Test + public void testBuilderTimeoutNegative() throws IOException { + Account account = new Account(KeyPair.random().getAccountId(), 2908908335136768L); + try { + new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(KeyPair.random().getAccountId(), "2000").build()) + .addMemo(Memo.hash("abcdef")) + .setTimeout(-1) + .build(); + fail(); + } catch (RuntimeException exception) { + assertTrue(exception.getMessage().contains("timeout cannot be negative")); + assertEquals(new Long(2908908335136768L), account.getSequenceNumber()); + } + } + + @Test + public void testBuilderTimeout() throws IOException { + Account account = new Account(KeyPair.random().getAccountId(), 2908908335136768L); + long currentUnix = System.currentTimeMillis() / 1000L; + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(KeyPair.random().getAccountId(), "2000").build()) + .setTimeout(10) + .setBaseFee(Transaction.MIN_BASE_FEE) + .build(); + + assertEquals(0, transaction.getTimeBounds().getMinTime()); + assertTrue(currentUnix + 10 <= transaction.getTimeBounds().getMaxTime()); + + // Convert transaction to binary XDR and back again to make sure timebounds are correctly de/serialized. + XdrDataInputStream is = new XdrDataInputStream( + new ByteArrayInputStream( + javax.xml.bind.DatatypeConverter.parseBase64Binary(transaction.toEnvelopeXdrBase64()) + ) + ); + org.stellar.sdk.xdr.TransactionEnvelope decodedTransaction = org.stellar.sdk.xdr.TransactionEnvelope.decode(is); + Transaction transaction2 = (Transaction)Transaction.fromEnvelopeXdr(AccountConverter.enableMuxed(), decodedTransaction, Network.TESTNET); + assertEquals(transaction, transaction2); + } + + @Test + public void testBuilderSetsLedgerBounds() throws IOException { + KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); + Account account = new Account(source.getAccountId(), 2908908335136768L); + KeyPair newAccount = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); + + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(newAccount.getAccountId(), "2000").build()) + .addPreconditions(TransactionPreconditions.builder() + .timeBounds(new TimeBounds(0L,TransactionPreconditions.TIMEOUT_INFINITE)) + .ledgerBounds(LedgerBounds.builder().minLedger(1).maxLedger(2).build()) + .build()) + .setBaseFee(Transaction.MIN_BASE_FEE) + .build(); + + assertEquals(1, transaction.getPreconditions().getLedgerBounds().getMinLedger()); + assertEquals(2, transaction.getPreconditions().getLedgerBounds().getMaxLedger()); + + XdrDataInputStream is = new XdrDataInputStream( + new ByteArrayInputStream( + javax.xml.bind.DatatypeConverter.parseBase64Binary(transaction.toEnvelopeXdrBase64()) + ) + ); + org.stellar.sdk.xdr.TransactionEnvelope decodedTransaction = org.stellar.sdk.xdr.TransactionEnvelope.decode(is); + Transaction transaction2 = (Transaction)Transaction.fromEnvelopeXdr(AccountConverter.enableMuxed(), decodedTransaction, Network.TESTNET); + assertEquals(transaction, transaction2); + + assertEquals( + "AAAAAgAAAABexSIg06FtXzmFBQQtHZsrnyWxUzmthkBEhs/ktoeVYgAAAGQAClWjAAAAAQAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAADt4FJhvNwvlQqjuhc7bjLVyRf5e4K2QOzI0c6nWfVvEAAAAASoF8gAAAAAAAAAAAA=", + transaction.toEnvelopeXdrBase64()); + + + } + + @Test + public void testBuilderSetsMinSeqNum() throws IOException { + KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); + Account account = new Account(source.getAccountId(), 2908908335136768L); + KeyPair newAccount = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); + PreconditionsV2.Builder preconditionsV2 = new PreconditionsV2.Builder(); + + SequenceNumber seqNum = new SequenceNumber(); + seqNum.setSequenceNumber(new Int64(5L)); + preconditionsV2.timeBounds(TransactionBuilder.buildTimeBounds(0, TransactionPreconditions.TIMEOUT_INFINITE)); + preconditionsV2.minSeqNum(seqNum); + + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(newAccount.getAccountId(), "2000").build()) + .addPreconditions(TransactionPreconditions.builder() + .timeBounds(new TimeBounds(0L,TransactionPreconditions.TIMEOUT_INFINITE)) + .minSeqNumber(5L) + .build()) + .setBaseFee(Transaction.MIN_BASE_FEE) + .build(); + + assertEquals(Long.valueOf(5), transaction.getPreconditions().getMinSeqNumber()); + + // Convert transaction to binary XDR and back again to make sure correctly xdr de/serialized. + XdrDataInputStream is = new XdrDataInputStream( + new ByteArrayInputStream( + javax.xml.bind.DatatypeConverter.parseBase64Binary(transaction.toEnvelopeXdrBase64()) + ) + ); + org.stellar.sdk.xdr.TransactionEnvelope decodedTransaction = org.stellar.sdk.xdr.TransactionEnvelope.decode(is); + Transaction transaction2 = (Transaction)Transaction.fromEnvelopeXdr(AccountConverter.enableMuxed(), decodedTransaction, Network.TESTNET); + assertEquals(transaction, transaction2); + + assertEquals( + "AAAAAgAAAABexSIg06FtXzmFBQQtHZsrnyWxUzmthkBEhs/ktoeVYgAAAGQAClWjAAAAAQAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAADt4FJhvNwvlQqjuhc7bjLVyRf5e4K2QOzI0c6nWfVvEAAAAASoF8gAAAAAAAAAAAA=", + transaction.toEnvelopeXdrBase64()); + } + + @Test + public void testBuilderSetsMinSeqAge() throws IOException { + KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); + KeyPair newAccount = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); + Account account = new Account(source.getAccountId(), 2908908335136768L); + + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(newAccount.getAccountId(), "2000").build()) + .addPreconditions(TransactionPreconditions.builder() + .timeBounds(new TimeBounds(0L,TransactionPreconditions.TIMEOUT_INFINITE)) + .minSeqAge(5L) + .build()) + .setBaseFee(Transaction.MIN_BASE_FEE) + .build(); + + assertEquals(5, transaction.getPreconditions().getMinSeqAge()); + + // Convert transaction to binary XDR and back again to make sure correctly xdr de/serialized. + XdrDataInputStream is = new XdrDataInputStream( + new ByteArrayInputStream( + javax.xml.bind.DatatypeConverter.parseBase64Binary(transaction.toEnvelopeXdrBase64()) + ) + ); + org.stellar.sdk.xdr.TransactionEnvelope decodedTransaction = org.stellar.sdk.xdr.TransactionEnvelope.decode(is); + Transaction transaction2 = (Transaction)Transaction.fromEnvelopeXdr(AccountConverter.enableMuxed(), decodedTransaction, Network.TESTNET); + assertEquals(transaction, transaction2); + + assertEquals( + "AAAAAgAAAABexSIg06FtXzmFBQQtHZsrnyWxUzmthkBEhs/ktoeVYgAAAGQAClWjAAAAAQAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAA7eBSYbzcL5UKo7oXO24y1ckX+XuCtkDsyNHOp1n1bxAAAAAEqBfIAAAAAAAAAAAA", + transaction.toEnvelopeXdrBase64()); + } + + @Test + public void testBuilderSetsMinSeqLedgerGap() throws IOException { + KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); + KeyPair newAccount = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); + Account account = new Account(source.getAccountId(), 2908908335136768L); + + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(newAccount.getAccountId(), "2000").build()) + .addPreconditions(TransactionPreconditions.builder() + .timeBounds(new TimeBounds(0L,TransactionPreconditions.TIMEOUT_INFINITE)) + .minSeqLedgerGap(5) + .build()) + .setBaseFee(Transaction.MIN_BASE_FEE) + .build(); + + assertEquals(5, transaction.getPreconditions().getMinSeqLedgerGap()); + + // Convert transaction to binary XDR and back again to make sure correctly xdr de/serialized. + XdrDataInputStream is = new XdrDataInputStream( + new ByteArrayInputStream( + javax.xml.bind.DatatypeConverter.parseBase64Binary(transaction.toEnvelopeXdrBase64()) + ) + ); + org.stellar.sdk.xdr.TransactionEnvelope decodedTransaction = org.stellar.sdk.xdr.TransactionEnvelope.decode(is); + Transaction transaction2 = (Transaction)Transaction.fromEnvelopeXdr(AccountConverter.enableMuxed(), decodedTransaction, Network.TESTNET); + assertEquals(transaction, transaction2); + + assertEquals( + "AAAAAgAAAABexSIg06FtXzmFBQQtHZsrnyWxUzmthkBEhs/ktoeVYgAAAGQAClWjAAAAAQAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAA7eBSYbzcL5UKo7oXO24y1ckX+XuCtkDsyNHOp1n1bxAAAAAEqBfIAAAAAAAAAAAA", + transaction.toEnvelopeXdrBase64()); + } + + @Test + public void testBuilderExtraSigners() throws IOException { + KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); + KeyPair newAccount = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); + Account account = new Account(source.getAccountId(), 2908908335136768L); + + String accountStrKey = "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ"; + byte[] payload = BaseEncoding.base16().decode("0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20".toUpperCase()); + + SignerKey signerKey = new SignerKey.Builder() + .discriminant(SignerKeyType.SIGNER_KEY_TYPE_ED25519_SIGNED_PAYLOAD) + .ed25519SignedPayload(new SignerKey.SignerKeyEd25519SignedPayload.Builder() + .payload(payload) + .ed25519(new Uint256(StrKey.decodeStellarAccountId(accountStrKey))) + .build()) + .build(); + + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(newAccount.getAccountId(), "2000").build()) + .addPreconditions(TransactionPreconditions.builder() + .timeBounds(new TimeBounds(0L,TransactionPreconditions.TIMEOUT_INFINITE)) + .extraSigners(newArrayList(signerKey)) + .minSeqLedgerGap(5) + .build()) + .setBaseFee(Transaction.MIN_BASE_FEE) + .build(); + + assertEquals(SignerKeyType.SIGNER_KEY_TYPE_ED25519_SIGNED_PAYLOAD, newArrayList(transaction.getPreconditions().getExtraSigners()).get(0).getDiscriminant()); + assertArrayEquals(payload, newArrayList(transaction.getPreconditions().getExtraSigners()).get(0).getEd25519SignedPayload().getPayload()); + + // Convert transaction to binary XDR and back again to make sure correctly xdr de/serialized. + XdrDataInputStream is = new XdrDataInputStream( + new ByteArrayInputStream( + javax.xml.bind.DatatypeConverter.parseBase64Binary(transaction.toEnvelopeXdrBase64()) + ) + ); + org.stellar.sdk.xdr.TransactionEnvelope decodedTransaction = org.stellar.sdk.xdr.TransactionEnvelope.decode(is); + Transaction transaction2 = (Transaction)Transaction.fromEnvelopeXdr(AccountConverter.enableMuxed(), decodedTransaction, Network.TESTNET); + assertEquals(transaction, transaction2); + + assertEquals( + "AAAAAgAAAABexSIg06FtXzmFBQQtHZsrnyWxUzmthkBEhs/ktoeVYgAAAGQAClWjAAAAAQAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAAAAAQAAAAM/DDS/k60NmXHQTMyQ9wVRHIOKrZc0pKL7DXoD/H/omgAAACABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fIAAAAAAAAAABAAAAAAAAAAAAAAAA7eBSYbzcL5UKo7oXO24y1ckX+XuCtkDsyNHOp1n1bxAAAAAEqBfIAAAAAAAAAAAA", + transaction.toEnvelopeXdrBase64()); + } + + @Test + public void testBuilderFailsWhenTooManyExtraSigners() throws IOException { + Account account = new Account(KeyPair.random().getAccountId(), 2908908335136768L); + + try { + new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(KeyPair.random().getAccountId(), "2000").build()) + .addPreconditions(TransactionPreconditions.builder() + .timeBounds(new TimeBounds(0L,TransactionPreconditions.TIMEOUT_INFINITE)) + .extraSigners(newArrayList(new SignerKey.Builder().build(), new SignerKey.Builder().build(), new SignerKey.Builder().build())) + .minSeqLedgerGap(5) + .build()) + .setBaseFee(Transaction.MIN_BASE_FEE) + .build(); + fail(); + } catch (FormatException ignored){} + } + + @Test + public void testBuilderFailsWhenTimeoutLessThanTimeBoundsMinimum() throws Exception { + Account account = new Account(KeyPair.random().getAccountId(), 2908908335136768L); + + try { + new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(KeyPair.random().getAccountId(), "2000").build()) + .addPreconditions(TransactionPreconditions.builder() + // set min time to 120 seconds from now + .timeBounds(new TimeBounds((System.currentTimeMillis() / 1000 )+ 120, TransactionPreconditions.TIMEOUT_INFINITE)) + .build()) + .setBaseFee(Transaction.MIN_BASE_FEE) + .setTimeout(1); // sat max time to 1 second from now + fail(); + } catch (IllegalArgumentException exception){ + assertTrue(exception.getMessage().contains("minTime must be >= maxTime")); + } + } + + @Test + public void testBuilderUsesAccountSequence() throws IOException { + Account account = new Account(KeyPair.random().getAccountId(), 3L); + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(KeyPair.random().getAccountId(), "2000").build()) + .addPreconditions(TransactionPreconditions.builder() + .timeBounds(new TimeBounds(0L,TransactionPreconditions.TIMEOUT_INFINITE)).build()) + .setBaseFee(Transaction.MIN_BASE_FEE) + .build(); + + // check that the created tx has the sequence number which custom sequence handler sets, + // rather than using default of sourceAccount.seqNum + 1 + assertEquals(4, transaction.getSequenceNumber()); + + // check that the sourceAccount.seqNum gets updated to what the custom sequence handler sets, + // rather than the default of sourceAccount.seqNum + 1 + assertEquals(4, account.getSequenceNumber().longValue()); + } + + @Test + public void testBuilderFailsWhenSettingTimeoutAndMaxTimeAlreadySet() throws IOException { + Account account = new Account(KeyPair.random().getAccountId(), 2908908335136768L); + try { + new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(KeyPair.random().getAccountId(), "2000").build()) + .setBaseFee(Transaction.MIN_BASE_FEE) + .addTimeBounds(new TimeBounds(42, 1337)) + .setTimeout(10) + .build(); + fail(); + } catch (RuntimeException exception) { + assertTrue(exception.getMessage().contains("TimeBounds.max_time has been already set")); + assertEquals(new Long(2908908335136768L), account.getSequenceNumber()); + } + } + + @Test + public void testBuilderFailsWhenSettingTimeboundsAndAlreadySet() throws IOException { + Account account = new Account(KeyPair.random().getAccountId(), 2908908335136768L); + try { + new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(KeyPair.random().getAccountId(), "2000").build()) + .setBaseFee(Transaction.MIN_BASE_FEE) + .setTimeout(10) + .addTimeBounds(new TimeBounds(42, 1337)) + .build(); + fail(); + } catch (RuntimeException exception) { + assertTrue(exception.getMessage().contains("TimeBounds already set.")); + assertEquals(new Long(2908908335136768L), account.getSequenceNumber()); + } + } + + @Test + public void testBuilderFailsWhenNoTimeBoundsOrTimeoutSet() throws IOException { + Account account = new Account(KeyPair.random().getAccountId(), 2908908335136768L); + try { + new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(KeyPair.random().getAccountId(), "2000").build()) + .setBaseFee(Transaction.MIN_BASE_FEE) + .build(); + fail(); + } catch (RuntimeException exception) { + assertTrue(exception.getMessage().contains("Invalid preconditions, must define timebounds")); + assertEquals(new Long(2908908335136768L), account.getSequenceNumber()); + } + } + + @Test + public void testBuilderInfinteTimeoutOnly() throws IOException { + KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); + KeyPair destination = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); + Account account = new Account(source.getAccountId(), 2908908335136768L); + + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) + .setBaseFee(Transaction.MIN_BASE_FEE) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) + .build(); + + transaction.sign(source); + + // Convert transaction to binary XDR and back again to make sure timeout is correctly de/serialized. + XdrDataInputStream is = new XdrDataInputStream(new ByteArrayInputStream(BaseEncoding.base64().decode(transaction.toEnvelopeXdrBase64()))); + org.stellar.sdk.xdr.TransactionEnvelope decodedTransaction = org.stellar.sdk.xdr.TransactionEnvelope.decode(is); + + assertEquals(decodedTransaction.getV1().getTx().getCond().getTimeBounds().getMinTime().getTimePoint().getUint64().longValue(), 0); + assertEquals(decodedTransaction.getV1().getTx().getCond().getTimeBounds().getMaxTime().getTimePoint().getUint64().longValue(), 0); + } + + @Test + public void testBuilderTimeoutOnly() throws IOException { + KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); + KeyPair destination = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); + Account account = new Account(source.getAccountId(), 2908908335136768L); + long currentUnix = System.currentTimeMillis() / 1000L; + + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) + .setBaseFee(Transaction.MIN_BASE_FEE) + .setTimeout(10) + .build(); + + transaction.sign(source); + + // Convert transaction to binary XDR and back again to make sure timeout is correctly de/serialized. + XdrDataInputStream is = new XdrDataInputStream(new ByteArrayInputStream(BaseEncoding.base64().decode(transaction.toEnvelopeXdrBase64()))); + org.stellar.sdk.xdr.TransactionEnvelope decodedTransaction = org.stellar.sdk.xdr.TransactionEnvelope.decode(is); + + assertEquals(decodedTransaction.getV1().getTx().getCond().getTimeBounds().getMinTime().getTimePoint().getUint64().longValue(), 0); + assertTrue(currentUnix + 10 <= decodedTransaction.getV1().getTx().getCond().getTimeBounds().getMaxTime().getTimePoint().getUint64().longValue() ); + } + + @Test + public void testBuilderTimeoutAndMaxTimeNotSet() throws IOException { + KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); + KeyPair destination = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); + Account account = new Account(source.getAccountId(), 2908908335136768L); + long currentUnix = System.currentTimeMillis() / 1000L; + + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) + .addTimeBounds(new TimeBounds(42, TransactionPreconditions.TIMEOUT_INFINITE)) + .setTimeout(10) + .setBaseFee(Transaction.MIN_BASE_FEE) + .build(); + + transaction.sign(source); + + // Convert transaction to binary XDR and back again to make sure timeout is correctly de/serialized. + XdrDataInputStream is = new XdrDataInputStream(new ByteArrayInputStream(BaseEncoding.base64().decode(transaction.toEnvelopeXdrBase64()))); + org.stellar.sdk.xdr.TransactionEnvelope decodedTransaction = org.stellar.sdk.xdr.TransactionEnvelope.decode(is); + + assertEquals(decodedTransaction.getV1().getTx().getCond().getTimeBounds().getMinTime().getTimePoint().getUint64().longValue(), 42); + assertTrue(currentUnix + 10 <= decodedTransaction.getV1().getTx().getCond().getTimeBounds().getMaxTime().getTimePoint().getUint64().longValue() ); + + } + + @Test + public void testBuilderInfinteTimeoutAndMaxTimeNotSet() throws FormatException, IOException { + // GBPMKIRA2OQW2XZZQUCQILI5TMVZ6JNRKM423BSAISDM7ZFWQ6KWEBC4 + KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); + KeyPair destination = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); + + Account account = new Account(source.getAccountId(), 2908908335136768L); + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) + .addTimeBounds(new TimeBounds(42, TransactionPreconditions.TIMEOUT_INFINITE)) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) + .addMemo(Memo.hash("abcdef")) + .setBaseFee(100) + .build(); + + transaction.sign(source); + + // Convert transaction to binary XDR and back again to make sure timebounds are correctly de/serialized. + XdrDataInputStream is = new XdrDataInputStream(new ByteArrayInputStream(BaseEncoding.base64().decode(transaction.toEnvelopeXdrBase64()))); + org.stellar.sdk.xdr.TransactionEnvelope decodedTransaction = org.stellar.sdk.xdr.TransactionEnvelope.decode(is); + + assertEquals(decodedTransaction.getV1().getTx().getCond().getTimeBounds().getMinTime().getTimePoint().getUint64().longValue(), 42); + assertEquals(decodedTransaction.getV1().getTx().getCond().getTimeBounds().getMaxTime().getTimePoint().getUint64().longValue(), 0); + } + + @Test + public void testBuilderSuccessPublic() throws FormatException, IOException { + + // GBPMKIRA2OQW2XZZQUCQILI5TMVZ6JNRKM423BSAISDM7ZFWQ6KWEBC4 + KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); + KeyPair destination = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); + + Account account = new Account(source.getAccountId(), 2908908335136768L); + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.PUBLIC) + .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) + .setBaseFee(Transaction.MIN_BASE_FEE) + .build(); + + transaction.sign(source); + + Transaction decodedTransaction = (Transaction) Transaction.fromEnvelopeXdr(AccountConverter.enableMuxed(), transaction.toEnvelopeXdrBase64(), Network.PUBLIC); + assertEquals( + "AAAAAgAAAABexSIg06FtXzmFBQQtHZsrnyWxUzmthkBEhs/ktoeVYgAAAGQAClWjAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAADt4FJhvNwvlQqjuhc7bjLVyRf5e4K2QOzI0c6nWfVvEAAAAASoF8gAAAAAAAAAAAG2h5ViAAAAQOFMVS3lQ1gtqY0a3VPsZXCNVGC/h8dANFiUS7hYPWSbyzi4Ob1ir5R256mOwX+B6vE552+y8JAFaAFPR0bDyAw=", + transaction.toEnvelopeXdrBase64()); + + assertEquals(decodedTransaction, transaction); + } + + @Test + public void testNoOperations() throws FormatException, IOException { + // GBPMKIRA2OQW2XZZQUCQILI5TMVZ6JNRKM423BSAISDM7ZFWQ6KWEBC4 + KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); + + Account account = new Account(source.getAccountId(), 2908908335136768L); + try { + Transaction transaction = new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) + .setBaseFee(Transaction.MIN_BASE_FEE) + .build(); + fail(); + } catch (RuntimeException exception) { + assertTrue(exception.getMessage().contains("At least one operation required")); + assertEquals(new Long(2908908335136768L), account.getSequenceNumber()); + } + } + + @Test + public void testTryingToAddMemoTwice() throws FormatException, IOException { + // GBPMKIRA2OQW2XZZQUCQILI5TMVZ6JNRKM423BSAISDM7ZFWQ6KWEBC4 + KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); + KeyPair destination = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); + + try { + Account account = new Account(source.getAccountId(), 2908908335136768L); + new TransactionBuilder(AccountConverter.enableMuxed(), account, Network.TESTNET) + .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) + .setBaseFee(Transaction.MIN_BASE_FEE) + .addMemo(Memo.none()) + .addMemo(Memo.none()); + fail(); + } catch (RuntimeException exception) { + assertTrue(exception.getMessage().contains("Memo has been already added.")); + } + } + + @Test + public void testNoNetworkSet() throws FormatException { + // GBPMKIRA2OQW2XZZQUCQILI5TMVZ6JNRKM423BSAISDM7ZFWQ6KWEBC4 + KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); + KeyPair destination = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); + + Account account = new Account(source.getAccountId(), 2908908335136768L); + try { + new TransactionBuilder(AccountConverter.enableMuxed(), account, null) + .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) + .setBaseFee(Transaction.MIN_BASE_FEE) + .addMemo(Memo.none()) + .setTimeout(TransactionPreconditions.TIMEOUT_INFINITE) + .build(); + fail(); + } catch (NullPointerException e) { + assertTrue(e.getMessage().contains("Network cannot be null")); + } + } +} \ No newline at end of file diff --git a/src/test/java/org/stellar/sdk/TransactionPreconditionsTest.java b/src/test/java/org/stellar/sdk/TransactionPreconditionsTest.java new file mode 100644 index 000000000..24cdfe772 --- /dev/null +++ b/src/test/java/org/stellar/sdk/TransactionPreconditionsTest.java @@ -0,0 +1,225 @@ +package org.stellar.sdk; + +import com.google.common.io.BaseEncoding; +import org.junit.Test; +import org.stellar.sdk.xdr.Duration; +import org.stellar.sdk.xdr.Int64; +import org.stellar.sdk.xdr.PreconditionType; +import org.stellar.sdk.xdr.Preconditions; +import org.stellar.sdk.xdr.PreconditionsV2; +import org.stellar.sdk.xdr.SequenceNumber; +import org.stellar.sdk.xdr.SignerKey; +import org.stellar.sdk.xdr.SignerKeyType; +import org.stellar.sdk.xdr.TimePoint; +import org.stellar.sdk.xdr.Uint256; +import org.stellar.sdk.xdr.Uint32; +import org.stellar.sdk.xdr.Uint64; +import org.stellar.sdk.xdr.XdrDataInputStream; +import org.stellar.sdk.xdr.XdrDataOutputStream; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import static com.google.common.collect.Lists.newArrayList; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class TransactionPreconditionsTest { + + @Test + public void itConvertsFromXdr() throws IOException { + + Preconditions.Builder preconditionsBuilder = new Preconditions.Builder(); + preconditionsBuilder.discriminant(PreconditionType.PRECOND_V2); + PreconditionsV2.Builder v2Builder = new PreconditionsV2.Builder(); + + v2Builder.extraSigners(new SignerKey[]{}); + v2Builder.minSeqAge(new Duration(new Uint64(2L))); + v2Builder.ledgerBounds(new org.stellar.sdk.xdr.LedgerBounds.Builder() + .minLedger(new Uint32(1)) + .maxLedger(new Uint32(2)) + .build()); + v2Builder.minSeqNum(new SequenceNumber(new Int64(4L))); + v2Builder.minSeqLedgerGap(new Uint32(0)); + preconditionsBuilder.v2(v2Builder.build()); + Preconditions xdr = preconditionsBuilder.build(); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + xdr.encode(new XdrDataOutputStream(baos)); + xdr = Preconditions.decode(new XdrDataInputStream(new ByteArrayInputStream(baos.toByteArray()))); + + TransactionPreconditions transactionPreconditions = TransactionPreconditions.fromXdr(xdr); + + assertEquals(transactionPreconditions.getMinSeqAge(), 2); + assertEquals(transactionPreconditions.getLedgerBounds().getMinLedger(), 1); + assertEquals(transactionPreconditions.getLedgerBounds().getMaxLedger(), 2); + assertEquals(transactionPreconditions.getMinSeqNumber(), Long.valueOf(4)); + assertEquals(transactionPreconditions.getMinSeqLedgerGap(), 0); + } + + @Test + public void itRoundTripsFromV2ToV1IfOnlyTimeboundsPresent() throws IOException { + + Preconditions.Builder preconditionsBuilder = new Preconditions.Builder(); + preconditionsBuilder.discriminant(PreconditionType.PRECOND_V2); + PreconditionsV2.Builder v2Builder = new PreconditionsV2.Builder(); + org.stellar.sdk.xdr.TimeBounds xdrTimeBounds = new org.stellar.sdk.xdr.TimeBounds.Builder().minTime(new TimePoint(new Uint64(1L))).maxTime(new TimePoint(new Uint64(2L))).build(); + v2Builder.timeBounds(xdrTimeBounds); + v2Builder.minSeqLedgerGap(new Uint32(0)); + v2Builder.minSeqAge(new Duration(new Uint64(0L))); + v2Builder.extraSigners(new SignerKey[]{}); + preconditionsBuilder.v2(v2Builder.build()); + // create V2 Precond with just timebounds + Preconditions xdr = preconditionsBuilder.build(); + + // serialize to binary + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + xdr.encode(new XdrDataOutputStream(baos)); + xdr = Preconditions.decode(new XdrDataInputStream(new ByteArrayInputStream(baos.toByteArray()))); + + // marshal it to pojo + TransactionPreconditions transactionPreconditions = TransactionPreconditions.fromXdr(xdr); + assertEquals(transactionPreconditions.getTimeBounds(), new TimeBounds(1L, 2L)); + + // marshal the pojo with just timebounds back to xdr, since only timebounds, precond type should be optimized to V!(PRECOND_TIME) + xdr = transactionPreconditions.toXdr(); + assertEquals(xdr.getDiscriminant() , PreconditionType.PRECOND_TIME); + assertEquals(xdr.getTimeBounds() , xdrTimeBounds); + assertNull(xdr.getV2()); + } + + @Test + public void itConvertsToV2Xdr() throws IOException { + + byte[] payload = BaseEncoding.base16().decode("0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20".toUpperCase()); + SignerKey signerKey = new SignerKey.Builder() + .discriminant(SignerKeyType.SIGNER_KEY_TYPE_ED25519_SIGNED_PAYLOAD) + .ed25519SignedPayload(new SignerKey.SignerKeyEd25519SignedPayload.Builder() + .payload(payload) + .ed25519(new Uint256(StrKey.decodeStellarAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"))) + .build()) + .build(); + + TransactionPreconditions preconditions = TransactionPreconditions.builder() + .timeBounds(new TimeBounds(1, 2)) + .minSeqNumber(3L) + .extraSigners(newArrayList(signerKey, signerKey, signerKey)) + .build(); + + Preconditions xdr = preconditions.toXdr(); + + // serialize to binary + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + xdr.encode(new XdrDataOutputStream(baos)); + xdr = Preconditions.decode(new XdrDataInputStream(new ByteArrayInputStream(baos.toByteArray()))); + + assertEquals(xdr.getDiscriminant(), PreconditionType.PRECOND_V2); + assertEquals(xdr.getV2().getTimeBounds().getMinTime().getTimePoint().getUint64(), Long.valueOf(1)); + assertEquals(xdr.getV2().getTimeBounds().getMaxTime().getTimePoint().getUint64(), Long.valueOf(2)); + assertEquals(xdr.getV2().getMinSeqNum().getSequenceNumber().getInt64(), Long.valueOf(3)); + // xdr encoding requires non-null for min ledger gap + assertEquals(xdr.getV2().getMinSeqLedgerGap().getUint32().intValue(), 0); + // xdr encoding requires non-null for min seq age + assertEquals(xdr.getV2().getMinSeqAge().getDuration().getUint64().longValue(), 0); + assertEquals(xdr.getV2().getExtraSigners().length, 3); + } + + @Test + public void itConvertsOnlyTimeBoundsXdr() throws IOException{ + TransactionPreconditions preconditions = TransactionPreconditions.builder() + .timeBounds(new TimeBounds(1, 2)) + .build(); + + Preconditions xdr = preconditions.toXdr(); + + // serialize to binary + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + xdr.encode(new XdrDataOutputStream(baos)); + xdr = Preconditions.decode(new XdrDataInputStream(new ByteArrayInputStream(baos.toByteArray()))); + + assertEquals(xdr.getDiscriminant(), PreconditionType.PRECOND_TIME); + assertEquals(xdr.getTimeBounds().getMinTime().getTimePoint().getUint64(), Long.valueOf(1)); + assertEquals(xdr.getTimeBounds().getMaxTime().getTimePoint().getUint64(), Long.valueOf(2)); + assertNull(xdr.getV2()); + } + + @Test + public void itConvertsNullTimeBoundsXdr() throws IOException { + // there was precedence in the sdk test coverage in TransactionTest.java for edge case of passing a null timebounds + // into a transaction, which occurrs when infinite timeout is set and timebounds is not set through TransactionBuilder. + // TransactionPreconditions continues to support that edge case. + TransactionPreconditions preconditions = TransactionPreconditions.builder().build(); + + Preconditions xdr = preconditions.toXdr(); + + // serialize to binary + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + xdr.encode(new XdrDataOutputStream(baos)); + xdr = Preconditions.decode(new XdrDataInputStream(new ByteArrayInputStream(baos.toByteArray()))); + + assertEquals(xdr.getDiscriminant(), PreconditionType.PRECOND_NONE); + assertNull(xdr.getTimeBounds()); + } + + @Test + public void itChecksValidityWhenTimebounds() { + TransactionPreconditions preconditions = TransactionPreconditions.builder().timeBounds(new TimeBounds(1, 2)).build(); + preconditions.isValid(); + } + + @Test + public void itChecksNonValidityOfTimeBounds() { + TransactionPreconditions preconditions = TransactionPreconditions.builder().build(); + try { + preconditions.isValid(); + fail(); + } catch (FormatException ignored) {} + } + + @Test + public void itChecksNonValidityOfExtraSignersSize() { + TransactionPreconditions preconditions = TransactionPreconditions.builder() + .timeBounds(new TimeBounds(1, 2)) + .extraSigners(newArrayList(new SignerKey.Builder().build(), new SignerKey.Builder().build(), new SignerKey.Builder().build())) + .build(); + try { + preconditions.isValid(); + fail(); + } catch (FormatException ignored) {} + } + + @Test + public void itChecksValidityWhenNoTimeboundsSet() { + TransactionPreconditions preconditions = TransactionPreconditions.builder().build(); + try { + preconditions.isValid(); + fail(); + } catch (FormatException exception) { + assertTrue(exception.getMessage().contains("Invalid preconditions, must define timebounds")); + } + } + + + @Test + public void itChecksV2Status() { + Preconditions.Builder preconditionsBuilder = new Preconditions.Builder(); + preconditionsBuilder.discriminant(PreconditionType.PRECOND_V2); + PreconditionsV2.Builder v2Builder = new PreconditionsV2.Builder(); + + v2Builder.extraSigners(new SignerKey[]{}); + v2Builder.minSeqAge(new Duration(new Uint64(2L))); + v2Builder.ledgerBounds(new org.stellar.sdk.xdr.LedgerBounds.Builder() + .minLedger(new Uint32(1)) + .maxLedger(new Uint32(2)) + .build()); + v2Builder.minSeqNum(new SequenceNumber(new Int64(4L))); + preconditionsBuilder.v2(v2Builder.build()); + Preconditions xdr = preconditionsBuilder.build(); + + TransactionPreconditions transactionPreconditions = TransactionPreconditions.fromXdr(xdr); + assertTrue(transactionPreconditions.hasV2()); + } +} diff --git a/src/test/java/org/stellar/sdk/TransactionTest.java b/src/test/java/org/stellar/sdk/TransactionTest.java index 681d18d2b..1d6c2ee82 100644 --- a/src/test/java/org/stellar/sdk/TransactionTest.java +++ b/src/test/java/org/stellar/sdk/TransactionTest.java @@ -1,369 +1,91 @@ package org.stellar.sdk; +import com.google.common.io.BaseEncoding; import org.junit.Test; +import org.stellar.sdk.xdr.DecoratedSignature; import org.stellar.sdk.xdr.EnvelopeType; +import org.stellar.sdk.xdr.SignerKey; import org.stellar.sdk.xdr.XdrDataInputStream; import java.io.ByteArrayInputStream; import java.io.IOException; import java.security.SecureRandom; +import java.util.ArrayList; import java.util.Arrays; -import static org.junit.Assert.*; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; public class TransactionTest { @Test - public void testMissingOperationFee() { - long sequenceNumber = 2908908335136768L; - Account account = new Account("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR", sequenceNumber); - try { - new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.TESTNET) - .addOperation(new CreateAccountOperation.Builder("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR", "2000").build()) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) - .build(); - fail("expected RuntimeException"); - } catch (RuntimeException e) { - // expected - } - } - - @Test - public void testBuilderSuccessTestnet() throws FormatException { - // GBPMKIRA2OQW2XZZQUCQILI5TMVZ6JNRKM423BSAISDM7ZFWQ6KWEBC4 - KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); - KeyPair destination = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); - - long sequenceNumber = 2908908335136768L; - Account account = new Account(source.getAccountId(), sequenceNumber); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.TESTNET) - .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) - .setBaseFee(Transaction.MIN_BASE_FEE) - .build(); - - transaction.sign(source); - - assertEquals( - "AAAAAgAAAABexSIg06FtXzmFBQQtHZsrnyWxUzmthkBEhs/ktoeVYgAAAGQAClWjAAAAAQAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAO3gUmG83C+VCqO6FztuMtXJF/l7grZA7MjRzqdZ9W8QAAAABKgXyAAAAAAAAAAAAbaHlWIAAABAy5IvTou9NDetC6PIFJhBR2yr2BuEEql4iyLfU9K7tjuQaYVZf40fbWLRwA/lHg2IYFzYMFMakxLtVrpLxMmHAw==", - transaction.toEnvelopeXdrBase64()); - - assertEquals(transaction.getSourceAccount(), source.getAccountId()); - assertEquals(transaction.getSequenceNumber(), sequenceNumber + 1); - assertEquals(transaction.getFee(), 100); - - Transaction transaction2 = (Transaction)Transaction.fromEnvelopeXdr(AccountConverter.enableMuxed(), transaction.toEnvelopeXdr(), Network.TESTNET); - - assertEquals(transaction.getSourceAccount(), transaction2.getSourceAccount()); - assertEquals(transaction.getSequenceNumber(), transaction2.getSequenceNumber()); - assertEquals(transaction.getFee(), transaction2.getFee()); - assertEquals( - ((CreateAccountOperation) transaction.getOperations()[0]).getStartingBalance(), - ((CreateAccountOperation) transaction2.getOperations()[0]).getStartingBalance() - ); - - assertEquals(transaction.getSignatures(), transaction2.getSignatures()); - } + public void testParseV0Transaction() throws FormatException, IOException { - @Test - public void testBuilderMemoText() throws FormatException { // GBPMKIRA2OQW2XZZQUCQILI5TMVZ6JNRKM423BSAISDM7ZFWQ6KWEBC4 KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); KeyPair destination = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); Account account = new Account(source.getAccountId(), 2908908335136768L); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.TESTNET) - .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) - .addMemo(Memo.text("Hello world!")) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) - .setBaseFee(Transaction.MIN_BASE_FEE) - .build(); - - transaction.sign(source); - - assertEquals( - "AAAAAgAAAABexSIg06FtXzmFBQQtHZsrnyWxUzmthkBEhs/ktoeVYgAAAGQAClWjAAAAAQAAAAAAAAABAAAADEhlbGxvIHdvcmxkIQAAAAEAAAAAAAAAAAAAAADt4FJhvNwvlQqjuhc7bjLVyRf5e4K2QOzI0c6nWfVvEAAAAASoF8gAAAAAAAAAAAG2h5ViAAAAQMc6HwYaGsrlJ8/LdE9VDVq04JifpQofSmnjhrtqaTTs/VBsNGmxi4b/vaFkLLLWh8emI8FsS/vBgb8AVFVkZQU=", - transaction.toEnvelopeXdrBase64()); - - Transaction transaction2 = (Transaction)Transaction.fromEnvelopeXdr(AccountConverter.enableMuxed(), transaction.toEnvelopeXdr(), Network.TESTNET); - assertEquals(transaction.getSourceAccount(), transaction2.getSourceAccount()); - assertEquals(transaction.getSequenceNumber(), transaction2.getSequenceNumber()); - assertEquals(transaction.getMemo(), transaction2.getMemo()); - assertEquals(transaction.getFee(), transaction2.getFee()); - assertEquals( - ((CreateAccountOperation) transaction.getOperations()[0]).getStartingBalance(), - ((CreateAccountOperation) transaction2.getOperations()[0]).getStartingBalance() + Transaction transaction = new Transaction( + AccountConverter.enableMuxed(), + account.getAccountId(), + Transaction.MIN_BASE_FEE, + account.getIncrementedSequenceNumber(), + new org.stellar.sdk.Operation[]{new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()}, + null, + new TransactionPreconditions(null, null, 0, 0, new ArrayList(),null), + Network.PUBLIC ); - } - - @Test - public void testBuilderTimeBounds() throws FormatException, IOException { - // GBPMKIRA2OQW2XZZQUCQILI5TMVZ6JNRKM423BSAISDM7ZFWQ6KWEBC4 - KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); - KeyPair destination = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); - - Account account = new Account(source.getAccountId(), 2908908335136768L); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.TESTNET) - .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) - .addTimeBounds(new TimeBounds(42, 1337)) - .addMemo(Memo.hash("abcdef")) - .setBaseFee(Transaction.MIN_BASE_FEE) - .build(); + transaction.setEnvelopeType(EnvelopeType.ENVELOPE_TYPE_TX_V0); transaction.sign(source); - // Convert transaction to binary XDR and back again to make sure timebounds are correctly de/serialized. - XdrDataInputStream is = new XdrDataInputStream( - new ByteArrayInputStream( - javax.xml.bind.DatatypeConverter.parseBase64Binary(transaction.toEnvelopeXdrBase64()) - ) - ); + XdrDataInputStream is = new XdrDataInputStream(new ByteArrayInputStream(BaseEncoding.base64().decode(transaction.toEnvelopeXdrBase64()))); org.stellar.sdk.xdr.TransactionEnvelope decodedTransaction = org.stellar.sdk.xdr.TransactionEnvelope.decode(is); + assertEquals(EnvelopeType.ENVELOPE_TYPE_TX_V0, decodedTransaction.getDiscriminant()); - assertEquals(decodedTransaction.getV1().getTx().getTimeBounds().getMinTime().getTimePoint().getUint64().longValue(), 42); - assertEquals(decodedTransaction.getV1().getTx().getTimeBounds().getMaxTime().getTimePoint().getUint64().longValue(), 1337); - - Transaction transaction2 = (Transaction)Transaction.fromEnvelopeXdr(AccountConverter.enableMuxed(), transaction.toEnvelopeXdr(), Network.TESTNET); - - assertEquals(transaction.getSourceAccount(), transaction2.getSourceAccount()); - assertEquals(transaction.getSequenceNumber(), transaction2.getSequenceNumber()); - assertEquals(transaction.getMemo(), transaction2.getMemo()); - assertEquals(transaction.getTimeBounds(), transaction2.getTimeBounds()); - assertEquals(transaction.getFee(), transaction2.getFee()); - assertEquals( - ((CreateAccountOperation) transaction.getOperations()[0]).getStartingBalance(), - ((CreateAccountOperation) transaction2.getOperations()[0]).getStartingBalance() - ); - } - - @Test - public void testBuilderBaseFee() throws FormatException { - // GBPMKIRA2OQW2XZZQUCQILI5TMVZ6JNRKM423BSAISDM7ZFWQ6KWEBC4 - KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); - KeyPair destination = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); - - Account account = new Account(source.getAccountId(), 2908908335136768L); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.TESTNET) - .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) - .setBaseFee(200) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) - .build(); - - transaction.sign(source); + Transaction parsed = (Transaction) Transaction.fromEnvelopeXdr(AccountConverter.enableMuxed(), transaction.toEnvelopeXdrBase64(), Network.PUBLIC); + assertTrue(parsed.equals(transaction)); + assertEquals(EnvelopeType.ENVELOPE_TYPE_TX_V0, parsed.toEnvelopeXdr().getDiscriminant()); + assertEquals(transaction.toEnvelopeXdrBase64(), parsed.toEnvelopeXdrBase64()); assertEquals( - "AAAAAgAAAABexSIg06FtXzmFBQQtHZsrnyWxUzmthkBEhs/ktoeVYgAAAMgAClWjAAAAAQAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAO3gUmG83C+VCqO6FztuMtXJF/l7grZA7MjRzqdZ9W8QAAAABKgXyAAAAAAAAAAAAbaHlWIAAABA9TG3dKKLtLHzRUbsbEqr68CfUc800p1/LE5pWzCnFdFdypdXgyqHqw/sWdaTUMDiWawBtsmqV8oOtD0Hw1HDDQ==", + "AAAAAF7FIiDToW1fOYUFBC0dmyufJbFTOa2GQESGz+S2h5ViAAAAZAAKVaMAAAABAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAA7eBSYbzcL5UKo7oXO24y1ckX+XuCtkDsyNHOp1n1bxAAAAAEqBfIAAAAAAAAAAABtoeVYgAAAEDzfR5PgRFim5Wdvq9ImdZNWGBxBWwYkQPa9l5iiBdtPLzAZv6qj+iOfSrqinsoF0XrLkwdIcZQVtp3VRHhRoUE", transaction.toEnvelopeXdrBase64()); - Transaction transaction2 = (Transaction)Transaction.fromEnvelopeXdr(AccountConverter.enableMuxed(), transaction.toEnvelopeXdr(), Network.TESTNET); - - assertEquals(transaction.getSourceAccount(), transaction2.getSourceAccount()); - assertEquals(transaction.getSequenceNumber(), transaction2.getSequenceNumber()); - assertEquals(transaction.getFee(), transaction2.getFee()); - assertEquals( - ((CreateAccountOperation) transaction.getOperations()[0]).getStartingBalance(), - ((CreateAccountOperation) transaction2.getOperations()[0]).getStartingBalance() - ); - } - - @Test - public void testBuilderBaseFeeThrows() throws FormatException { - // GBPMKIRA2OQW2XZZQUCQILI5TMVZ6JNRKM423BSAISDM7ZFWQ6KWEBC4 - KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); - - Account account = new Account(source.getAccountId(), 2908908335136768L); - Transaction.Builder builder = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.TESTNET); - try { - builder.setBaseFee(99); - fail("expected IllegalArgumentException"); - } catch (IllegalArgumentException e) { - // expected - } - } - - @Test - public void testBuilderWithTimeBoundsButNoTimeout() throws IOException { - Account account = new Account(KeyPair.random().getAccountId(), 2908908335136768L); - new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.TESTNET) - .addOperation(new CreateAccountOperation.Builder(KeyPair.random().getAccountId(), "2000").build()) - .addTimeBounds(new TimeBounds(42, 1337)) - .addMemo(Memo.hash("abcdef")) - .setBaseFee(Transaction.MIN_BASE_FEE) - .build(); } @Test - public void testBuilderRequiresTimeoutOrTimeBounds() throws IOException { - Account account = new Account(KeyPair.random().getAccountId(), 2908908335136768L); - try { - new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.TESTNET) - .addOperation(new CreateAccountOperation.Builder(KeyPair.random().getAccountId(), "2000").build()) - .addMemo(Memo.hash("abcdef")) - .setBaseFee(Transaction.MIN_BASE_FEE) - .build(); - fail(); - } catch (RuntimeException exception) { - assertEquals( - exception.getMessage(), - "TimeBounds has to be set or you must call setTimeout(TIMEOUT_INFINITE)." - ); - } - } - - - @Test - public void testBuilderTimeoutNegative() throws IOException { - Account account = new Account(KeyPair.random().getAccountId(), 2908908335136768L); - try { - new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.TESTNET) - .addOperation(new CreateAccountOperation.Builder(KeyPair.random().getAccountId(), "2000").build()) - .addMemo(Memo.hash("abcdef")) - .setTimeout(-1) - .build(); - fail(); - } catch (RuntimeException exception) { - assertTrue(exception.getMessage().contains("timeout cannot be negative")); - assertEquals(new Long(2908908335136768L), account.getSequenceNumber()); - } - } + public void testAddingSignaturesDirectly() { + KeyPair source = KeyPair.fromAccountId("GBBM6BKZPEHWYO3E3YKREDPQXMS4VK35YLNU7NFBRI26RAN7GI5POFBB"); + KeyPair destination = KeyPair.fromAccountId("GDJJRRMBK4IWLEPJGIE6SXD2LP7REGZODU7WDC3I2D6MR37F4XSHBKX2"); - @Test - public void testBuilderTimeoutSetsTimeBounds() throws IOException { - Account account = new Account(KeyPair.random().getAccountId(), 2908908335136768L); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.TESTNET) - .addOperation(new CreateAccountOperation.Builder(KeyPair.random().getAccountId(), "2000").build()) - .setTimeout(10) - .setBaseFee(Transaction.MIN_BASE_FEE) - .build(); + Account account = new Account(source.getAccountId(), 0L); - assertEquals(0, transaction.getTimeBounds().getMinTime()); - long currentUnix = System.currentTimeMillis() / 1000L; - assertEquals(currentUnix + 10, transaction.getTimeBounds().getMaxTime()); - } + Transaction transaction = new Transaction( + AccountConverter.disableMuxed(), + account.getAccountId(), + Transaction.MIN_BASE_FEE, + account.getIncrementedSequenceNumber(), + new org.stellar.sdk.Operation[]{new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()}, + null, + new TransactionPreconditions(null, null, 0, 0, new ArrayList(),null), + Network.PUBLIC + ); - @Test - public void testBuilderFailsWhenSettingTimeoutAndMaxTimeAlreadySet() throws IOException { - Account account = new Account(KeyPair.random().getAccountId(), 2908908335136768L); + assertEquals(0, transaction.getSignatures().size()); try { - new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.TESTNET) - .addOperation(new CreateAccountOperation.Builder(KeyPair.random().getAccountId(), "2000").build()) - .addTimeBounds(new TimeBounds(42, 1337)) - .setTimeout(10) - .build(); + // should not be able to change the list of signatures directly + transaction.getSignatures().add(new DecoratedSignature()); fail(); - } catch (RuntimeException exception) { - assertTrue(exception.getMessage().contains("TimeBounds.max_time has been already set")); - assertEquals(new Long(2908908335136768L), account.getSequenceNumber()); - } - } + } catch (UnsupportedOperationException ignored) {} - @Test - public void testBuilderFailsWhenSettingTimeoutAndMaxTimeNotSet() throws IOException { - Account account = new Account(KeyPair.random().getAccountId(), 2908908335136768L); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.TESTNET) - .addOperation(new CreateAccountOperation.Builder(KeyPair.random().getAccountId(), "2000").build()) - .addTimeBounds(new TimeBounds(42, 0)) - .setTimeout(10) - .setBaseFee(Transaction.MIN_BASE_FEE) - .build(); - - assertEquals(42, transaction.getTimeBounds().getMinTime()); - // Should add max_time - long currentUnix = System.currentTimeMillis() / 1000L; - assertEquals(currentUnix + 10, transaction.getTimeBounds().getMaxTime()); - } - - @Test - public void testBuilderTimeBoundsNoMaxTime() throws FormatException, IOException { - // GBPMKIRA2OQW2XZZQUCQILI5TMVZ6JNRKM423BSAISDM7ZFWQ6KWEBC4 - KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); - KeyPair destination = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); - - Account account = new Account(source.getAccountId(), 2908908335136768L); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.TESTNET) - .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) - .addTimeBounds(new TimeBounds(42, 0)) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) - .addMemo(Memo.hash("abcdef")) - .setBaseFee(100) - .build(); - - transaction.sign(source); - - // Convert transaction to binary XDR and back again to make sure timebounds are correctly de/serialized. - XdrDataInputStream is = new XdrDataInputStream( - new ByteArrayInputStream( - javax.xml.bind.DatatypeConverter.parseBase64Binary(transaction.toEnvelopeXdrBase64()) - ) - ); - org.stellar.sdk.xdr.TransactionEnvelope decodedTransaction = org.stellar.sdk.xdr.TransactionEnvelope.decode(is); - - assertEquals(decodedTransaction.getV1().getTx().getTimeBounds().getMinTime().getTimePoint().getUint64().longValue(), 42); - assertEquals(decodedTransaction.getV1().getTx().getTimeBounds().getMaxTime().getTimePoint().getUint64().longValue(), 0); - } - - @Test - public void testBuilderSuccessPublic() throws FormatException, IOException { - - // GBPMKIRA2OQW2XZZQUCQILI5TMVZ6JNRKM423BSAISDM7ZFWQ6KWEBC4 - KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); - KeyPair destination = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); - - Account account = new Account(source.getAccountId(), 2908908335136768L); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.PUBLIC) - .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) - .setBaseFee(Transaction.MIN_BASE_FEE) - .build(); - - transaction.sign(source); - - XdrDataInputStream is = new XdrDataInputStream( - new ByteArrayInputStream( - javax.xml.bind.DatatypeConverter.parseBase64Binary(transaction.toEnvelopeXdrBase64()) - ) - ); - org.stellar.sdk.xdr.TransactionEnvelope decodedTransaction = org.stellar.sdk.xdr.TransactionEnvelope.decode(is); - assertEquals(EnvelopeType.ENVELOPE_TYPE_TX, decodedTransaction.getDiscriminant()); - - assertEquals( - "AAAAAgAAAABexSIg06FtXzmFBQQtHZsrnyWxUzmthkBEhs/ktoeVYgAAAGQAClWjAAAAAQAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAO3gUmG83C+VCqO6FztuMtXJF/l7grZA7MjRzqdZ9W8QAAAABKgXyAAAAAAAAAAAAbaHlWIAAABA830eT4ERYpuVnb6vSJnWTVhgcQVsGJED2vZeYogXbTy8wGb+qo/ojn0q6op7KBdF6y5MHSHGUFbad1UR4UaFBA==", - transaction.toEnvelopeXdrBase64()); - } - - @Test - public void testParseV0Transaction() throws FormatException, IOException { - - // GBPMKIRA2OQW2XZZQUCQILI5TMVZ6JNRKM423BSAISDM7ZFWQ6KWEBC4 - KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); - KeyPair destination = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); - - Account account = new Account(source.getAccountId(), 2908908335136768L); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.PUBLIC) - .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) - .setBaseFee(Transaction.MIN_BASE_FEE) - .build(); - transaction.setEnvelopeType(EnvelopeType.ENVELOPE_TYPE_TX_V0); - transaction.sign(source); - - XdrDataInputStream is = new XdrDataInputStream( - new ByteArrayInputStream( - javax.xml.bind.DatatypeConverter.parseBase64Binary(transaction.toEnvelopeXdrBase64()) - ) - ); - org.stellar.sdk.xdr.TransactionEnvelope decodedTransaction = org.stellar.sdk.xdr.TransactionEnvelope.decode(is); - assertEquals(EnvelopeType.ENVELOPE_TYPE_TX_V0, decodedTransaction.getDiscriminant()); - - Transaction parsed = (Transaction) Transaction.fromEnvelopeXdr(AccountConverter.enableMuxed(), transaction.toEnvelopeXdrBase64(), Network.PUBLIC); - assertTrue(parsed.equals(transaction)); - assertEquals(EnvelopeType.ENVELOPE_TYPE_TX_V0, parsed.toEnvelopeXdr().getDiscriminant()); - - assertEquals( - "AAAAAF7FIiDToW1fOYUFBC0dmyufJbFTOa2GQESGz+S2h5ViAAAAZAAKVaMAAAABAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAA7eBSYbzcL5UKo7oXO24y1ckX+XuCtkDsyNHOp1n1bxAAAAAEqBfIAAAAAAAAAAABtoeVYgAAAEDzfR5PgRFim5Wdvq9ImdZNWGBxBWwYkQPa9l5iiBdtPLzAZv6qj+iOfSrqinsoF0XrLkwdIcZQVtp3VRHhRoUE", - transaction.toEnvelopeXdrBase64()); - assertEquals(transaction.toEnvelopeXdrBase64(), parsed.toEnvelopeXdrBase64()); + // should only be able to add signatures through interface + transaction.addSignature(new DecoratedSignature()); + assertEquals(1, transaction.getSignatures().size()); } @Test @@ -372,11 +94,17 @@ public void testSha256HashSigning() throws FormatException { KeyPair destination = KeyPair.fromAccountId("GDJJRRMBK4IWLEPJGIE6SXD2LP7REGZODU7WDC3I2D6MR37F4XSHBKX2"); Account account = new Account(source.getAccountId(), 0L); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.PUBLIC) - .addOperation(new PaymentOperation.Builder(destination.getAccountId(), new AssetTypeNative(), "2000").build()) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) - .setBaseFee(Transaction.MIN_BASE_FEE) - .build(); + + Transaction transaction = new Transaction( + AccountConverter.disableMuxed(), + account.getAccountId(), + Transaction.MIN_BASE_FEE, + account.getIncrementedSequenceNumber(), + new org.stellar.sdk.Operation[]{new PaymentOperation.Builder(destination.getAccountId(), new AssetTypeNative(), "2000").build()}, + null, + new TransactionPreconditions(null, null, 0, 0, new ArrayList(),null), + Network.PUBLIC + ); byte[] preimage = new byte[64]; new SecureRandom().nextBytes(preimage); @@ -398,70 +126,23 @@ public void testToBase64EnvelopeXdrBuilderNoSignatures() throws FormatException, KeyPair destination = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); Account account = new Account(source.getAccountId(), 2908908335136768L); - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.TESTNET) - .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) - .setBaseFee(Transaction.MIN_BASE_FEE) - .build(); + Transaction transaction = new Transaction( + AccountConverter.enableMuxed(), + account.getAccountId(), + Transaction.MIN_BASE_FEE, + account.getIncrementedSequenceNumber(), + new org.stellar.sdk.Operation[]{new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()}, + null, + new TransactionPreconditions(null, null, 0, 0, new ArrayList(),null), + Network.TESTNET + ); + + Transaction parsed = (Transaction) Transaction.fromEnvelopeXdr(AccountConverter.enableMuxed(), transaction.toEnvelopeXdrBase64(), Network.TESTNET); + assertEquals(parsed, transaction); assertEquals( "AAAAAgAAAABexSIg06FtXzmFBQQtHZsrnyWxUzmthkBEhs/ktoeVYgAAAGQAClWjAAAAAQAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAO3gUmG83C+VCqO6FztuMtXJF/l7grZA7MjRzqdZ9W8QAAAABKgXyAAAAAAAAAAAAA==", transaction.toEnvelopeXdrBase64() ); } - - @Test - public void testNoOperations() throws FormatException, IOException { - // GBPMKIRA2OQW2XZZQUCQILI5TMVZ6JNRKM423BSAISDM7ZFWQ6KWEBC4 - KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); - - Account account = new Account(source.getAccountId(), 2908908335136768L); - try { - Transaction transaction = new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.TESTNET) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) - .setBaseFee(Transaction.MIN_BASE_FEE) - .build(); - fail(); - } catch (RuntimeException exception) { - assertTrue(exception.getMessage().contains("At least one operation required")); - assertEquals(new Long(2908908335136768L), account.getSequenceNumber()); - } - } - - @Test - public void testTryingToAddMemoTwice() throws FormatException, IOException { - // GBPMKIRA2OQW2XZZQUCQILI5TMVZ6JNRKM423BSAISDM7ZFWQ6KWEBC4 - KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); - KeyPair destination = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); - - try { - Account account = new Account(source.getAccountId(), 2908908335136768L); - new Transaction.Builder(AccountConverter.enableMuxed(), account, Network.TESTNET) - .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) - .addMemo(Memo.none()) - .addMemo(Memo.none()); - fail(); - } catch (RuntimeException exception) { - assertTrue(exception.getMessage().contains("Memo has been already added.")); - } - } - - @Test - public void testNoNetworkSet() throws FormatException { - // GBPMKIRA2OQW2XZZQUCQILI5TMVZ6JNRKM423BSAISDM7ZFWQ6KWEBC4 - KeyPair source = KeyPair.fromSecretSeed("SCH27VUZZ6UAKB67BDNF6FA42YMBMQCBKXWGMFD5TZ6S5ZZCZFLRXKHS"); - KeyPair destination = KeyPair.fromAccountId("GDW6AUTBXTOC7FIKUO5BOO3OGLK4SF7ZPOBLMQHMZDI45J2Z6VXRB5NR"); - - Account account = new Account(source.getAccountId(), 2908908335136768L); - try { - new Transaction.Builder(AccountConverter.enableMuxed(), account, null) - .addOperation(new CreateAccountOperation.Builder(destination.getAccountId(), "2000").build()) - .addMemo(Memo.none()) - .setTimeout(Transaction.Builder.TIMEOUT_INFINITE) - .build(); - fail(); - } catch (NullPointerException e) { - assertTrue(e.getMessage().contains("Network cannot be null")); - } - } } \ No newline at end of file diff --git a/src/test/java/org/stellar/sdk/responses/AccountDeserializerTest.java b/src/test/java/org/stellar/sdk/responses/AccountDeserializerTest.java index 869ec5a64..698b4b519 100644 --- a/src/test/java/org/stellar/sdk/responses/AccountDeserializerTest.java +++ b/src/test/java/org/stellar/sdk/responses/AccountDeserializerTest.java @@ -37,9 +37,11 @@ public void testDeserializeBalanceAuth() { @Test public void testDeserialize() { AccountResponse account = GsonSingleton.getInstance().fromJson(json, AccountResponse.class); - assertEquals(account.getAccountId(), "GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN7"); + assertEquals(account.getAccountId(), "GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN7"); assertEquals(account.getSequenceNumber(), new Long(2319149195853854L)); assertEquals(account.getSubentryCount(), new Integer(0)); + assertEquals(account.getSequenceUpdatedAtLedger().longValue(),1234) ; + assertEquals(account.getSequenceUpdatedAtTime().longValue(),4567) ; assertEquals(account.getInflationDestination(), "GAGRSA6QNQJN2OQYCBNQGMFLO4QLZFNEHIFXOMTQVSUTWVTWT66TOFSC"); assertEquals(account.getHomeDomain(), "stellar.org"); assertFalse(account.getSponsor().isPresent()); @@ -250,6 +252,8 @@ public void testDeserializeLiquidityPoolBalanc() { " \"paging_token\": \"1\",\n" + " \"account_id\": \"GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN7\",\n" + " \"sequence\": 2319149195853854,\n" + + " \"sequence_ledger\": 1234,\n" + + " \"sequence_time\": 4567,\n" + " \"subentry_count\": 0,\n" + " \"inflation_destination\": \"GAGRSA6QNQJN2OQYCBNQGMFLO4QLZFNEHIFXOMTQVSUTWVTWT66TOFSC\",\n" + " \"home_domain\": \"stellar.org\",\n" + diff --git a/src/test/java/org/stellar/sdk/responses/ClaimableBalancePageDeserializerTest.java b/src/test/java/org/stellar/sdk/responses/ClaimableBalancePageDeserializerTest.java index b53516305..b7b054ae8 100644 --- a/src/test/java/org/stellar/sdk/responses/ClaimableBalancePageDeserializerTest.java +++ b/src/test/java/org/stellar/sdk/responses/ClaimableBalancePageDeserializerTest.java @@ -34,7 +34,7 @@ public void testDeserialize() { Predicate.AbsBefore absBefore = (Predicate.AbsBefore)or.getInner().get(0); Predicate.RelBefore relBefore = (Predicate.RelBefore)or.getInner().get(1); assertEquals(absBefore.getDate().toString(), "2020-09-28T17:57:04Z"); - assertEquals(relBefore.getSecondsSinceClose(), 12); + assertEquals(relBefore.getSecondsSinceClose(), 12L); assertEquals(claimableBalancePage.getRecords().get(1).getId(), "00000000ae76f49e8513d0922b6bcbc8a3f5c4c0a5161871f27924e08724646acab56cd3"); assertEquals(claimableBalancePage.getRecords().get(1).getAsset(), Asset.create("native")); diff --git a/src/test/java/org/stellar/sdk/responses/EffectDeserializerTest.java b/src/test/java/org/stellar/sdk/responses/EffectDeserializerTest.java index 431c8e89e..c9bc17c76 100644 --- a/src/test/java/org/stellar/sdk/responses/EffectDeserializerTest.java +++ b/src/test/java/org/stellar/sdk/responses/EffectDeserializerTest.java @@ -1,13 +1,37 @@ package org.stellar.sdk.responses; import junit.framework.TestCase; - import org.junit.Test; -import org.stellar.sdk.Asset; import org.stellar.sdk.AssetAmount; import org.stellar.sdk.AssetTypeNative; import org.stellar.sdk.Predicate; -import org.stellar.sdk.responses.effects.*; +import org.stellar.sdk.responses.effects.AccountCreatedEffectResponse; +import org.stellar.sdk.responses.effects.AccountCreditedEffectResponse; +import org.stellar.sdk.responses.effects.AccountDebitedEffectResponse; +import org.stellar.sdk.responses.effects.AccountFlagsUpdatedEffectResponse; +import org.stellar.sdk.responses.effects.AccountHomeDomainUpdatedEffectResponse; +import org.stellar.sdk.responses.effects.AccountInflationDestinationUpdatedEffectResponse; +import org.stellar.sdk.responses.effects.AccountRemovedEffectResponse; +import org.stellar.sdk.responses.effects.AccountThresholdsUpdatedEffectResponse; +import org.stellar.sdk.responses.effects.ClaimableBalanceClaimantCreatedEffectResponse; +import org.stellar.sdk.responses.effects.ClaimableBalanceClawedBackEffectResponse; +import org.stellar.sdk.responses.effects.DataCreatedEffectResponse; +import org.stellar.sdk.responses.effects.DataRemovedEffectResponse; +import org.stellar.sdk.responses.effects.DataUpdatedEffectResponse; +import org.stellar.sdk.responses.effects.EffectResponse; +import org.stellar.sdk.responses.effects.LiquidityPoolTradeEffectResponse; +import org.stellar.sdk.responses.effects.SequenceBumpedEffectResponse; +import org.stellar.sdk.responses.effects.SignerCreatedEffectResponse; +import org.stellar.sdk.responses.effects.SignerRemovedEffectResponse; +import org.stellar.sdk.responses.effects.SignerUpdatedEffectResponse; +import org.stellar.sdk.responses.effects.TradeEffectResponse; +import org.stellar.sdk.responses.effects.TrustlineAuthorizedEffectResponse; +import org.stellar.sdk.responses.effects.TrustlineAuthorizedToMaintainLiabilitiesEffectResponse; +import org.stellar.sdk.responses.effects.TrustlineCreatedEffectResponse; +import org.stellar.sdk.responses.effects.TrustlineDeauthorizedEffectResponse; +import org.stellar.sdk.responses.effects.TrustlineFlagsUpdatedEffectResponse; +import org.stellar.sdk.responses.effects.TrustlineRemovedEffectResponse; +import org.stellar.sdk.responses.effects.TrustlineUpdatedEffectResponse; import org.stellar.sdk.xdr.LiquidityPoolType; import java.util.Arrays; diff --git a/src/test/java/org/stellar/sdk/responses/OperationDeserializerTest.java b/src/test/java/org/stellar/sdk/responses/OperationDeserializerTest.java index 19bde0c35..9ee801760 100644 --- a/src/test/java/org/stellar/sdk/responses/OperationDeserializerTest.java +++ b/src/test/java/org/stellar/sdk/responses/OperationDeserializerTest.java @@ -4,8 +4,34 @@ import com.google.common.collect.Lists; import junit.framework.TestCase; import org.junit.Test; -import org.stellar.sdk.*; -import org.stellar.sdk.responses.operations.*; +import org.stellar.sdk.Asset; +import org.stellar.sdk.AssetAmount; +import org.stellar.sdk.AssetTypeNative; +import org.stellar.sdk.AssetTypePoolShare; +import org.stellar.sdk.FormatException; +import org.stellar.sdk.Predicate; +import org.stellar.sdk.Price; +import org.stellar.sdk.responses.operations.AccountMergeOperationResponse; +import org.stellar.sdk.responses.operations.AllowTrustOperationResponse; +import org.stellar.sdk.responses.operations.BumpSequenceOperationResponse; +import org.stellar.sdk.responses.operations.ChangeTrustOperationResponse; +import org.stellar.sdk.responses.operations.ClaimClaimableBalanceOperationResponse; +import org.stellar.sdk.responses.operations.ClawbackClaimableBalanceOperationResponse; +import org.stellar.sdk.responses.operations.ClawbackOperationResponse; +import org.stellar.sdk.responses.operations.CreateAccountOperationResponse; +import org.stellar.sdk.responses.operations.CreateClaimableBalanceOperationResponse; +import org.stellar.sdk.responses.operations.EndSponsoringFutureReservesOperationResponse; +import org.stellar.sdk.responses.operations.InflationOperationResponse; +import org.stellar.sdk.responses.operations.LiquidityPoolDepositOperationResponse; +import org.stellar.sdk.responses.operations.LiquidityPoolWithdrawOperationResponse; +import org.stellar.sdk.responses.operations.ManageBuyOfferOperationResponse; +import org.stellar.sdk.responses.operations.ManageDataOperationResponse; +import org.stellar.sdk.responses.operations.OperationResponse; +import org.stellar.sdk.responses.operations.PathPaymentStrictReceiveOperationResponse; +import org.stellar.sdk.responses.operations.PathPaymentStrictSendOperationResponse; +import org.stellar.sdk.responses.operations.PaymentOperationResponse; +import org.stellar.sdk.responses.operations.SetOptionsOperationResponse; +import org.stellar.sdk.responses.operations.SetTrustLineFlagsOperationResponse; import java.math.BigInteger; import java.util.Arrays; diff --git a/src/test/java/org/stellar/sdk/xdr/AccountEntryDecodeTest.java b/src/test/java/org/stellar/sdk/xdr/AccountEntryDecodeTest.java new file mode 100644 index 000000000..ae754be34 --- /dev/null +++ b/src/test/java/org/stellar/sdk/xdr/AccountEntryDecodeTest.java @@ -0,0 +1,65 @@ +package org.stellar.sdk.xdr; + +import com.google.common.io.BaseEncoding; +import org.junit.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +public class AccountEntryDecodeTest { + + BaseEncoding base64Encoding = BaseEncoding.base64(); + + @Test + public void testDecodeSignerPayload() throws IOException { + AccountEntry.Builder bldr = new AccountEntry.Builder(); + Signer signer = new Signer(); + SignerKey signerKey = new SignerKey(); + signerKey.setDiscriminant(SignerKeyType.SIGNER_KEY_TYPE_ED25519_SIGNED_PAYLOAD); + signerKey.setEd25519SignedPayload(new SignerKey.SignerKeyEd25519SignedPayload()); + signerKey.getEd25519SignedPayload().setPayload(new byte[]{1,2,3,4}); + signerKey.getEd25519SignedPayload().setEd25519(new Uint256(new byte[32])); + signer.setKey(signerKey); + signer.setWeight(new Uint32(1)); + bldr.signers(new Signer[]{signer}); + bldr.accountID(new AccountID(new PublicKey.Builder().discriminant(PublicKeyType.PUBLIC_KEY_TYPE_ED25519).ed25519(new Uint256(new byte[32])).build())); + bldr.seqNum(new SequenceNumber(new Int64(1L))); + bldr.balance(new Int64(0L)); + bldr.numSubEntries(new Uint32(0)); + bldr.flags(new Uint32(0)); + bldr.homeDomain(new String32(new XdrString(""))); + bldr.thresholds(new Thresholds(new byte[3])); + bldr.ext(new AccountEntry.AccountEntryExt.Builder().discriminant(1) + .v1(new AccountEntryExtensionV1.Builder().liabilities(new Liabilities.Builder().buying(new Int64(0L)).selling(new Int64(0L)).build()) + .ext(new AccountEntryExtensionV1.AccountEntryExtensionV1Ext.Builder().discriminant(2) + .v2(new AccountEntryExtensionV2.Builder().numSponsored(new Uint32(0)).numSponsoring(new Uint32(0)).signerSponsoringIDs(new SponsorshipDescriptor[]{}) + .ext(new AccountEntryExtensionV2.AccountEntryExtensionV2Ext.Builder().discriminant(3) + .v3(new AccountEntryExtensionV3.Builder().seqLedger(new Uint32(1)).seqTime(new TimePoint(new Uint64(2L))) + .ext(new ExtensionPoint.Builder().discriminant(0).build()) + .build()) + .build()) + .build()) + .build()) + .build()) + .build()); + + AccountEntry xdr = bldr.build(); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + XdrDataOutputStream outputStream = new XdrDataOutputStream(baos); + AccountEntry.encode(outputStream, xdr); + String encodedXdr = base64Encoding.encode(baos.toByteArray()); + + byte[] decodedbBytes = base64Encoding.decode(encodedXdr); + + AccountEntry accountEntry = AccountEntry.decode(new XdrDataInputStream(new ByteArrayInputStream(decodedbBytes))); + assertArrayEquals(new byte[32], accountEntry.getSigners()[0].getKey().getEd25519SignedPayload().getEd25519().getUint256()); + assertArrayEquals(new byte[]{1,2,3,4}, accountEntry.getSigners()[0].getKey().getEd25519SignedPayload().getPayload()); + assertEquals(1, accountEntry.getExt().getV1().getExt().getV2().getExt().getV3().getSeqLedger().getUint32().longValue()); + assertEquals(2L, accountEntry.getExt().getV1().getExt().getV2().getExt().getV3().getSeqTime().getTimePoint().getUint64().longValue()); + } +} diff --git a/xdr/Stellar-ledger-entries.x b/xdr/Stellar-ledger-entries.x index 198e93dd8..3eb578f16 100644 --- a/xdr/Stellar-ledger-entries.x +++ b/xdr/Stellar-ledger-entries.x @@ -13,6 +13,7 @@ typedef string string32<32>; typedef string string64<64>; typedef int64 SequenceNumber; typedef uint64 TimePoint; +typedef uint64 Duration; typedef opaque DataValue<64>; typedef Hash PoolID; // SHA256(LiquidityPoolParameters) @@ -133,6 +134,19 @@ const MAX_SIGNERS = 20; typedef AccountID* SponsorshipDescriptor; +struct AccountEntryExtensionV3 +{ + // We can use this to add more fields, or because it is first, to + // change AccountEntryExtensionV3 into a union. + ExtensionPoint ext; + + // Ledger number at which `seqNum` took on its present value. + uint32 seqLedger; + + // Time at which `seqNum` took on its present value. + TimePoint seqTime; +}; + struct AccountEntryExtensionV2 { uint32 numSponsored; @@ -143,6 +157,8 @@ struct AccountEntryExtensionV2 { case 0: void; + case 3: + AccountEntryExtensionV3 v3; } ext; }; @@ -257,10 +273,10 @@ struct TrustLineEntryExtensionV2 struct TrustLineEntry { - AccountID accountID; // account this trustline belongs to - TrustLineAsset asset; // type of asset (with issuer) - int64 balance; // how much of this asset the user has. - // Asset defines the unit for this; + AccountID accountID; // account this trustline belongs to + TrustLineAsset asset; // type of asset (with issuer) + int64 balance; // how much of this asset the user has. + // Asset defines the unit for this; int64 limit; // balance cannot be above this uint32 flags; // see TrustLineFlags @@ -290,7 +306,8 @@ struct TrustLineEntry enum OfferEntryFlags { - // issuer has authorized account to perform transactions with its credit + // an offer with this flag will not act on and take a reverse offer of equal + // price PASSIVE_FLAG = 1 }; @@ -391,16 +408,13 @@ case CLAIMANT_TYPE_V0: enum ClaimableBalanceIDType { - CLAIMABLE_BALANCE_ID_TYPE_V0 = 0, - CLAIMABLE_BALANCE_ID_TYPE_FROM_POOL_REVOKE = 1 + CLAIMABLE_BALANCE_ID_TYPE_V0 = 0 }; union ClaimableBalanceID switch (ClaimableBalanceIDType type) { case CLAIMABLE_BALANCE_ID_TYPE_V0: Hash v0; -case CLAIMABLE_BALANCE_ID_TYPE_FROM_POOL_REVOKE: - Hash fromPoolRevoke; }; enum ClaimableBalanceFlags @@ -453,7 +467,7 @@ struct LiquidityPoolConstantProductParameters { Asset assetA; // assetA < assetB Asset assetB; - int32 fee; // Fee is in basis points, so the actual rate is (fee/100)% + int32 fee; // Fee is in basis points, so the actual rate is (fee/100)% }; struct LiquidityPoolEntry @@ -470,7 +484,8 @@ struct LiquidityPoolEntry int64 reserveA; // amount of A in the pool int64 reserveB; // amount of B in the pool int64 totalPoolShares; // total number of pool shares issued - int64 poolSharesTrustLineCount; // number of trust lines for the associated pool shares + int64 poolSharesTrustLineCount; // number of trust lines for the + // associated pool shares } constantProduct; } body; diff --git a/xdr/Stellar-ledger.x b/xdr/Stellar-ledger.x index 8a45985c8..84b84cbf7 100644 --- a/xdr/Stellar-ledger.x +++ b/xdr/Stellar-ledger.x @@ -33,7 +33,7 @@ struct StellarValue // this is a vector of encoded 'LedgerUpgrade' so that nodes can drop // unknown steps during consensus if needed. // see notes below on 'LedgerUpgrade' for more detail - // max size is dictated by number of upgrade types ( room for future) + // max size is dictated by number of upgrade types (+ room for future) UpgradeType upgrades<6>; // reserved for future use @@ -47,11 +47,10 @@ struct StellarValue ext; }; -const MASK_LEDGERHEADER_FLAGS = 0x7; +const MASK_LEDGER_HEADER_FLAGS = 0x7; enum LedgerHeaderFlags -{ // masks for each flag - +{ DISABLE_LIQUIDITY_POOL_TRADING_FLAG = 0x1, DISABLE_LIQUIDITY_POOL_DEPOSIT_FLAG = 0x2, DISABLE_LIQUIDITY_POOL_WITHDRAWAL_FLAG = 0x4 @@ -59,7 +58,7 @@ enum LedgerHeaderFlags struct LedgerHeaderExtensionV1 { - uint32 flags; // UpgradeFlags + uint32 flags; // LedgerHeaderFlags union switch (int v) { @@ -69,7 +68,6 @@ struct LedgerHeaderExtensionV1 ext; }; - /* The LedgerHeader is the highest level structure representing the * state of a ledger, cryptographically linked to previous ledgers. */ diff --git a/xdr/Stellar-overlay.x b/xdr/Stellar-overlay.x index a4ab6b077..9e3a083d3 100644 --- a/xdr/Stellar-overlay.x +++ b/xdr/Stellar-overlay.x @@ -22,6 +22,11 @@ struct Error string msg<100>; }; +struct SendMore +{ + uint32 numMessages; +}; + struct AuthCert { Curve25519Public pubkey; @@ -93,7 +98,9 @@ enum MessageType HELLO = 13, SURVEY_REQUEST = 14, - SURVEY_RESPONSE = 15 + SURVEY_RESPONSE = 15, + + SEND_MORE = 16 }; struct DontHave @@ -214,6 +221,8 @@ case SCP_MESSAGE: SCPEnvelope envelope; case GET_SCP_STATE: uint32 getSCPLedgerSeq; // ledger seq requested ; if 0, requests the latest +case SEND_MORE: + SendMore sendMoreMessage; }; union AuthenticatedMessage switch (uint32 v) diff --git a/xdr/Stellar-transaction.x b/xdr/Stellar-transaction.x index 19d0240d0..f2f593c21 100644 --- a/xdr/Stellar-transaction.x +++ b/xdr/Stellar-transaction.x @@ -445,10 +445,10 @@ const LIQUIDITY_POOL_FEE_V18 = 30; struct LiquidityPoolDepositOp { PoolID liquidityPoolID; - int64 maxAmountA; // maximum amount of first asset to deposit - int64 maxAmountB; // maximum amount of second asset to deposit - Price minPrice; // minimum depositA/depositB - Price maxPrice; // maximum depositA/depositB + int64 maxAmountA; // maximum amount of first asset to deposit + int64 maxAmountB; // maximum amount of second asset to deposit + Price minPrice; // minimum depositA/depositB + Price maxPrice; // maximum depositA/depositB }; /* Withdraw assets from a liquidity pool @@ -460,9 +460,9 @@ struct LiquidityPoolDepositOp struct LiquidityPoolWithdrawOp { PoolID liquidityPoolID; - int64 amount; // amount of pool shares to withdraw - int64 minAmountA; // minimum amount of first asset to withdraw - int64 minAmountB; // minimum amount of second asset to withdraw + int64 amount; // amount of pool shares to withdraw + int64 minAmountA; // minimum amount of first asset to withdraw + int64 minAmountB; // minimum amount of second asset to withdraw }; /* An operation is the lowest unit of work that a transaction does */ @@ -527,7 +527,7 @@ struct Operation body; }; -union OperationID switch (EnvelopeType type) +union HashIDPreimage switch (EnvelopeType type) { case ENVELOPE_TYPE_OP_ID: struct @@ -535,7 +535,7 @@ case ENVELOPE_TYPE_OP_ID: AccountID sourceAccount; SequenceNumber seqNum; uint32 opNum; - } id; + } operationID; case ENVELOPE_TYPE_POOL_REVOKE_OP_ID: struct { @@ -544,7 +544,7 @@ case ENVELOPE_TYPE_POOL_REVOKE_OP_ID: uint32 opNum; PoolID liquidityPoolID; Asset asset; - } revokeId; + } revokeID; }; enum MemoType @@ -576,6 +576,62 @@ struct TimeBounds TimePoint maxTime; // 0 here means no maxTime }; +struct LedgerBounds +{ + uint32 minLedger; + uint32 maxLedger; // 0 here means no maxLedger +}; + +struct PreconditionsV2 +{ + TimeBounds* timeBounds; + + // Transaction only valid for ledger numbers n such that + // minLedger <= n < maxLedger (if maxLedger == 0, then + // only minLedger is checked) + LedgerBounds* ledgerBounds; + + // If NULL, only valid when sourceAccount's sequence number + // is seqNum - 1. Otherwise, valid when sourceAccount's + // sequence number n satisfies minSeqNum <= n < tx.seqNum. + // Note that after execution the account's sequence number + // is always raised to tx.seqNum, and a transaction is not + // valid if tx.seqNum is too high to ensure replay protection. + SequenceNumber* minSeqNum; + + // For the transaction to be valid, the current ledger time must + // be at least minSeqAge greater than sourceAccount's seqTime. + Duration minSeqAge; + + // For the transaction to be valid, the current ledger number + // must be at least minSeqLedgerGap greater than sourceAccount's + // seqLedger. + uint32 minSeqLedgerGap; + + // For the transaction to be valid, there must be a signature + // corresponding to every Signer in this array, even if the + // signature is not otherwise required by the sourceAccount or + // operations. + SignerKey extraSigners<2>; +}; + +enum PreconditionType +{ + PRECOND_NONE = 0, + PRECOND_TIME = 1, + PRECOND_V2 = 2 +}; + +union Preconditions switch (PreconditionType type) +{ +case PRECOND_NONE: + void; +case PRECOND_TIME: + TimeBounds timeBounds; +case PRECOND_V2: + PreconditionsV2 v2; +}; + // maximum number of operations per transaction const MAX_OPS_PER_TX = 100; @@ -627,8 +683,8 @@ struct Transaction // sequence number to consume in the account SequenceNumber seqNum; - // validity range (inclusive) for the last ledger close time - TimeBounds* timeBounds; + // validity conditions + Preconditions cond; Memo memo; @@ -1054,10 +1110,12 @@ enum ChangeTrustResultCode // cannot create with a limit of 0 CHANGE_TRUST_LOW_RESERVE = -4, // not enough funds to create a new trust line, - CHANGE_TRUST_SELF_NOT_ALLOWED = -5, // trusting self is not allowed + CHANGE_TRUST_SELF_NOT_ALLOWED = -5, // trusting self is not allowed CHANGE_TRUST_TRUST_LINE_MISSING = -6, // Asset trustline is missing for pool - CHANGE_TRUST_CANNOT_DELETE = -7, // Asset trustline is still referenced in a pool - CHANGE_TRUST_NOT_AUTH_MAINTAIN_LIABILITIES = -8 // Asset trustline is deauthorized + CHANGE_TRUST_CANNOT_DELETE = + -7, // Asset trustline is still referenced in a pool + CHANGE_TRUST_NOT_AUTH_MAINTAIN_LIABILITIES = + -8 // Asset trustline is deauthorized }; union ChangeTrustResult switch (ChangeTrustResultCode code) @@ -1079,10 +1137,10 @@ enum AllowTrustResultCode ALLOW_TRUST_NO_TRUST_LINE = -2, // trustor does not have a trustline // source account does not require trust ALLOW_TRUST_TRUST_NOT_REQUIRED = -3, - ALLOW_TRUST_CANT_REVOKE = -4, // source account can't revoke trust, + ALLOW_TRUST_CANT_REVOKE = -4, // source account can't revoke trust, ALLOW_TRUST_SELF_NOT_ALLOWED = -5, // trusting self is not allowed - ALLOW_TRUST_LOW_RESERVE = -6 // claimable balances can't be created - // on revoke due to low reserves + ALLOW_TRUST_LOW_RESERVE = -6 // claimable balances can't be created + // on revoke due to low reserves }; union AllowTrustResult switch (AllowTrustResultCode code) @@ -1379,8 +1437,7 @@ enum LiquidityPoolDepositResultCode LIQUIDITY_POOL_DEPOSIT_POOL_FULL = -7 // pool reserves are full }; -union LiquidityPoolDepositResult switch ( - LiquidityPoolDepositResultCode code) +union LiquidityPoolDepositResult switch (LiquidityPoolDepositResultCode code) { case LIQUIDITY_POOL_DEPOSIT_SUCCESS: void; @@ -1396,18 +1453,17 @@ enum LiquidityPoolWithdrawResultCode LIQUIDITY_POOL_WITHDRAW_SUCCESS = 0, // codes considered as "failure" for the operation - LIQUIDITY_POOL_WITHDRAW_MALFORMED = -1, // bad input - LIQUIDITY_POOL_WITHDRAW_NO_TRUST = -2, // no trust line for one of the - // assets - LIQUIDITY_POOL_WITHDRAW_UNDERFUNDED = -3, // not enough balance of the - // pool share - LIQUIDITY_POOL_WITHDRAW_LINE_FULL = -4, // would go above limit for one - // of the assets - LIQUIDITY_POOL_WITHDRAW_UNDER_MINIMUM = -5 // didn't withdraw enough + LIQUIDITY_POOL_WITHDRAW_MALFORMED = -1, // bad input + LIQUIDITY_POOL_WITHDRAW_NO_TRUST = -2, // no trust line for one of the + // assets + LIQUIDITY_POOL_WITHDRAW_UNDERFUNDED = -3, // not enough balance of the + // pool share + LIQUIDITY_POOL_WITHDRAW_LINE_FULL = -4, // would go above limit for one + // of the assets + LIQUIDITY_POOL_WITHDRAW_UNDER_MINIMUM = -5 // didn't withdraw enough }; -union LiquidityPoolWithdrawResult switch ( - LiquidityPoolWithdrawResultCode code) +union LiquidityPoolWithdrawResult switch (LiquidityPoolWithdrawResultCode code) { case LIQUIDITY_POOL_WITHDRAW_SUCCESS: void; @@ -1415,7 +1471,6 @@ default: void; }; - /* High level Operation Result */ enum OperationResultCode { @@ -1509,7 +1564,10 @@ enum TransactionResultCode txNOT_SUPPORTED = -12, // transaction type not supported txFEE_BUMP_INNER_FAILED = -13, // fee bump inner transaction failed - txBAD_SPONSORSHIP = -14 // sponsorship not confirmed + txBAD_SPONSORSHIP = -14, // sponsorship not confirmed + txBAD_MIN_SEQ_AGE_OR_GAP = + -15, // minSeqAge or minSeqLedgerGap conditions not met + txMALFORMED = -16 // precondition is invalid }; // InnerTransactionResult must be binary compatible with TransactionResult @@ -1538,6 +1596,8 @@ struct InnerTransactionResult case txNOT_SUPPORTED: // txFEE_BUMP_INNER_FAILED is not included case txBAD_SPONSORSHIP: + case txBAD_MIN_SEQ_AGE_OR_GAP: + case txMALFORMED: void; } result; diff --git a/xdr/Stellar-types.x b/xdr/Stellar-types.x index 8f7d5c206..c3a1ebe2c 100644 --- a/xdr/Stellar-types.x +++ b/xdr/Stellar-types.x @@ -14,11 +14,21 @@ typedef int int32; typedef unsigned hyper uint64; typedef hyper int64; +// An ExtensionPoint is always marshaled as a 32-bit 0 value. At a +// later point, it can be replaced by a different union so as to +// extend a structure. +union ExtensionPoint switch (int v) +{ +case 0: + void; +}; + enum CryptoKeyType { KEY_TYPE_ED25519 = 0, KEY_TYPE_PRE_AUTH_TX = 1, KEY_TYPE_HASH_X = 2, + KEY_TYPE_ED25519_SIGNED_PAYLOAD = 3, // MUXED enum values for supported type are derived from the enum values // above by ORing them with 0x100 KEY_TYPE_MUXED_ED25519 = 0x100 @@ -33,7 +43,8 @@ enum SignerKeyType { SIGNER_KEY_TYPE_ED25519 = KEY_TYPE_ED25519, SIGNER_KEY_TYPE_PRE_AUTH_TX = KEY_TYPE_PRE_AUTH_TX, - SIGNER_KEY_TYPE_HASH_X = KEY_TYPE_HASH_X + SIGNER_KEY_TYPE_HASH_X = KEY_TYPE_HASH_X, + SIGNER_KEY_TYPE_ED25519_SIGNED_PAYLOAD = KEY_TYPE_ED25519_SIGNED_PAYLOAD }; union PublicKey switch (PublicKeyType type) @@ -52,6 +63,14 @@ case SIGNER_KEY_TYPE_PRE_AUTH_TX: case SIGNER_KEY_TYPE_HASH_X: /* Hash of random 256 bit preimage X */ uint256 hashX; +case SIGNER_KEY_TYPE_ED25519_SIGNED_PAYLOAD: + struct + { + /* Public key that must sign the payload. */ + uint256 ed25519; + /* Payload to be raw signed by ed25519. */ + opaque payload<64>; + } ed25519SignedPayload; }; // variable size as the size depends on the signature scheme used