diff --git a/src/main/java/org/altcoinj/core/ScryptHash.java b/src/main/java/org/altcoinj/core/ScryptHash.java index e715624e..0ef232c3 100644 --- a/src/main/java/org/altcoinj/core/ScryptHash.java +++ b/src/main/java/org/altcoinj/core/ScryptHash.java @@ -15,6 +15,7 @@ */ package org.altcoinj.core; +import org.bitcoinj.core.Sha256Hash; import org.bitcoinj.core.Sha256Hash; /** diff --git a/src/main/java/org/altcoinj/params/AbstractDogecoinParams.java b/src/main/java/org/altcoinj/params/AbstractDogecoinParams.java index 5570fed0..21a33aa2 100644 --- a/src/main/java/org/altcoinj/params/AbstractDogecoinParams.java +++ b/src/main/java/org/altcoinj/params/AbstractDogecoinParams.java @@ -26,7 +26,6 @@ import org.bitcoinj.core.Coin; import static org.bitcoinj.core.Coin.COIN; import org.bitcoinj.core.NetworkParameters; import org.bitcoinj.core.Sha256Hash; -import org.bitcoinj.core.Utils; import org.bitcoinj.core.VerificationException; import org.bitcoinj.script.Script; import org.bitcoinj.script.ScriptOpCodes; @@ -38,11 +37,16 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static com.google.common.base.Preconditions.checkState; +import org.bitcoinj.core.StoredBlock; +import org.bitcoinj.core.Transaction; +import org.bitcoinj.core.TransactionInput; +import org.bitcoinj.core.TransactionOutput; +import org.bitcoinj.core.Utils; /** * Parameters for the main Dogecoin production network on which people trade goods and services. */ -public class AbstractDogecoinParams extends NetworkParameters { +public abstract class AbstractDogecoinParams extends NetworkParameters implements AuxPoWNetworkParameters { /** Standard format for the DOGE denomination. */ public static final MonetaryFormat DOGE; /** Standard format for the mDOGE denomination. */ @@ -285,4 +289,10 @@ public class AbstractDogecoinParams extends NetworkParameters { public int getDigishieldBlockHeight() { return DIGISHIELD_BLOCK_HEIGHT; } + + @Override + public boolean isAuxPoWBlockVersion(long version) { + return version >= BLOCK_VERSION_AUXPOW + && (version & BLOCK_VERSION_FLAG_AUXPOW) > 0; + } } diff --git a/src/main/java/org/altcoinj/params/DogecoinMainNetParams.java b/src/main/java/org/altcoinj/params/DogecoinMainNetParams.java index d2ae97bb..e7dc446e 100644 --- a/src/main/java/org/altcoinj/params/DogecoinMainNetParams.java +++ b/src/main/java/org/altcoinj/params/DogecoinMainNetParams.java @@ -94,10 +94,4 @@ public class DogecoinMainNetParams extends AbstractDogecoinParams { // TODO: CHANGE THIS return ID_DOGE_MAINNET; } - - @Override - public boolean isAuxPoWBlockVersion(long version) { - return version >= BLOCK_VERSION_AUXPOW - && (version & BLOCK_VERSION_FLAG_AUXPOW) > 0; - } } diff --git a/src/main/java/org/altcoinj/core/AltcoinBlock.java b/src/main/java/org/bitcoinj/core/AltcoinBlock.java similarity index 91% rename from src/main/java/org/altcoinj/core/AltcoinBlock.java rename to src/main/java/org/bitcoinj/core/AltcoinBlock.java index 9079c2fd..8d2ffcf6 100644 --- a/src/main/java/org/altcoinj/core/AltcoinBlock.java +++ b/src/main/java/org/bitcoinj/core/AltcoinBlock.java @@ -15,30 +15,22 @@ * limitations under the License. */ -package org.altcoinj.core; +package org.bitcoinj.core; -import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableList; import javax.annotation.Nullable; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.ObjectInputStream; import java.io.OutputStream; import java.math.BigInteger; import java.security.GeneralSecurityException; import java.util.List; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import org.altcoinj.core.ScryptHash; import static org.altcoinj.core.Utils.scryptDigest; -import static org.bitcoinj.core.Coin.FIFTY_COINS; -import static org.bitcoinj.core.Utils.doubleDigest; -import static org.bitcoinj.core.Utils.doubleDigestTwoBuffers; +import static org.bitcoinj.core.Utils.reverseBytes; /** *

A block is a group of transactions, and is one of the fundamental data structures of the Bitcoin system. @@ -69,7 +61,7 @@ public class AltcoinBlock extends org.bitcoinj.core.Block { /** Constructs a block object from the Bitcoin wire format. */ public AltcoinBlock(NetworkParameters params, byte[] payloadBytes) throws ProtocolException { - super(params, payloadBytes, 0, false, false, payloadBytes.length); + super(params, payloadBytes); } /** @@ -85,7 +77,7 @@ public class AltcoinBlock extends org.bitcoinj.core.Block { */ public AltcoinBlock(NetworkParameters params, byte[] payloadBytes, boolean parseLazy, boolean parseRetain, int length) throws ProtocolException { - super(params, payloadBytes, 0, parseLazy, parseRetain, length); + super(params, payloadBytes, parseLazy, parseRetain, length); } /** @@ -107,7 +99,7 @@ public class AltcoinBlock extends org.bitcoinj.core.Block { public AltcoinBlock(NetworkParameters params, byte[] payloadBytes, int offset, @Nullable Message parent, boolean parseLazy, boolean parseRetain, int length) throws ProtocolException { // TODO: Keep the parent - super(params, payloadBytes, offset, parseLazy, parseRetain, length); + super(params, payloadBytes, offset, parent, parseLazy, parseRetain, length); } @@ -131,7 +123,7 @@ public class AltcoinBlock extends org.bitcoinj.core.Block { try { ByteArrayOutputStream bos = new UnsafeByteArrayOutputStream(HEADER_SIZE); writeHeader(bos); - return new ScryptHash(Utils.reverseBytes(scryptDigest(bos.toByteArray()))); + return new ScryptHash(reverseBytes(scryptDigest(bos.toByteArray()))); } catch (IOException e) { throw new RuntimeException(e); // Cannot happen. } catch (GeneralSecurityException e) { @@ -223,16 +215,8 @@ public class AltcoinBlock extends org.bitcoinj.core.Block { /** Returns a copy of the block, but without any transactions. */ @Override public Block cloneAsHeader() { - maybeParseHeader(); AltcoinBlock block = new AltcoinBlock(params); - block.nonce = nonce; - block.prevBlockHash = prevBlockHash; - block.merkleRoot = getMerkleRoot(); - block.version = version; - block.time = time; - block.difficultyTarget = difficultyTarget; - block.transactions = null; - block.hash = getHash(); + super.copyBitcoinHeaderTo(block); block.auxpow = auxpow; return block; } diff --git a/src/main/java/org/altcoinj/core/AuxPoW.java b/src/main/java/org/bitcoinj/core/AuxPoW.java similarity index 95% rename from src/main/java/org/altcoinj/core/AuxPoW.java rename to src/main/java/org/bitcoinj/core/AuxPoW.java index b8a6b81b..90327df1 100644 --- a/src/main/java/org/altcoinj/core/AuxPoW.java +++ b/src/main/java/org/bitcoinj/core/AuxPoW.java @@ -16,17 +16,8 @@ * limitations under the License. */ -package org.altcoinj.core; +package org.bitcoinj.core; -import org.bitcoinj.crypto.TransactionSignature; -import org.bitcoinj.script.Script; -import org.bitcoinj.script.ScriptBuilder; -import org.bitcoinj.script.ScriptOpCodes; -import org.bitcoinj.utils.ExchangeRate; -import org.bitcoinj.wallet.WalletTransaction.Pool; -import com.google.common.collect.ImmutableMap; -import com.google.common.primitives.Ints; -import com.google.common.primitives.Longs; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -34,8 +25,6 @@ import javax.annotation.Nullable; import java.io.*; import java.util.*; -import static org.bitcoinj.core.Utils.*; -import static com.google.common.base.Preconditions.checkState; /** *

An AuxPoW header wraps a block header from another coin, enabling the foreign diff --git a/src/main/java/org/bitcoinj/core/AuxPoWNetworkParameters.java b/src/main/java/org/bitcoinj/core/AuxPoWNetworkParameters.java new file mode 100644 index 00000000..00f36788 --- /dev/null +++ b/src/main/java/org/bitcoinj/core/AuxPoWNetworkParameters.java @@ -0,0 +1,16 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.bitcoinj.core; + +/** + * + * @author jrn + */ +public interface AuxPoWNetworkParameters { + + public boolean isAuxPoWBlockVersion(long version); + +} diff --git a/src/main/java/org/altcoinj/core/MerkleBranch.java b/src/main/java/org/bitcoinj/core/MerkleBranch.java similarity index 99% rename from src/main/java/org/altcoinj/core/MerkleBranch.java rename to src/main/java/org/bitcoinj/core/MerkleBranch.java index c1cddadf..3acd33a6 100644 --- a/src/main/java/org/altcoinj/core/MerkleBranch.java +++ b/src/main/java/org/bitcoinj/core/MerkleBranch.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.altcoinj.core; +package org.bitcoinj.core; import static org.bitcoinj.core.Utils.doubleDigestTwoBuffers; import static org.bitcoinj.core.Utils.reverseBytes; diff --git a/src/test/java/org/altcoinj/core/AddressTest.java b/src/test/java/org/altcoinj/core/AddressTest.java deleted file mode 100644 index dbca86b2..00000000 --- a/src/test/java/org/altcoinj/core/AddressTest.java +++ /dev/null @@ -1,228 +0,0 @@ -/** - * Copyright 2011 Google Inc. - * Copyright 2014 Andreas Schildbach - * - * 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 - * - * http://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. - */ - -package com.dogecoin.dogecoinj.core; - -import com.dogecoin.dogecoinj.params.MainNetParams; -import com.dogecoin.dogecoinj.params.Networks; -import com.dogecoin.dogecoinj.params.TestNet3Params; -import com.dogecoin.dogecoinj.script.Script; -import com.dogecoin.dogecoinj.script.ScriptBuilder; -import org.junit.Test; - -import java.util.Arrays; -import java.util.List; - -import static com.dogecoin.dogecoinj.core.Utils.HEX; -import static org.junit.Assert.*; - -public class AddressTest { - static final NetworkParameters testParams = TestNet3Params.get(); - static final NetworkParameters mainParams = MainNetParams.get(); - - @Test - public void stringification() throws Exception { - // Test a testnet address. - Address a = new Address(testParams, HEX.decode("8e34b02b3c2552791c2151394a1958fe8d40348d")); - assertEquals("nhA5LMB3mtmVf1xNsHnoGakmFyq1fuzyb7", a.toString()); - assertFalse(a.isP2SHAddress()); - - Address b = new Address(mainParams, HEX.decode("6bf21708a0ee6cabde2f3bec6f7880c29b1b1d7e")); - assertEquals("DEyrrVQspH26SS2wjfZdFT579NLBto1x64", b.toString()); - assertFalse(b.isP2SHAddress()); - } - - @Test - public void decoding() throws Exception { - Address a = new Address(testParams, "nhA5LMB3mtmVf1xNsHnoGakmFyq1fuzyb7"); - assertEquals("8e34b02b3c2552791c2151394a1958fe8d40348d", Utils.HEX.encode(a.getHash160())); - - Address b = new Address(mainParams, "DEyrrVQspH26SS2wjfZdFT579NLBto1x64"); - assertEquals("6bf21708a0ee6cabde2f3bec6f7880c29b1b1d7e", Utils.HEX.encode(b.getHash160())); - } - - @Test - public void errorPaths() { - // Check what happens if we try and decode garbage. - try { - new Address(testParams, "this is not a valid address!"); - fail(); - } catch (WrongNetworkException e) { - fail(); - } catch (AddressFormatException e) { - // Success. - } - - // Check the empty case. - try { - new Address(testParams, ""); - fail(); - } catch (WrongNetworkException e) { - fail(); - } catch (AddressFormatException e) { - // Success. - } - - // Check the case of a mismatched network. - try { - new Address(testParams, "DEyrrVQspH26SS2wjfZdFT579NLBto1x64"); - fail(); - } catch (WrongNetworkException e) { - // Success. - assertEquals(e.verCode, MainNetParams.get().getAddressHeader()); - assertTrue(Arrays.equals(e.acceptableVersions, TestNet3Params.get().getAcceptableAddressCodes())); - } catch (AddressFormatException e) { - fail(); - } - } - - @Test - public void getNetwork() throws Exception { - NetworkParameters params = Address.getParametersFromAddress("DEyrrVQspH26SS2wjfZdFT579NLBto1x64"); - assertEquals(MainNetParams.get().getId(), params.getId()); - params = Address.getParametersFromAddress("nhA5LMB3mtmVf1xNsHnoGakmFyq1fuzyb7"); - assertEquals(TestNet3Params.get().getId(), params.getId()); - } - - @Test - public void getAltNetwork() throws Exception { - // An alternative network - class AltNetwork extends MainNetParams { - AltNetwork() { - super(); - id = "alt.network"; - addressHeader = 48; - p2shHeader = 5; - acceptableAddressCodes = new int[] { addressHeader, p2shHeader }; - } - } - AltNetwork altNetwork = new AltNetwork(); - // Add new network params - Networks.register(altNetwork); - // Check if can parse address - NetworkParameters params = Address.getParametersFromAddress("LLxSnHLN2CYyzB5eWTR9K9rS9uWtbTQFb6"); - assertEquals(altNetwork.getId(), params.getId()); - // Check if main network works as before - params = Address.getParametersFromAddress("DEyrrVQspH26SS2wjfZdFT579NLBto1x64"); - assertEquals(MainNetParams.get().getId(), params.getId()); - // Unregister network - Networks.unregister(altNetwork); - try { - Address.getParametersFromAddress("LLxSnHLN2CYyzB5eWTR9K9rS9uWtbTQFb6"); - fail(); - } catch (AddressFormatException e) { } - } - - @Test - public void p2shAddress() throws Exception { - // Test that we can construct P2SH addresses - Address mainNetP2SHAddress = new Address(MainNetParams.get(), "9wWHL91mYrdiBEw9uHuBtS42in2XqWKrRY"); - assertEquals(mainNetP2SHAddress.version, MainNetParams.get().p2shHeader); - assertTrue(mainNetP2SHAddress.isP2SHAddress()); - Address testNetP2SHAddress = new Address(TestNet3Params.get(), "2N8jyJyivK4trjisMYPHyMsdnTyWVDTWxaL"); - assertEquals(testNetP2SHAddress.version, TestNet3Params.get().p2shHeader); - assertTrue(testNetP2SHAddress.isP2SHAddress()); - - // Test that we can determine what network a P2SH address belongs to - NetworkParameters mainNetParams = Address.getParametersFromAddress("9wWHL91mYrdiBEw9uHuBtS42in2XqWKrRY"); - assertEquals(MainNetParams.get().getId(), mainNetParams.getId()); - NetworkParameters testNetParams = Address.getParametersFromAddress("2N8jyJyivK4trjisMYPHyMsdnTyWVDTWxaL"); - assertEquals(TestNet3Params.get().getId(), testNetParams.getId()); - - // Test that we can convert them from hashes - byte[] hex = HEX.decode("379ad9b7ba73bdc1e29e286e014d4e2e1f6884e3"); - Address a = Address.fromP2SHHash(mainParams, hex); - assertEquals("9wWHL91mYrdiBEw9uHuBtS42in2XqWKrRY", a.toString()); - Address b = Address.fromP2SHHash(testParams, HEX.decode("a9f9b28507bbe69c13eaed4f880bb22d17450b56")); - assertEquals("2N8jyJyivK4trjisMYPHyMsdnTyWVDTWxaL", b.toString()); - Address c = Address.fromP2SHScript(mainParams, ScriptBuilder.createP2SHOutputScript(hex)); - assertEquals("9wWHL91mYrdiBEw9uHuBtS42in2XqWKrRY", c.toString()); - } - - @Test - public void p2shAddressCreationFromKeys() throws Exception { - // import some keys from this example: https://gist.github.com/gavinandresen/3966071 - ECKey key1 = new DumpedPrivateKey(mainParams, "QVUd4dwqxqePZgBaC6ny5rHvNHu6CoT8t1sTTPnF5RfFAjtKjTQH").getKey(); - key1 = ECKey.fromPrivate(key1.getPrivKeyBytes()); - ECKey key2 = new DumpedPrivateKey(mainParams, "QTZSzo8RphsaJFiEJAEvjvRqqP9MVyWpT1ns9hVRij4nXTE3XTzP").getKey(); - key2 = ECKey.fromPrivate(key2.getPrivKeyBytes()); - ECKey key3 = new DumpedPrivateKey(mainParams, "QS2YZKyPB6nDH7WnMuT4YKwLQwZQ3vN2FCPTwTCeyUNSKeRyPgRk").getKey(); - key3 = ECKey.fromPrivate(key3.getPrivKeyBytes()); - - List keys = Arrays.asList(key1, key2, key3); - Script p2shScript = ScriptBuilder.createP2SHOutputScript(2, keys); - Address address = Address.fromP2SHScript(mainParams, p2shScript); - assertEquals("ACdJj7YT7dJkV6bv6cRenUMCTDQxSdZSo5", address.toString()); - } - - @Test - public void cloning() throws Exception { - Address a = new Address(testParams, HEX.decode("fda79a24e50ff70ff42f7d89585da5bd19d9e5cc")); - Address b = a.clone(); - - assertEquals(a, b); - assertNotSame(a, b); - } - - @Test - public void comparisonCloneEqualTo() throws Exception { - Address a = new Address(mainParams, "1Dorian4RoXcnBv9hnQ4Y2C1an6NJ4UrjX"); - Address b = a.clone(); - - int result = a.compareTo(b); - assertEquals(0, result); - } - - @Test - public void comparisonEqualTo() throws Exception { - Address a = new Address(mainParams, "1Dorian4RoXcnBv9hnQ4Y2C1an6NJ4UrjX"); - Address b = a.clone(); - - int result = a.compareTo(b); - assertEquals(0, result); - } - - @Test - public void comparisonLessThan() throws Exception { - Address a = new Address(mainParams, "1Dorian4RoXcnBv9hnQ4Y2C1an6NJ4UrjX"); - Address b = new Address(mainParams, "1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P"); - - int result = a.compareTo(b); - assertTrue(result < 0); - } - - @Test - public void comparisonGreaterThan() throws Exception { - Address a = new Address(mainParams, "1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P"); - Address b = new Address(mainParams, "1Dorian4RoXcnBv9hnQ4Y2C1an6NJ4UrjX"); - - int result = a.compareTo(b); - assertTrue(result > 0); - } - - @Test - public void comparisonBytesVsString() throws Exception { - // TODO: To properly test this we need a much larger data set - Address a = new Address(mainParams, "1Dorian4RoXcnBv9hnQ4Y2C1an6NJ4UrjX"); - Address b = new Address(mainParams, "1EXoDusjGwvnjZUyKkxZ4UHEf77z6A5S4P"); - - int resultBytes = a.compareTo(b); - int resultsString = a.toString().compareTo(b.toString()); - assertTrue( resultBytes < 0 ); - assertTrue( resultsString < 0 ); - } -} diff --git a/src/test/java/org/altcoinj/core/DumpedPrivateKeyTest.java b/src/test/java/org/altcoinj/core/DumpedPrivateKeyTest.java deleted file mode 100644 index d6eb25f0..00000000 --- a/src/test/java/org/altcoinj/core/DumpedPrivateKeyTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2014 Andreas Schildbach - * - * 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 - * - * http://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. - */ - -package com.dogecoin.dogecoinj.core; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotSame; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; - -import org.junit.Test; - -import com.dogecoin.dogecoinj.params.MainNetParams; - -public class DumpedPrivateKeyTest { - @Test - public void testJavaSerialization() throws Exception { - - DumpedPrivateKey key = new DumpedPrivateKey(MainNetParams.get(), new ECKey().getPrivKeyBytes(), true); - ByteArrayOutputStream os = new ByteArrayOutputStream(); - new ObjectOutputStream(os).writeObject(key); - DumpedPrivateKey keyCopy = (DumpedPrivateKey) new ObjectInputStream(new ByteArrayInputStream(os.toByteArray())) - .readObject(); - assertEquals(key, keyCopy); - } - - @Test - public void cloning() throws Exception { - DumpedPrivateKey a = new DumpedPrivateKey(MainNetParams.get(), new ECKey().getPrivKeyBytes(), true); - // TODO: Consider overriding clone() in DumpedPrivateKey to narrow the type - DumpedPrivateKey b = (DumpedPrivateKey) a.clone(); - - assertEquals(a, b); - assertNotSame(a, b); - } - -} diff --git a/src/test/java/org/altcoinj/core/PeerGroupTest.java b/src/test/java/org/altcoinj/core/PeerGroupTest.java deleted file mode 100644 index 12c3ea61..00000000 --- a/src/test/java/org/altcoinj/core/PeerGroupTest.java +++ /dev/null @@ -1,853 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * Copyright 2014 Andreas Schildbach - * - * 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 - * - * http://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. - */ - -package com.dogecoin.dogecoinj.core; - -import com.dogecoin.dogecoinj.net.discovery.PeerDiscovery; -import com.dogecoin.dogecoinj.net.discovery.PeerDiscoveryException; -import com.dogecoin.dogecoinj.params.UnitTestParams; -import com.dogecoin.dogecoinj.testing.FakeTxBuilder; -import com.dogecoin.dogecoinj.testing.InboundMessageQueuer; -import com.dogecoin.dogecoinj.testing.TestWithPeerGroup; -import com.dogecoin.dogecoinj.utils.Threading; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; -import com.google.common.net.InetAddresses; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.common.util.concurrent.SettableFuture; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import java.io.IOException; -import java.net.BindException; -import java.net.InetSocketAddress; -import java.net.ServerSocket; -import java.util.*; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -import static com.dogecoin.dogecoinj.core.Coin.COIN; -import static com.dogecoin.dogecoinj.core.Coin.valueOf; -import static org.junit.Assert.*; - - -// TX announcement and broadcast is tested in TransactionBroadcastTest. - -@RunWith(value = Parameterized.class) -public class PeerGroupTest extends TestWithPeerGroup { - static final NetworkParameters params = UnitTestParams.get(); - private BlockingQueue connectedPeers; - private BlockingQueue disconnectedPeers; - private PeerEventListener listener; - private Map peerToMessageCount; - - @Parameterized.Parameters - public static Collection parameters() { - return Arrays.asList(new ClientType[] {ClientType.NIO_CLIENT_MANAGER}, - new ClientType[] {ClientType.BLOCKING_CLIENT_MANAGER}); - } - - public PeerGroupTest(ClientType clientType) { - super(clientType); - } - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - peerToMessageCount = new HashMap(); - connectedPeers = new LinkedBlockingQueue(); - disconnectedPeers = new LinkedBlockingQueue(); - listener = new AbstractPeerEventListener() { - @Override - public void onPeerConnected(Peer peer, int peerCount) { - connectedPeers.add(peer); - } - - @Override - public void onPeerDisconnected(Peer peer, int peerCount) { - disconnectedPeers.add(peer); - } - - @Override - public Message onPreMessageReceived(Peer peer, Message m) { - AtomicInteger messageCount = peerToMessageCount.get(peer); - if (messageCount == null) { - messageCount = new AtomicInteger(0); - peerToMessageCount.put(peer, messageCount); - } - messageCount.incrementAndGet(); - // Just pass the message right through for further processing. - return m; - } - }; - } - - @Override - @After - public void tearDown() { - super.tearDown(); - } - - @Test - public void listener() throws Exception { - peerGroup.start(); - peerGroup.addEventListener(listener); - - // Create a couple of peers. - InboundMessageQueuer p1 = connectPeer(1); - InboundMessageQueuer p2 = connectPeer(2); - connectedPeers.take(); - connectedPeers.take(); - - pingAndWait(p1); - pingAndWait(p2); - Threading.waitForUserCode(); - assertEquals(0, disconnectedPeers.size()); - - p1.close(); - disconnectedPeers.take(); - assertEquals(0, disconnectedPeers.size()); - p2.close(); - disconnectedPeers.take(); - assertEquals(0, disconnectedPeers.size()); - - assertTrue(peerGroup.removeEventListener(listener)); - assertFalse(peerGroup.removeEventListener(listener)); - } - - @Test - public void peerDiscoveryPolling() throws InterruptedException { - // Check that if peer discovery fails, we keep trying until we have some nodes to talk with. - final CountDownLatch latch = new CountDownLatch(1); - final AtomicBoolean result = new AtomicBoolean(); - peerGroup.addPeerDiscovery(new PeerDiscovery() { - @Override - public InetSocketAddress[] getPeers(long unused, TimeUnit unused2) throws PeerDiscoveryException { - if (!result.getAndSet(true)) { - // Pretend we are not connected to the internet. - throw new PeerDiscoveryException("test failure"); - } else { - // Return a bogus address. - latch.countDown(); - return new InetSocketAddress[]{new InetSocketAddress("localhost", 1)}; - } - } - - @Override - public void shutdown() { - } - }); - peerGroup.start(); - latch.await(); - // Check that we did indeed throw an exception. If we got here it means we threw and then PeerGroup tried - // again a bit later. - assertTrue(result.get()); - } - - // Utility method to create a PeerDiscovery with a certain number of addresses. - private PeerDiscovery createPeerDiscovery(int nrOfAddressesWanted, int port) { - final InetSocketAddress[] addresses = new InetSocketAddress[nrOfAddressesWanted]; - for (int addressNr = 0; addressNr < nrOfAddressesWanted; addressNr++) { - // make each address unique by using the counter to increment the port. - addresses[addressNr] = new InetSocketAddress("localhost", port + addressNr); - } - return new PeerDiscovery() { - public InetSocketAddress[] getPeers(long unused, TimeUnit unused2) throws PeerDiscoveryException { - return addresses; - } - public void shutdown() { - } - }; - } - - @Test - public void multiplePeerDiscovery() throws InterruptedException { - peerGroup.setMaxPeersToDiscoverCount(98); - peerGroup.addPeerDiscovery(createPeerDiscovery(1, 0)); - peerGroup.addPeerDiscovery(createPeerDiscovery(2, 100)); - peerGroup.addPeerDiscovery(createPeerDiscovery(96, 200)); - peerGroup.addPeerDiscovery(createPeerDiscovery(3, 300)); - peerGroup.addPeerDiscovery(createPeerDiscovery(1, 400)); - peerGroup.addEventListener(new AbstractPeerEventListener() { - @Override - public void onPeersDiscovered(Set peerAddresses) { - assertEquals(99, peerAddresses.size()); - } - }); - peerGroup.start(); - } - - @Test - public void receiveTxBroadcast() throws Exception { - // Check that when we receive transactions on all our peers, we do the right thing. - peerGroup.start(); - - // Create a couple of peers. - InboundMessageQueuer p1 = connectPeer(1); - InboundMessageQueuer p2 = connectPeer(2); - - // Check the peer accessors. - assertEquals(2, peerGroup.numConnectedPeers()); - Set tmp = new HashSet(peerGroup.getConnectedPeers()); - Set expectedPeers = new HashSet(); - expectedPeers.add(peerOf(p1)); - expectedPeers.add(peerOf(p2)); - assertEquals(tmp, expectedPeers); - - Coin value = COIN; - Transaction t1 = FakeTxBuilder.createFakeTx(unitTestParams, value, address); - InventoryMessage inv = new InventoryMessage(unitTestParams); - inv.addTransaction(t1); - - // Note: we start with p2 here to verify that transactions are downloaded from whichever peer announces first - // which does not have to be the same as the download peer (which is really the "block download peer"). - inbound(p2, inv); - assertTrue(outbound(p2) instanceof GetDataMessage); - inbound(p1, inv); - assertNull(outbound(p1)); // Only one peer is used to download. - inbound(p2, t1); - assertNull(outbound(p1)); - // Asks for dependency. - GetDataMessage getdata = (GetDataMessage) outbound(p2); - assertNotNull(getdata); - inbound(p2, new NotFoundMessage(unitTestParams, getdata.getItems())); - pingAndWait(p2); - assertEquals(value, wallet.getBalance(Wallet.BalanceType.ESTIMATED)); - } - - - @Test - public void receiveTxBroadcastOnAddedWallet() throws Exception { - // Check that when we receive transactions on all our peers, we do the right thing. - peerGroup.start(); - - // Create a peer. - InboundMessageQueuer p1 = connectPeer(1); - - Wallet wallet2 = new Wallet(unitTestParams); - ECKey key2 = wallet2.freshReceiveKey(); - Address address2 = key2.toAddress(unitTestParams); - - peerGroup.addWallet(wallet2); - blockChain.addWallet(wallet2); - - assertEquals(BloomFilter.class, waitForOutbound(p1).getClass()); - assertEquals(MemoryPoolMessage.class, waitForOutbound(p1).getClass()); - - Coin value = COIN; - Transaction t1 = FakeTxBuilder.createFakeTx(unitTestParams, value, address2); - InventoryMessage inv = new InventoryMessage(unitTestParams); - inv.addTransaction(t1); - - inbound(p1, inv); - assertTrue(outbound(p1) instanceof GetDataMessage); - inbound(p1, t1); - // Asks for dependency. - GetDataMessage getdata = (GetDataMessage) outbound(p1); - assertNotNull(getdata); - inbound(p1, new NotFoundMessage(unitTestParams, getdata.getItems())); - pingAndWait(p1); - assertEquals(value, wallet2.getBalance(Wallet.BalanceType.ESTIMATED)); - } - - @Test - public void singleDownloadPeer1() throws Exception { - // Check that we don't attempt to retrieve blocks on multiple peers. - peerGroup.start(); - - // Create a couple of peers. - InboundMessageQueuer p1 = connectPeer(1); - InboundMessageQueuer p2 = connectPeer(2); - assertEquals(2, peerGroup.numConnectedPeers()); - - // Set up a little block chain. We heard about b1 but not b2 (it is pending download). b3 is solved whilst we - // are downloading the chain. - Block b1 = FakeTxBuilder.createFakeBlock(blockStore).block; - blockChain.add(b1); - Block b2 = FakeTxBuilder.makeSolvedTestBlock(b1); - Block b3 = FakeTxBuilder.makeSolvedTestBlock(b2); - - // Peer 1 and 2 receives an inv advertising a newly solved block. - InventoryMessage inv = new InventoryMessage(params); - inv.addBlock(b3); - // Only peer 1 tries to download it. - inbound(p1, inv); - pingAndWait(p1); - - assertTrue(outbound(p1) instanceof GetDataMessage); - assertNull(outbound(p2)); - // Peer 1 goes away, peer 2 becomes the download peer and thus queries the remote mempool. - final SettableFuture p1CloseFuture = SettableFuture.create(); - peerOf(p1).addEventListener(new AbstractPeerEventListener() { - @Override - public void onPeerDisconnected(Peer peer, int peerCount) { - p1CloseFuture.set(null); - } - }); - closePeer(peerOf(p1)); - p1CloseFuture.get(); - // Peer 2 fetches it next time it hears an inv (should it fetch immediately?). - inbound(p2, inv); - assertTrue(outbound(p2) instanceof GetDataMessage); - } - - @Test - public void singleDownloadPeer2() throws Exception { - // Check that we don't attempt multiple simultaneous block chain downloads, when adding a new peer in the - // middle of an existing chain download. - // Create a couple of peers. - peerGroup.start(); - - // Create a couple of peers. - InboundMessageQueuer p1 = connectPeer(1); - - // Set up a little block chain. - Block b1 = FakeTxBuilder.createFakeBlock(blockStore).block; - Block b2 = FakeTxBuilder.makeSolvedTestBlock(b1); - Block b3 = FakeTxBuilder.makeSolvedTestBlock(b2); - - // Expect a zero hash getblocks on p1. This is how the process starts. - peerGroup.startBlockChainDownload(new AbstractPeerEventListener() { - }); - GetBlocksMessage getblocks = (GetBlocksMessage) outbound(p1); - assertEquals(Sha256Hash.ZERO_HASH, getblocks.getStopHash()); - // We give back an inv with some blocks in it. - InventoryMessage inv = new InventoryMessage(params); - inv.addBlock(b1); - inv.addBlock(b2); - inv.addBlock(b3); - - inbound(p1, inv); - assertTrue(outbound(p1) instanceof GetDataMessage); - // We hand back the first block. - inbound(p1, b1); - // Now we successfully connect to another peer. There should be no messages sent. - InboundMessageQueuer p2 = connectPeer(2); - Message message = (Message)outbound(p2); - assertNull(message == null ? "" : message.toString(), message); - } - - @Test - public void transactionConfidence() throws Exception { - // Checks that we correctly count how many peers broadcast a transaction, so we can establish some measure of - // its trustworthyness assuming an untampered with internet connection. - peerGroup.start(); - - final Transaction[] event = new Transaction[1]; - final TransactionConfidence[] confEvent = new TransactionConfidence[1]; - peerGroup.addEventListener(new AbstractPeerEventListener() { - @Override - public void onTransaction(Peer peer, Transaction t) { - event[0] = t; - } - }, Threading.SAME_THREAD); - - InboundMessageQueuer p1 = connectPeer(1); - InboundMessageQueuer p2 = connectPeer(2); - InboundMessageQueuer p3 = connectPeer(3); - - Transaction tx = FakeTxBuilder.createFakeTx(params, valueOf(20, 0), address); - InventoryMessage inv = new InventoryMessage(params); - inv.addTransaction(tx); - - // Peer 2 advertises the tx but does not receive it yet. - inbound(p2, inv); - assertTrue(outbound(p2) instanceof GetDataMessage); - assertEquals(0, tx.getConfidence().numBroadcastPeers()); - assertTrue(blockChain.getContext().getConfidenceTable().maybeWasSeen(tx.getHash())); - assertNull(event[0]); - // Peer 1 advertises the tx, we don't do anything as it's already been requested. - inbound(p1, inv); - assertNull(outbound(p1)); - // Peer 2 gets sent the tx and requests the dependency. - inbound(p2, tx); - assertTrue(outbound(p2) instanceof GetDataMessage); - tx = event[0]; // We want to use the canonical copy delivered by the PeerGroup from now on. - assertNotNull(tx); - event[0] = null; - - // Peer 1 (the download peer) advertises the tx, we download it. - inbound(p1, inv); // returns getdata - inbound(p1, tx); // returns nothing after a queue drain. - // Two peers saw this tx hash. - assertEquals(2, tx.getConfidence().numBroadcastPeers()); - assertTrue(tx.getConfidence().wasBroadcastBy(peerOf(p1).getAddress())); - assertTrue(tx.getConfidence().wasBroadcastBy(peerOf(p2).getAddress())); - - tx.getConfidence().addEventListener(new TransactionConfidence.Listener() { - @Override - public void onConfidenceChanged(TransactionConfidence confidence, TransactionConfidence.Listener.ChangeReason reason) { - confEvent[0] = confidence; - } - }); - // A straggler reports in. - inbound(p3, inv); - pingAndWait(p3); - Threading.waitForUserCode(); - assertEquals(tx.getHash(), confEvent[0].getTransactionHash()); - assertEquals(3, tx.getConfidence().numBroadcastPeers()); - assertTrue(tx.getConfidence().wasBroadcastBy(peerOf(p3).getAddress())); - } - - @Test - public void testWalletCatchupTime() throws Exception { - // Check the fast catchup time was initialized to something around the current runtime minus a week. - // The wallet was already added to the peer in setup. - final int WEEK = 86400 * 7; - final long now = Utils.currentTimeSeconds(); - peerGroup.start(); - assertTrue(peerGroup.getFastCatchupTimeSecs() > now - WEEK - 10000); - Wallet w2 = new Wallet(params); - ECKey key1 = new ECKey(); - key1.setCreationTimeSeconds(now - 86400); // One day ago. - w2.importKey(key1); - peerGroup.addWallet(w2); - peerGroup.waitForJobQueue(); - assertEquals(peerGroup.getFastCatchupTimeSecs(), now - 86400 - WEEK); - // Adding a key to the wallet should update the fast catchup time, but asynchronously and in the background - // due to the need to avoid complicated lock inversions. - ECKey key2 = new ECKey(); - key2.setCreationTimeSeconds(now - 100000); - w2.importKey(key2); - peerGroup.waitForJobQueue(); - assertEquals(peerGroup.getFastCatchupTimeSecs(), now - WEEK - 100000); - } - - @Test - public void noPings() throws Exception { - peerGroup.start(); - peerGroup.setPingIntervalMsec(0); - VersionMessage versionMessage = new VersionMessage(params, 2); - versionMessage.clientVersion = FilteredBlock.MIN_PROTOCOL_VERSION; - versionMessage.localServices = VersionMessage.NODE_NETWORK; - connectPeer(1, versionMessage); - peerGroup.waitForPeers(1).get(); - assertFalse(peerGroup.getConnectedPeers().get(0).getLastPingTime() < Long.MAX_VALUE); - } - - @Test - public void pings() throws Exception { - peerGroup.start(); - peerGroup.setPingIntervalMsec(100); - VersionMessage versionMessage = new VersionMessage(params, 2); - versionMessage.clientVersion = FilteredBlock.MIN_PROTOCOL_VERSION; - versionMessage.localServices = VersionMessage.NODE_NETWORK; - InboundMessageQueuer p1 = connectPeer(1, versionMessage); - Ping ping = (Ping) waitForOutbound(p1); - inbound(p1, new Pong(ping.getNonce())); - pingAndWait(p1); - assertTrue(peerGroup.getConnectedPeers().get(0).getLastPingTime() < Long.MAX_VALUE); - // The call to outbound should block until a ping arrives. - ping = (Ping) waitForOutbound(p1); - inbound(p1, new Pong(ping.getNonce())); - assertTrue(peerGroup.getConnectedPeers().get(0).getLastPingTime() < Long.MAX_VALUE); - } - - @Test - public void downloadPeerSelection() throws Exception { - peerGroup.start(); - VersionMessage versionMessage2 = new VersionMessage(params, 2); - versionMessage2.clientVersion = FilteredBlock.MIN_PROTOCOL_VERSION; - versionMessage2.localServices = VersionMessage.NODE_NETWORK; - VersionMessage versionMessage3 = new VersionMessage(params, 3); - versionMessage3.clientVersion = FilteredBlock.MIN_PROTOCOL_VERSION; - versionMessage3.localServices = VersionMessage.NODE_NETWORK; - assertNull(peerGroup.getDownloadPeer()); - Peer a = connectPeer(1, versionMessage2).peer; - assertEquals(2, peerGroup.getMostCommonChainHeight()); - assertEquals(a, peerGroup.getDownloadPeer()); - connectPeer(2, versionMessage2); - assertEquals(2, peerGroup.getMostCommonChainHeight()); - assertEquals(a, peerGroup.getDownloadPeer()); // No change. - Peer c = connectPeer(3, versionMessage3).peer; - assertEquals(2, peerGroup.getMostCommonChainHeight()); - assertEquals(a, peerGroup.getDownloadPeer()); // No change yet. - connectPeer(4, versionMessage3); - assertEquals(3, peerGroup.getMostCommonChainHeight()); - assertEquals(c, peerGroup.getDownloadPeer()); // Switch to first peer advertising new height. - // New peer with a higher protocol version but same chain height. - //TODO: When PeerGroup.selectDownloadPeer.PREFERRED_VERSION is not equal to vMinRequiredProtocolVersion, - // reenable this test - /*VersionMessage versionMessage4 = new VersionMessage(params, 3); - versionMessage4.clientVersion = 100000; - versionMessage4.localServices = VersionMessage.NODE_NETWORK; - InboundMessageQueuer d = connectPeer(5, versionMessage4); - assertEquals(d.peer, peerGroup.getDownloadPeer());*/ - } - - @Test - public void peerTimeoutTest() throws Exception { - peerGroup.start(); - peerGroup.setConnectTimeoutMillis(100); - - final SettableFuture peerConnectedFuture = SettableFuture.create(); - final SettableFuture peerDisconnectedFuture = SettableFuture.create(); - peerGroup.addEventListener(new AbstractPeerEventListener() { - @Override - public void onPeerConnected(Peer peer, int peerCount) { - peerConnectedFuture.set(null); - } - - @Override - public void onPeerDisconnected(Peer peer, int peerCount) { - peerDisconnectedFuture.set(null); - } - }, Threading.SAME_THREAD); - connectPeerWithoutVersionExchange(0); - Thread.sleep(50); - assertFalse(peerConnectedFuture.isDone() || peerDisconnectedFuture.isDone()); - Thread.sleep(60); - assertTrue(!peerConnectedFuture.isDone()); - assertTrue(!peerConnectedFuture.isDone() && peerDisconnectedFuture.isDone()); - } - - @Test - public void peerPriority() throws Exception { - final List addresses = Lists.newArrayList( - new InetSocketAddress("localhost", 2000), - new InetSocketAddress("localhost", 2001), - new InetSocketAddress("localhost", 2002) - ); - peerGroup.addEventListener(listener); - peerGroup.addPeerDiscovery(new PeerDiscovery() { - @Override - public InetSocketAddress[] getPeers(long unused, TimeUnit unused2) throws PeerDiscoveryException { - return addresses.toArray(new InetSocketAddress[addresses.size()]); - } - - @Override - public void shutdown() { - } - }); - peerGroup.setMaxConnections(3); - - Utils.setMockSleep(true); - blockJobs = true; - - jobBlocks.release(2); // startup + first peer discovery - peerGroup.start(); - - jobBlocks.release(3); // One for each peer. - handleConnectToPeer(0); - handleConnectToPeer(1); - handleConnectToPeer(2); - connectedPeers.take(); - connectedPeers.take(); - connectedPeers.take(); - addresses.clear(); - addresses.addAll(Lists.newArrayList(new InetSocketAddress("localhost", 2003))); - stopPeerServer(2); - assertEquals(2002, disconnectedPeers.take().getAddress().getPort()); // peer died - - // discovers, connects to new peer - jobBlocks.release(1); - handleConnectToPeer(3); - assertEquals(2003, connectedPeers.take().getAddress().getPort()); - - stopPeerServer(1); - assertEquals(2001, disconnectedPeers.take().getAddress().getPort()); // peer died - - // Alternates trying two offline peers - jobBlocks.release(10); - assertEquals(2001, disconnectedPeers.take().getAddress().getPort()); - assertEquals(2002, disconnectedPeers.take().getAddress().getPort()); - assertEquals(2001, disconnectedPeers.take().getAddress().getPort()); - assertEquals(2002, disconnectedPeers.take().getAddress().getPort()); - assertEquals(2001, disconnectedPeers.take().getAddress().getPort()); - - // Peer 2 comes online - startPeerServer(2); - jobBlocks.release(1); - handleConnectToPeer(2); - assertEquals(2002, connectedPeers.take().getAddress().getPort()); - - jobBlocks.release(6); - stopPeerServer(2); - assertEquals(2002, disconnectedPeers.take().getAddress().getPort()); // peer died - - // Peer 2 is tried before peer 1, since it has a lower backoff due to recent success - assertEquals(2002, disconnectedPeers.take().getAddress().getPort()); - assertEquals(2001, disconnectedPeers.take().getAddress().getPort()); - } - - @Test - public void testBloomOnP2Pubkey() throws Exception { - // Cover bug 513. When a relevant transaction with a p2pubkey output is found, the Bloom filter should be - // recalculated to include that transaction hash but not re-broadcast as the remote nodes should have followed - // the same procedure. However a new node that's connected should get the fresh filter. - peerGroup.start(); - final ECKey key = wallet.currentReceiveKey(); - // Create a couple of peers. - InboundMessageQueuer p1 = connectPeer(1); - InboundMessageQueuer p2 = connectPeer(2); - // Create a pay to pubkey tx. - Transaction tx = FakeTxBuilder.createFakeTx(params, COIN, key); - Transaction tx2 = new Transaction(params); - tx2.addInput(tx.getOutput(0)); - TransactionOutPoint outpoint = tx2.getInput(0).getOutpoint(); - assertTrue(p1.lastReceivedFilter.contains(key.getPubKey())); - assertFalse(p1.lastReceivedFilter.contains(tx.getHash().getBytes())); - inbound(p1, tx); - // p1 requests dep resolution, p2 is quiet. - assertTrue(outbound(p1) instanceof GetDataMessage); - final Sha256Hash dephash = tx.getInput(0).getOutpoint().getHash(); - final InventoryItem inv = new InventoryItem(InventoryItem.Type.Transaction, dephash); - inbound(p1, new NotFoundMessage(params, ImmutableList.of(inv))); - assertNull(outbound(p1)); - assertNull(outbound(p2)); - peerGroup.waitForJobQueue(); - // Now we connect p3 and there is a new bloom filter sent, that DOES match the relevant outpoint. - InboundMessageQueuer p3 = connectPeer(3); - assertTrue(p3.lastReceivedFilter.contains(key.getPubKey())); - assertTrue(p3.lastReceivedFilter.contains(outpoint.bitcoinSerialize())); - } - - @Test - public void testBloomResendOnNewKey() throws Exception { - // Check that when we add a new key to the wallet, the Bloom filter is re-calculated and re-sent but only once - // we exceed the lookahead threshold. - wallet.setKeychainLookaheadSize(5); - wallet.setKeychainLookaheadThreshold(4); - peerGroup.start(); - // Create a couple of peers. - InboundMessageQueuer p1 = connectPeer(1); - InboundMessageQueuer p2 = connectPeer(2); - peerGroup.waitForJobQueue(); - BloomFilter f1 = p1.lastReceivedFilter; - ECKey key = null; - // We have to run ahead of the lookahead zone for this test. There should only be one bloom filter recalc. - for (int i = 0; i < wallet.getKeychainLookaheadSize() + wallet.getKeychainLookaheadThreshold() + 1; i++) { - key = wallet.freshReceiveKey(); - } - peerGroup.waitForJobQueue(); - BloomFilter bf, f2 = null; - while ((bf = (BloomFilter) outbound(p1)) != null) { - assertEquals(MemoryPoolMessage.class, outbound(p1).getClass()); - f2 = bf; - } - assertNotNull(key); - assertNotNull(f2); - assertNull(outbound(p1)); - // Check the last filter received. - assertNotEquals(f1, f2); - assertTrue(f2.contains(key.getPubKey())); - assertTrue(f2.contains(key.getPubKeyHash())); - assertFalse(f1.contains(key.getPubKey())); - assertFalse(f1.contains(key.getPubKeyHash())); - } - - @Test - public void waitForNumPeers1() throws Exception { - ListenableFuture> future = peerGroup.waitForPeers(3); - peerGroup.start(); - assertFalse(future.isDone()); - connectPeer(1); - assertFalse(future.isDone()); - connectPeer(2); - assertFalse(future.isDone()); - assertTrue(peerGroup.waitForPeers(2).isDone()); // Immediate completion. - connectPeer(3); - future.get(); - assertTrue(future.isDone()); - } - - @Test - public void waitForPeersOfVersion() throws Exception { - final int baseVer = peerGroup.getMinRequiredProtocolVersion() + 3000; - final int newVer = baseVer + 1000; - - ListenableFuture> future = peerGroup.waitForPeersOfVersion(2, newVer); - - VersionMessage ver1 = new VersionMessage(params, 10); - ver1.clientVersion = baseVer; - ver1.localServices = VersionMessage.NODE_NETWORK; - VersionMessage ver2 = new VersionMessage(params, 10); - ver2.clientVersion = newVer; - ver2.localServices = VersionMessage.NODE_NETWORK; - peerGroup.start(); - assertFalse(future.isDone()); - connectPeer(1, ver1); - assertFalse(future.isDone()); - connectPeer(2, ver2); - assertFalse(future.isDone()); - assertTrue(peerGroup.waitForPeersOfVersion(1, newVer).isDone()); // Immediate completion. - connectPeer(3, ver2); - future.get(); - assertTrue(future.isDone()); - } - - @Test - public void waitForPeersWithServiceFlags() throws Exception { - ListenableFuture> future = peerGroup.waitForPeersWithServiceMask(2, 3); - - VersionMessage ver1 = new VersionMessage(params, 10); - ver1.clientVersion = 70000; - ver1.localServices = VersionMessage.NODE_NETWORK; - VersionMessage ver2 = new VersionMessage(params, 10); - ver2.clientVersion = 70000; - ver2.localServices = VersionMessage.NODE_NETWORK | 2; - peerGroup.start(); - assertFalse(future.isDone()); - connectPeer(1, ver1); - assertTrue(peerGroup.findPeersWithServiceMask(3).isEmpty()); - assertFalse(future.isDone()); - connectPeer(2, ver2); - assertFalse(future.isDone()); - assertEquals(1, peerGroup.findPeersWithServiceMask(3).size()); - assertTrue(peerGroup.waitForPeersWithServiceMask(1, 0x3).isDone()); // Immediate completion. - connectPeer(3, ver2); - future.get(); - assertTrue(future.isDone()); - peerGroup.stop(); - } - - @Test - public void preferLocalPeer() throws IOException { - // Because we are using the same port (8333 or 18333) that is used by Satoshi client - // We have to consider 2 cases: - // 1. Test are executed on the same machine that is running full node / Satoshi client - // 2. Test are executed without any full node running locally - // We have to avoid to connecting to real and external services in unit tests - // So we skip this test in case we have already something running on port params.getPort() - - // Check that if we have a localhost port 8333 or 18333 then it's used instead of the p2p network. - ServerSocket local = null; - try { - local = new ServerSocket(params.getPort(), 100, InetAddresses.forString("127.0.0.1")); - } - catch(BindException e) { // Port already in use, skipping this test. - return; - } - - try { - peerGroup.setUseLocalhostPeerWhenPossible(true); - peerGroup.start(); - local.accept().close(); // Probe connect - local.accept(); // Real connect - // If we get here it used the local peer. Check no others are in use. - assertEquals(1, peerGroup.getMaxConnections()); - assertEquals(PeerAddress.localhost(params), peerGroup.getPendingPeers().get(0).getAddress()); - } finally { - local.close(); - } - } - - private T assertNextMessageIs(InboundMessageQueuer q, Class klass) throws Exception { - Message outbound = waitForOutbound(q); - assertEquals(klass, outbound.getClass()); - return (T) outbound; - } - - @Test - public void autoRescanOnKeyExhaustion() throws Exception { - // Check that if the last key that was inserted into the bloom filter is seen in some requested blocks, - // that the exhausting block is discarded, a new filter is calculated and sent, and then the download resumes. - - final int NUM_KEYS = 9; - - // First, grab a load of keys from the wallet, and then recreate it so it forgets that those keys were issued. - Wallet shadow = Wallet.fromSeed(wallet.getParams(), wallet.getKeyChainSeed()); - List keys = new ArrayList(NUM_KEYS); - for (int i = 0; i < NUM_KEYS; i++) { - keys.add(shadow.freshReceiveKey()); - } - // Reduce the number of keys we need to work with to speed up this test. - wallet.setKeychainLookaheadSize(4); - wallet.setKeychainLookaheadThreshold(2); - - peerGroup.start(); - InboundMessageQueuer p1 = connectPeer(1); - assertTrue(p1.lastReceivedFilter.contains(keys.get(0).getPubKey())); - assertTrue(p1.lastReceivedFilter.contains(keys.get(5).getPubKeyHash())); - assertFalse(p1.lastReceivedFilter.contains(keys.get(keys.size() - 1).getPubKey())); - peerGroup.startBlockChainDownload(null); - assertNextMessageIs(p1, GetBlocksMessage.class); - - // Make some transactions and blocks that send money to the wallet thus using up all the keys. - List blocks = Lists.newArrayList(); - Coin expectedBalance = Coin.ZERO; - Block prev = blockStore.getChainHead().getHeader(); - for (ECKey key1 : keys) { - Address addr = key1.toAddress(params); - Block next = FakeTxBuilder.makeSolvedTestBlock(prev, FakeTxBuilder.createFakeTx(params, Coin.FIFTY_COINS, addr)); - expectedBalance = expectedBalance.add(next.getTransactions().get(2).getOutput(0).getValue()); - blocks.add(next); - prev = next; - } - - // Send the chain that doesn't have all the transactions in it. The blocks after the exhaustion point should all - // be ignored. - int epoch = wallet.keychain.getCombinedKeyLookaheadEpochs(); - BloomFilter filter = new BloomFilter(params, p1.lastReceivedFilter.bitcoinSerialize()); - filterAndSend(p1, blocks, filter); - Block exhaustionPoint = blocks.get(3); - pingAndWait(p1); - - assertNotEquals(epoch, wallet.keychain.getCombinedKeyLookaheadEpochs()); - // 4th block was end of the lookahead zone and thus was discarded, so we got 3 blocks worth of money (50 each). - assertEquals(Coin.FIFTY_COINS.multiply(3), wallet.getBalance()); - assertEquals(exhaustionPoint.getPrevBlockHash(), blockChain.getChainHead().getHeader().getHash()); - - // Await the new filter. - peerGroup.waitForJobQueue(); - BloomFilter newFilter = assertNextMessageIs(p1, BloomFilter.class); - assertNotEquals(filter, newFilter); - assertNextMessageIs(p1, MemoryPoolMessage.class); - Ping ping = assertNextMessageIs(p1, Ping.class); - inbound(p1, new Pong(ping.getNonce())); - - // Await restart of the chain download. - GetDataMessage getdata = assertNextMessageIs(p1, GetDataMessage.class); - assertEquals(exhaustionPoint.getHash(), getdata.getHashOf(0)); - assertEquals(InventoryItem.Type.FilteredBlock, getdata.getItems().get(0).type); - List newBlocks = blocks.subList(3, blocks.size()); - filterAndSend(p1, newBlocks, newFilter); - assertNextMessageIs(p1, Ping.class); - - // It happened again. - peerGroup.waitForJobQueue(); - newFilter = assertNextMessageIs(p1, BloomFilter.class); - assertNextMessageIs(p1, MemoryPoolMessage.class); - inbound(p1, new Pong(assertNextMessageIs(p1, Ping.class).getNonce())); - assertNextMessageIs(p1, GetDataMessage.class); - newBlocks = blocks.subList(6, blocks.size()); - filterAndSend(p1, newBlocks, newFilter); - // Send a non-tx message so the peer knows the filtered block is over and force processing. - inbound(p1, new Ping()); - pingAndWait(p1); - - assertEquals(expectedBalance, wallet.getBalance()); - assertEquals(blocks.get(blocks.size() - 1).getHash(), blockChain.getChainHead().getHeader().getHash()); - } - - private void filterAndSend(InboundMessageQueuer p1, List blocks, BloomFilter filter) { - for (Block block : blocks) { - FilteredBlock fb = filter.applyAndUpdate(block); - inbound(p1, fb); - for (Transaction tx : fb.getAssociatedTransactions().values()) - inbound(p1, tx); - } - } -} diff --git a/src/test/java/org/altcoinj/core/TransactionBroadcastTest.java b/src/test/java/org/altcoinj/core/TransactionBroadcastTest.java deleted file mode 100644 index 9b57af16..00000000 --- a/src/test/java/org/altcoinj/core/TransactionBroadcastTest.java +++ /dev/null @@ -1,231 +0,0 @@ -/** - * Copyright 2013 Google Inc. - * Copyright 2014 Andreas Schildbach - * - * 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 - * - * http://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. - */ - -package com.dogecoin.dogecoinj.core; - -import com.dogecoin.dogecoinj.params.UnitTestParams; -import com.dogecoin.dogecoinj.testing.FakeTxBuilder; -import com.dogecoin.dogecoinj.testing.InboundMessageQueuer; -import com.dogecoin.dogecoinj.testing.TestWithPeerGroup; -import com.dogecoin.dogecoinj.utils.Threading; -import com.google.common.util.concurrent.ListenableFuture; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Random; -import java.util.concurrent.*; - -import static com.dogecoin.dogecoinj.core.Coin.*; -import static com.google.common.base.Preconditions.checkNotNull; -import static org.junit.Assert.*; - -@RunWith(value = Parameterized.class) -public class TransactionBroadcastTest extends TestWithPeerGroup { - static final NetworkParameters params = UnitTestParams.get(); - - @Parameterized.Parameters - public static Collection parameters() { - return Arrays.asList(new ClientType[] {ClientType.NIO_CLIENT_MANAGER}, - new ClientType[] {ClientType.BLOCKING_CLIENT_MANAGER}); - } - - public TransactionBroadcastTest(ClientType clientType) { - super(clientType); - } - - @Override - @Before - public void setUp() throws Exception { - Utils.setMockClock(); // Use mock clock - super.setUp(); - // Fix the random permutation that TransactionBroadcast uses to shuffle the peers. - TransactionBroadcast.random = new Random(0); - peerGroup.setMinBroadcastConnections(2); - peerGroup.start(); - } - - @Override - @After - public void tearDown() { - super.tearDown(); - } - - @Test - public void fourPeers() throws Exception { - InboundMessageQueuer[] channels = { connectPeer(1), connectPeer(2), connectPeer(3), connectPeer(4) }; - Transaction tx = new Transaction(params); - TransactionBroadcast broadcast = new TransactionBroadcast(peerGroup, blockChain.getContext(), tx); - ListenableFuture future = broadcast.broadcast(); - assertFalse(future.isDone()); - // We expect two peers to receive a tx message, and at least one of the others must announce for the future to - // complete successfully. - Message[] messages = { - (Message) outbound(channels[0]), - (Message) outbound(channels[1]), - (Message) outbound(channels[2]), - (Message) outbound(channels[3]) - }; - // 0 and 3 are randomly selected to receive the broadcast. - assertEquals(tx, messages[0]); - assertEquals(tx, messages[3]); - assertNull(messages[1]); - assertNull(messages[2]); - Threading.waitForUserCode(); - assertFalse(future.isDone()); - inbound(channels[1], InventoryMessage.with(tx)); - pingAndWait(channels[1]); - Threading.waitForUserCode(); - // FIXME flaky test - future is not handled on user thread - assertTrue(future.isDone()); - } - - @Test - public void rejectHandling() throws Exception { - InboundMessageQueuer[] channels = { connectPeer(0), connectPeer(1), connectPeer(2), connectPeer(3), connectPeer(4) }; - Transaction tx = new Transaction(params); - TransactionBroadcast broadcast = new TransactionBroadcast(peerGroup, blockChain.getContext(), tx); - ListenableFuture future = broadcast.broadcast(); - // 0 and 3 are randomly selected to receive the broadcast. - assertEquals(tx, outbound(channels[1])); - assertEquals(tx, outbound(channels[2])); - assertEquals(tx, outbound(channels[4])); - RejectMessage reject = new RejectMessage(params, RejectMessage.RejectCode.DUST, tx.getHash(), "tx", "dust"); - inbound(channels[1], reject); - inbound(channels[4], reject); - try { - future.get(); - fail(); - } catch (ExecutionException e) { - assertEquals(RejectedTransactionException.class, e.getCause().getClass()); - } - } - - @Test - public void retryFailedBroadcast() throws Exception { - // If we create a spend, it's sent to a peer that swallows it, and the peergroup is removed/re-added then - // the tx should be broadcast again. - InboundMessageQueuer p1 = connectPeer(1); - connectPeer(2); - - // Send ourselves a bit of money. - Block b1 = FakeTxBuilder.makeSolvedTestBlock(blockStore, address); - inbound(p1, b1); - assertNull(outbound(p1)); - assertEquals(FIFTY_COINS, wallet.getBalance()); - - // Now create a spend, and expect the announcement on p1. - Address dest = new ECKey().toAddress(params); - Wallet.SendResult sendResult = wallet.sendCoins(peerGroup, dest, COIN); - assertFalse(sendResult.broadcastComplete.isDone()); - Transaction t1; - { - Message m; - while (!((m = outbound(p1)) instanceof Transaction)); - t1 = (Transaction) m; - } - assertFalse(sendResult.broadcastComplete.isDone()); - - // p1 eats it :( A bit later the PeerGroup is taken down. - peerGroup.removeWallet(wallet); - peerGroup.addWallet(wallet); - - // We want to hear about it again. Now, because we've disabled the randomness for the unit tests it will - // re-appear on p1 again. Of course in the real world it would end up with a different set of peers and - // select randomly so we get a second chance. - Transaction t2 = (Transaction) outbound(p1); - assertEquals(t1, t2); - } - - @Test - public void peerGroupWalletIntegration() throws Exception { - // Make sure we can create spends, and that they are announced. Then do the same with offline mode. - - // Set up connections and block chain. - VersionMessage ver = new VersionMessage(params, 2); - ver.localServices = VersionMessage.NODE_NETWORK; - InboundMessageQueuer p1 = connectPeer(1, ver); - InboundMessageQueuer p2 = connectPeer(2); - - // Send ourselves a bit of money. - Block b1 = FakeTxBuilder.makeSolvedTestBlock(blockStore, address); - inbound(p1, b1); - pingAndWait(p1); - assertNull(outbound(p1)); - assertEquals(FIFTY_COINS, wallet.getBalance()); - - // Check that the wallet informs us of changes in confidence as the transaction ripples across the network. - final Transaction[] transactions = new Transaction[1]; - wallet.addEventListener(new AbstractWalletEventListener() { - @Override - public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) { - transactions[0] = tx; - } - }); - - // Now create a spend, and expect the announcement on p1. - Address dest = new ECKey().toAddress(params); - Wallet.SendResult sendResult = wallet.sendCoins(peerGroup, dest, COIN); - assertNotNull(sendResult.tx); - Threading.waitForUserCode(); - assertFalse(sendResult.broadcastComplete.isDone()); - assertEquals(transactions[0], sendResult.tx); - assertEquals(0, transactions[0].getConfidence().numBroadcastPeers()); - transactions[0] = null; - Transaction t1; - { - peerGroup.waitForJobQueue(); - Message m = outbound(p1); - // Hack: bloom filters are recalculated asynchronously to sending transactions to avoid lock - // inversion, so we might or might not get the filter/mempool message first or second. - while (!(m instanceof Transaction)) m = outbound(p1); - t1 = (Transaction) m; - } - assertNotNull(t1); - // 49 BTC in change. - assertEquals(valueOf(49, 0), t1.getValueSentToMe(wallet)); - // The future won't complete until it's heard back from the network on p2. - InventoryMessage inv = new InventoryMessage(params); - inv.addTransaction(t1); - inbound(p2, inv); - pingAndWait(p2); - Threading.waitForUserCode(); - assertTrue(sendResult.broadcastComplete.isDone()); - assertEquals(transactions[0], sendResult.tx); - assertEquals(1, transactions[0].getConfidence().numBroadcastPeers()); - // Confirm it. - Block b2 = FakeTxBuilder.createFakeBlock(blockStore, t1).block; - inbound(p1, b2); - pingAndWait(p1); - assertNull(outbound(p1)); - - // Do the same thing with an offline transaction. - peerGroup.removeWallet(wallet); - Wallet.SendRequest req = Wallet.SendRequest.to(dest, valueOf(2, 0)); - req.ensureMinRequiredFee = false; - Transaction t3 = checkNotNull(wallet.sendCoinsOffline(req)); - assertNull(outbound(p1)); // Nothing sent. - // Add the wallet to the peer group (simulate initialization). Transactions should be announced. - peerGroup.addWallet(wallet); - // Transaction announced to the first peer. No extra Bloom filter because no change address was needed. - assertEquals(t3.getHash(), ((Transaction) outbound(p1)).getHash()); - } -} diff --git a/src/test/java/org/altcoinj/core/VersionedChecksummedBytesTest.java b/src/test/java/org/altcoinj/core/VersionedChecksummedBytesTest.java deleted file mode 100644 index 0db3b1aa..00000000 --- a/src/test/java/org/altcoinj/core/VersionedChecksummedBytesTest.java +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright 2014 BitcoinJ Project - * - * 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 - * - * http://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. - */ - -package com.dogecoin.dogecoinj.core; - -import com.dogecoin.dogecoinj.params.MainNetParams; -import com.dogecoin.dogecoinj.params.TestNet3Params; -import org.junit.Test; - -import static com.dogecoin.dogecoinj.core.Utils.HEX; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; - -/** - * - */ -public class VersionedChecksummedBytesTest { - static final NetworkParameters testParams = TestNet3Params.get(); - static final NetworkParameters mainParams = MainNetParams.get(); - - @Test - public void stringification() throws Exception { - // Test a testnet address. - VersionedChecksummedBytes a = new VersionedChecksummedBytes(testParams.getAddressHeader(), HEX.decode("fda79a24e50ff70ff42f7d89585da5bd19d9e5cc")); - assertEquals("n4eA2nbYqErp7H6jebchxAN59DmNpksexv", a.toString()); - - VersionedChecksummedBytes b = new VersionedChecksummedBytes(mainParams.getAddressHeader(), HEX.decode("4a22c3c4cbb31e4d03b15550636762bda0baf85a")); - assertEquals("17kzeh4N8g49GFvdDzSf8PjaPfyoD1MndL", b.toString()); - } - - @Test - public void cloning() throws Exception { - VersionedChecksummedBytes a = new VersionedChecksummedBytes(testParams.getAddressHeader(), HEX.decode("fda79a24e50ff70ff42f7d89585da5bd19d9e5cc")); - VersionedChecksummedBytes b = a.clone(); - - assertEquals(a, b); - assertNotSame(a, b); - } - - @Test - public void comparisonCloneEqualTo() throws Exception { - VersionedChecksummedBytes a = new VersionedChecksummedBytes(testParams.getAddressHeader(), HEX.decode("fda79a24e50ff70ff42f7d89585da5bd19d9e5cc")); - VersionedChecksummedBytes b = a.clone(); - - assertTrue(a.compareTo(b) == 0); - } -} diff --git a/src/test/java/org/altcoinj/core/WalletTest.java b/src/test/java/org/altcoinj/core/WalletTest.java deleted file mode 100644 index 20bf0211..00000000 --- a/src/test/java/org/altcoinj/core/WalletTest.java +++ /dev/null @@ -1,3122 +0,0 @@ -/** - * Copyright 2011 Google Inc. - * Copyright 2014 Andreas Schildbach - * - * 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 - * - * http://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. - */ - -package com.dogecoin.dogecoinj.core; - -import com.dogecoin.dogecoinj.core.Wallet.SendRequest; -import com.dogecoin.dogecoinj.crypto.*; -import com.dogecoin.dogecoinj.script.Script; -import com.dogecoin.dogecoinj.script.ScriptBuilder; -import com.dogecoin.dogecoinj.script.ScriptOpCodes; -import com.dogecoin.dogecoinj.signers.StatelessTransactionSigner; -import com.dogecoin.dogecoinj.signers.TransactionSigner; -import com.dogecoin.dogecoinj.store.BlockStoreException; -import com.dogecoin.dogecoinj.store.MemoryBlockStore; -import com.dogecoin.dogecoinj.store.UnreadableWalletException; -import com.dogecoin.dogecoinj.store.WalletProtobufSerializer; -import com.dogecoin.dogecoinj.testing.*; -import com.dogecoin.dogecoinj.utils.ExchangeRate; -import com.dogecoin.dogecoinj.utils.Fiat; -import com.dogecoin.dogecoinj.utils.Threading; -import com.dogecoin.dogecoinj.wallet.*; -import com.dogecoin.dogecoinj.wallet.WalletTransaction.Pool; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; -import com.google.common.util.concurrent.ListenableFuture; -import com.google.protobuf.ByteString; -import com.dogecoin.dogecoinj.wallet.Protos.Wallet.EncryptionType; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.spongycastle.crypto.params.KeyParameter; - -import java.io.File; -import java.math.BigInteger; -import java.net.InetAddress; -import java.security.SecureRandom; -import java.util.*; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; - -import static com.dogecoin.dogecoinj.core.Coin.*; -import static com.dogecoin.dogecoinj.core.Utils.HEX; -import static com.dogecoin.dogecoinj.testing.FakeTxBuilder.*; -import static com.google.common.base.Preconditions.checkNotNull; -import static org.junit.Assert.*; - -public class WalletTest extends TestWithWallet { - private static final Logger log = LoggerFactory.getLogger(WalletTest.class); - - private static final CharSequence PASSWORD1 = "my helicopter contains eels"; - private static final CharSequence WRONG_PASSWORD = "nothing noone nobody nowhere"; - - private SecureRandom secureRandom = new SecureRandom(); - - private ECKey someOtherKey = new ECKey(); - private Address someOtherAddress = someOtherKey.toAddress(params); - - @Before - @Override - public void setUp() throws Exception { - super.setUp(); - } - - @After - @Override - public void tearDown() throws Exception { - super.tearDown(); - } - - private void createMarriedWallet(int threshold, int numKeys) throws BlockStoreException { - createMarriedWallet(threshold, numKeys, true); - } - - private void createMarriedWallet(int threshold, int numKeys, boolean addSigners) throws BlockStoreException { - wallet = new Wallet(params); - blockStore = new MemoryBlockStore(params); - chain = new BlockChain(params, wallet, blockStore); - - List followingKeys = Lists.newArrayList(); - for (int i = 0; i < numKeys - 1; i++) { - final DeterministicKeyChain keyChain = new DeterministicKeyChain(new SecureRandom()); - DeterministicKey partnerKey = DeterministicKey.deserializeB58(null, keyChain.getWatchingKey().serializePubB58(params), params); - followingKeys.add(partnerKey); - if (addSigners && i < threshold - 1) - wallet.addTransactionSigner(new KeyChainTransactionSigner(keyChain)); - } - - MarriedKeyChain chain = MarriedKeyChain.builder() - .random(new SecureRandom()) - .followingKeys(followingKeys) - .threshold(threshold).build(); - wallet.addAndActivateHDChain(chain); - } - - @Test - public void getSeedAsWords1() { - // Can't verify much here as the wallet is random each time. We could fix the RNG for the unit tests and solve. - assertEquals(12, wallet.getKeyChainSeed().getMnemonicCode().size()); - } - - @Test - public void checkSeed() throws MnemonicException { - wallet.getKeyChainSeed().check(); - } - - @Test - public void basicSpending() throws Exception { - basicSpendingCommon(wallet, myAddress, new ECKey().toAddress(params), null); - } - - @Test - public void basicSpendingToP2SH() throws Exception { - Address destination = new Address(params, params.getP2SHHeader(), HEX.decode("4a22c3c4cbb31e4d03b15550636762bda0baf85a")); - basicSpendingCommon(wallet, myAddress, destination, null); - } - - @Test - public void basicSpendingWithEncryptedWallet() throws Exception { - Wallet encryptedWallet = new Wallet(params); - encryptedWallet.encrypt(PASSWORD1); - Address myEncryptedAddress = encryptedWallet.freshReceiveKey().toAddress(params); - basicSpendingCommon(encryptedWallet, myEncryptedAddress, new ECKey().toAddress(params), encryptedWallet); - } - - @Test - public void basicSpendingFromP2SH() throws Exception { - createMarriedWallet(2, 2); - myAddress = wallet.currentAddress(KeyChain.KeyPurpose.RECEIVE_FUNDS); - basicSpendingCommon(wallet, myAddress, new ECKey().toAddress(params), null); - - createMarriedWallet(2, 3); - myAddress = wallet.currentAddress(KeyChain.KeyPurpose.RECEIVE_FUNDS); - basicSpendingCommon(wallet, myAddress, new ECKey().toAddress(params), null); - - createMarriedWallet(3, 3); - myAddress = wallet.currentAddress(KeyChain.KeyPurpose.RECEIVE_FUNDS); - basicSpendingCommon(wallet, myAddress, new ECKey().toAddress(params), null); - } - - @Test (expected = IllegalArgumentException.class) - public void thresholdShouldNotExceedNumberOfKeys() throws Exception { - createMarriedWallet(3, 2); - } - - @Test - public void spendingWithIncompatibleSigners() throws Exception { - wallet.addTransactionSigner(new NopTransactionSigner(true)); - basicSpendingCommon(wallet, myAddress, new ECKey().toAddress(params), null); - } - - static class TestRiskAnalysis implements RiskAnalysis { - private final boolean risky; - - public TestRiskAnalysis(boolean risky) { - this.risky = risky; - } - - @Override - public Result analyze() { - return risky ? Result.NON_FINAL : Result.OK; - } - - public static class Analyzer implements RiskAnalysis.Analyzer { - private final Transaction riskyTx; - - Analyzer(Transaction riskyTx) { - this.riskyTx = riskyTx; - } - - @Override - public RiskAnalysis create(Wallet wallet, Transaction tx, List dependencies) { - return new TestRiskAnalysis(tx == riskyTx); - } - } - } - - static class TestCoinSelector extends DefaultCoinSelector { - @Override - protected boolean shouldSelect(Transaction tx) { - return true; - } - } - - private Transaction cleanupCommon(Address destination) throws Exception { - receiveATransaction(wallet, myAddress); - - Coin v2 = valueOf(0, 50); - SendRequest req = SendRequest.to(destination, v2); - req.fee = CENT; - wallet.completeTx(req); - - Transaction t2 = req.tx; - - // Broadcast the transaction and commit. - broadcastAndCommit(wallet, t2); - - // At this point we have one pending and one spent - - Coin v1 = valueOf(0, 10); - Transaction t = sendMoneyToWallet(wallet, v1, myAddress, null); - Threading.waitForUserCode(); - sendMoneyToWallet(wallet, t, null); - assertEquals("Wrong number of PENDING.4", 2, wallet.getPoolSize(Pool.PENDING)); - assertEquals("Wrong number of UNSPENT.4", 0, wallet.getPoolSize(Pool.UNSPENT)); - assertEquals("Wrong number of ALL.4", 3, wallet.getTransactions(true).size()); - assertEquals(valueOf(0, 59), wallet.getBalance(Wallet.BalanceType.ESTIMATED)); - - // Now we have another incoming pending - return t; - } - - @Test - public void cleanup() throws Exception { - Address destination = new ECKey().toAddress(params); - Transaction t = cleanupCommon(destination); - - // Consider the new pending as risky and remove it from the wallet - wallet.setRiskAnalyzer(new TestRiskAnalysis.Analyzer(t)); - - wallet.cleanup(); - assertTrue(wallet.isConsistent()); - assertEquals("Wrong number of PENDING.5", 1, wallet.getPoolSize(WalletTransaction.Pool.PENDING)); - assertEquals("Wrong number of UNSPENT.5", 0, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT)); - assertEquals("Wrong number of ALL.5", 2, wallet.getTransactions(true).size()); - assertEquals(valueOf(0, 49), wallet.getBalance(Wallet.BalanceType.ESTIMATED)); - } - - @Test - public void cleanupFailsDueToSpend() throws Exception { - Address destination = new ECKey().toAddress(params); - Transaction t = cleanupCommon(destination); - - // Now we have another incoming pending. Spend everything. - Coin v3 = valueOf(0, 58); - SendRequest req = SendRequest.to(destination, v3); - - // Force selection of the incoming coin so that we can spend it - req.coinSelector = new TestCoinSelector(); - - req.fee = CENT; - wallet.completeTx(req); - wallet.commitTx(req.tx); - - assertEquals("Wrong number of PENDING.5", 3, wallet.getPoolSize(WalletTransaction.Pool.PENDING)); - assertEquals("Wrong number of UNSPENT.5", 0, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT)); - assertEquals("Wrong number of ALL.5", 4, wallet.getTransactions(true).size()); - - // Consider the new pending as risky and try to remove it from the wallet - wallet.setRiskAnalyzer(new TestRiskAnalysis.Analyzer(t)); - - wallet.cleanup(); - assertTrue(wallet.isConsistent()); - - // The removal should have failed - assertEquals("Wrong number of PENDING.5", 3, wallet.getPoolSize(WalletTransaction.Pool.PENDING)); - assertEquals("Wrong number of UNSPENT.5", 0, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT)); - assertEquals("Wrong number of ALL.5", 4, wallet.getTransactions(true).size()); - assertEquals(ZERO, wallet.getBalance(Wallet.BalanceType.ESTIMATED)); - } - - private void basicSpendingCommon(Wallet wallet, Address toAddress, Address destination, Wallet encryptedWallet) throws Exception { - // We'll set up a wallet that receives a coin, then sends a coin of lesser value and keeps the change. We - // will attach a small fee. Because the Bitcoin protocol makes it difficult to determine the fee of an - // arbitrary transaction in isolation, we'll check that the fee was set by examining the size of the change. - - // Receive some money as a pending transaction. - receiveATransaction(wallet, toAddress); - - // Try to send too much and fail. - Coin vHuge = valueOf(10, 0); - Wallet.SendRequest req = Wallet.SendRequest.to(destination, vHuge); - try { - wallet.completeTx(req); - fail(); - } catch (InsufficientMoneyException e) { - assertEquals(valueOf(9, 0), e.missing); - } - - // Prepare to send. - Coin v2 = valueOf(0, 50); - req = Wallet.SendRequest.to(destination, v2); - req.fee = CENT; - - if (encryptedWallet != null) { - KeyCrypter keyCrypter = encryptedWallet.getKeyCrypter(); - KeyParameter aesKey = keyCrypter.deriveKey(PASSWORD1); - KeyParameter wrongAesKey = keyCrypter.deriveKey(WRONG_PASSWORD); - - // Try to create a send with a fee but no password (this should fail). - try { - req.ensureMinRequiredFee = false; - wallet.completeTx(req); - fail(); - } catch (ECKey.MissingPrivateKeyException kce) { - } - assertEquals("Wrong number of UNSPENT.1", 1, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT)); - assertEquals("Wrong number of ALL.1", 1, wallet.getTransactions(true).size()); - - // Try to create a send with a fee but the wrong password (this should fail). - req = Wallet.SendRequest.to(destination, v2); - req.aesKey = wrongAesKey; - req.fee = CENT; - req.ensureMinRequiredFee = false; - - try { - wallet.completeTx(req); - fail("No exception was thrown trying to sign an encrypted key with the wrong password supplied."); - } catch (KeyCrypterException kce) { - assertEquals("Could not decrypt bytes", kce.getMessage()); - } - - assertEquals("Wrong number of UNSPENT.2", 1, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT)); - assertEquals("Wrong number of ALL.2", 1, wallet.getTransactions(true).size()); - - // Create a send with a fee with the correct password (this should succeed). - req = Wallet.SendRequest.to(destination, v2); - req.aesKey = aesKey; - req.fee = CENT; - req.ensureMinRequiredFee = false; - } - - // Complete the transaction successfully. - req.shuffleOutputs = false; - wallet.completeTx(req); - - Transaction t2 = req.tx; - assertEquals("Wrong number of UNSPENT.3", 1, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT)); - assertEquals("Wrong number of ALL.3", 1, wallet.getTransactions(true).size()); - assertEquals(TransactionConfidence.Source.SELF, t2.getConfidence().getSource()); - assertEquals(Transaction.Purpose.USER_PAYMENT, t2.getPurpose()); - - // Do some basic sanity checks. - basicSanityChecks(wallet, t2, destination); - - // Broadcast the transaction and commit. - broadcastAndCommit(wallet, t2); - - // Now check that we can spend the unconfirmed change, with a new change address of our own selection. - // (req.aesKey is null for unencrypted / the correct aesKey for encrypted.) - spendUnconfirmedChange(wallet, t2, req.aesKey); - } - - private void receiveATransaction(Wallet wallet, Address toAddress) throws Exception { - receiveATransactionAmount(wallet, toAddress, COIN); - } - - private void receiveATransactionAmount(Wallet wallet, Address toAddress, Coin amount) { - final ListenableFuture availFuture = wallet.getBalanceFuture(amount, Wallet.BalanceType.AVAILABLE); - final ListenableFuture estimatedFuture = wallet.getBalanceFuture(amount, Wallet.BalanceType.ESTIMATED); - assertFalse(availFuture.isDone()); - assertFalse(estimatedFuture.isDone()); - // Send some pending coins to the wallet. - Transaction t1 = sendMoneyToWallet(wallet, amount, toAddress, null); - Threading.waitForUserCode(); - final ListenableFuture depthFuture = t1.getConfidence().getDepthFuture(1); - assertFalse(depthFuture.isDone()); - assertEquals(ZERO, wallet.getBalance()); - assertEquals(amount, wallet.getBalance(Wallet.BalanceType.ESTIMATED)); - assertFalse(availFuture.isDone()); - // Our estimated balance has reached the requested level. - assertTrue(estimatedFuture.isDone()); - assertEquals(1, wallet.getPoolSize(Pool.PENDING)); - assertEquals(0, wallet.getPoolSize(Pool.UNSPENT)); - // Confirm the coins. - sendMoneyToWallet(wallet, t1, AbstractBlockChain.NewBlockType.BEST_CHAIN); - assertEquals("Incorrect confirmed tx balance", amount, wallet.getBalance()); - assertEquals("Incorrect confirmed tx PENDING pool size", 0, wallet.getPoolSize(Pool.PENDING)); - assertEquals("Incorrect confirmed tx UNSPENT pool size", 1, wallet.getPoolSize(Pool.UNSPENT)); - assertEquals("Incorrect confirmed tx ALL pool size", 1, wallet.getTransactions(true).size()); - Threading.waitForUserCode(); - assertTrue(availFuture.isDone()); - assertTrue(estimatedFuture.isDone()); - assertTrue(depthFuture.isDone()); - } - - private void basicSanityChecks(Wallet wallet, Transaction t, Address destination) throws VerificationException { - assertEquals("Wrong number of tx inputs", 1, t.getInputs().size()); - assertEquals("Wrong number of tx outputs",2, t.getOutputs().size()); - assertEquals(destination, t.getOutput(0).getScriptPubKey().getToAddress(params)); - assertEquals(wallet.getChangeAddress(), t.getOutputs().get(1).getScriptPubKey().getToAddress(params)); - assertEquals(valueOf(0, 49), t.getOutputs().get(1).getValue()); - // Check the script runs and signatures verify. - t.getInputs().get(0).verify(); - } - - private static void broadcastAndCommit(Wallet wallet, Transaction t) throws Exception { - final LinkedList txns = Lists.newLinkedList(); - wallet.addEventListener(new AbstractWalletEventListener() { - @Override - public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) { - txns.add(tx); - } - }); - - t.getConfidence().markBroadcastBy(new PeerAddress(InetAddress.getByAddress(new byte[]{1,2,3,4}))); - t.getConfidence().markBroadcastBy(new PeerAddress(InetAddress.getByAddress(new byte[]{10,2,3,4}))); - wallet.commitTx(t); - Threading.waitForUserCode(); - assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.PENDING)); - assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.SPENT)); - assertEquals(2, wallet.getTransactions(true).size()); - assertEquals(t, txns.getFirst()); - assertEquals(1, txns.size()); - } - - private void spendUnconfirmedChange(Wallet wallet, Transaction t2, KeyParameter aesKey) throws Exception { - if (wallet.getTransactionSigners().size() == 1) // don't bother reconfiguring the p2sh wallet - wallet = roundTrip(wallet); - Coin v3 = valueOf(0, 49); - assertEquals(v3, wallet.getBalance()); - Wallet.SendRequest req = Wallet.SendRequest.to(new ECKey().toAddress(params), valueOf(0, 48)); - req.aesKey = aesKey; - req.ensureMinRequiredFee = false; - req.shuffleOutputs = false; - wallet.completeTx(req); - Transaction t3 = req.tx; - assertNotEquals(t2.getOutput(1).getScriptPubKey().getToAddress(params), - t3.getOutput(1).getScriptPubKey().getToAddress(params)); - assertNotNull(t3); - wallet.commitTx(t3); - assertTrue(wallet.isConsistent()); - // t2 and t3 gets confirmed in the same block. - BlockPair bp = createFakeBlock(blockStore, t2, t3); - wallet.receiveFromBlock(t2, bp.storedBlock, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); - wallet.receiveFromBlock(t3, bp.storedBlock, AbstractBlockChain.NewBlockType.BEST_CHAIN, 1); - wallet.notifyNewBestBlock(bp.storedBlock); - assertTrue(wallet.isConsistent()); - } - - @Test - @SuppressWarnings("deprecation") - // Having a test for deprecated method getFromAddress() is no evil so we suppress the warning here. - public void customTransactionSpending() throws Exception { - // We'll set up a wallet that receives a coin, then sends a coin of lesser value and keeps the change. - Coin v1 = valueOf(3, 0); - sendMoneyToWallet(v1, AbstractBlockChain.NewBlockType.BEST_CHAIN); - assertEquals(v1, wallet.getBalance()); - assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT)); - assertEquals(1, wallet.getTransactions(true).size()); - - ECKey k2 = new ECKey(); - Address a2 = k2.toAddress(params); - Coin v2 = valueOf(0, 50); - Coin v3 = valueOf(0, 75); - Coin v4 = valueOf(1, 25); - - Transaction t2 = new Transaction(params); - t2.addOutput(v2, a2); - t2.addOutput(v3, a2); - t2.addOutput(v4, a2); - SendRequest req = SendRequest.forTx(t2); - req.ensureMinRequiredFee = false; - wallet.completeTx(req); - - // Do some basic sanity checks. - assertEquals(1, t2.getInputs().size()); - assertEquals(myAddress, t2.getInput(0).getScriptSig().getFromAddress(params)); - assertEquals(TransactionConfidence.ConfidenceType.UNKNOWN, t2.getConfidence().getConfidenceType()); - - // We have NOT proven that the signature is correct! - wallet.commitTx(t2); - assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.PENDING)); - assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.SPENT)); - assertEquals(2, wallet.getTransactions(true).size()); - } - - @Test - public void sideChain() throws Exception { - // The wallet receives a coin on the main chain, then on a side chain. Balance is equal to both added together - // as we assume the side chain tx is pending and will be included shortly. - Coin v1 = COIN; - sendMoneyToWallet(v1, AbstractBlockChain.NewBlockType.BEST_CHAIN); - assertEquals(v1, wallet.getBalance()); - assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT)); - assertEquals(1, wallet.getTransactions(true).size()); - - Coin v2 = valueOf(0, 50); - sendMoneyToWallet(v2, AbstractBlockChain.NewBlockType.SIDE_CHAIN); - assertEquals(2, wallet.getTransactions(true).size()); - assertEquals(v1, wallet.getBalance()); - assertEquals(v1.add(v2), wallet.getBalance(Wallet.BalanceType.ESTIMATED)); - } - - @Test - public void balance() throws Exception { - // Receive 5 coins then half a coin. - Coin v1 = valueOf(5, 0); - Coin v2 = valueOf(0, 50); - Coin expected = valueOf(5, 50); - assertEquals(0, wallet.getTransactions(true).size()); - sendMoneyToWallet(v1, AbstractBlockChain.NewBlockType.BEST_CHAIN); - assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT)); - sendMoneyToWallet(v2, AbstractBlockChain.NewBlockType.BEST_CHAIN); - assertEquals(2, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT)); - assertEquals(expected, wallet.getBalance()); - - // Now spend one coin. - Coin v3 = COIN; - Transaction spend = wallet.createSend(new ECKey().toAddress(params), v3); - wallet.commitTx(spend); - assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.PENDING)); - - // Available and estimated balances should not be the same. We don't check the exact available balance here - // because it depends on the coin selection algorithm. - assertEquals(valueOf(4, 50), wallet.getBalance(Wallet.BalanceType.ESTIMATED)); - assertFalse(wallet.getBalance(Wallet.BalanceType.AVAILABLE).equals( - wallet.getBalance(Wallet.BalanceType.ESTIMATED))); - - // Now confirm the transaction by including it into a block. - StoredBlock b3 = createFakeBlock(blockStore, spend).storedBlock; - wallet.receiveFromBlock(spend, b3, BlockChain.NewBlockType.BEST_CHAIN, 0); - - // Change is confirmed. We started with 5.50 so we should have 4.50 left. - Coin v4 = valueOf(4, 50); - assertEquals(v4, wallet.getBalance(Wallet.BalanceType.AVAILABLE)); - } - - // Intuitively you'd expect to be able to create a transaction with identical inputs and outputs and get an - // identical result to the official client. However the signatures are not deterministic - signing the same data - // with the same key twice gives two different outputs. So we cannot prove bit-for-bit compatibility in this test - // suite. - - @Test - public void blockChainCatchup() throws Exception { - // Test that we correctly process transactions arriving from the chain, with callbacks for inbound and outbound. - final Coin bigints[] = new Coin[4]; - final Transaction txn[] = new Transaction[2]; - final LinkedList confTxns = new LinkedList(); - wallet.addEventListener(new AbstractWalletEventListener() { - @Override - public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) { - super.onCoinsReceived(wallet, tx, prevBalance, newBalance); - bigints[0] = prevBalance; - bigints[1] = newBalance; - txn[0] = tx; - } - - @Override - public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) { - super.onCoinsSent(wallet, tx, prevBalance, newBalance); - bigints[2] = prevBalance; - bigints[3] = newBalance; - txn[1] = tx; - } - - @Override - public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) { - super.onTransactionConfidenceChanged(wallet, tx); - confTxns.add(tx); - } - }); - - // Receive some money. - Coin oneCoin = COIN; - Transaction tx1 = sendMoneyToWallet(oneCoin, AbstractBlockChain.NewBlockType.BEST_CHAIN); - Threading.waitForUserCode(); - assertEquals(null, txn[1]); // onCoinsSent not called. - assertEquals(tx1, confTxns.getFirst()); // onTransactionConfidenceChanged called - assertEquals(txn[0].getHash(), tx1.getHash()); - assertEquals(ZERO, bigints[0]); - assertEquals(oneCoin, bigints[1]); - assertEquals(TransactionConfidence.ConfidenceType.BUILDING, tx1.getConfidence().getConfidenceType()); - assertEquals(1, tx1.getConfidence().getAppearedAtChainHeight()); - // Send 0.10 to somebody else. - Transaction send1 = wallet.createSend(new ECKey().toAddress(params), valueOf(0, 10)); - // Pretend it makes it into the block chain, our wallet state is cleared but we still have the keys, and we - // want to get back to our previous state. We can do this by just not confirming the transaction as - // createSend is stateless. - txn[0] = txn[1] = null; - confTxns.clear(); - sendMoneyToWallet(send1, AbstractBlockChain.NewBlockType.BEST_CHAIN); - Threading.waitForUserCode(); - assertEquals(Coin.valueOf(0, 90), wallet.getBalance()); - assertEquals(null, txn[0]); - assertEquals(2, confTxns.size()); - assertEquals(txn[1].getHash(), send1.getHash()); - assertEquals(Coin.COIN, bigints[2]); - assertEquals(Coin.valueOf(0, 90), bigints[3]); - // And we do it again after the catchup. - Transaction send2 = wallet.createSend(new ECKey().toAddress(params), valueOf(0, 10)); - // What we'd really like to do is prove the official client would accept it .... no such luck unfortunately. - wallet.commitTx(send2); - sendMoneyToWallet(send2, AbstractBlockChain.NewBlockType.BEST_CHAIN); - assertEquals(Coin.valueOf(0, 80), wallet.getBalance()); - Threading.waitForUserCode(); - BlockPair b4 = createFakeBlock(blockStore); - confTxns.clear(); - wallet.notifyNewBestBlock(b4.storedBlock); - Threading.waitForUserCode(); - assertEquals(3, confTxns.size()); - } - - @Test - public void balances() throws Exception { - Coin nanos = COIN; - Transaction tx1 = sendMoneyToWallet(nanos, AbstractBlockChain.NewBlockType.BEST_CHAIN); - assertEquals(nanos, tx1.getValueSentToMe(wallet, true)); - assertTrue(tx1.getWalletOutputs(wallet).size() >= 1); - // Send 0.10 to somebody else. - Transaction send1 = wallet.createSend(new ECKey().toAddress(params), valueOf(0, 10)); - // Reserialize. - Transaction send2 = new Transaction(params, send1.bitcoinSerialize()); - assertEquals(nanos, send2.getValueSentFromMe(wallet)); - assertEquals(ZERO.subtract(valueOf(0, 10)), send2.getValue(wallet)); - } - - @Test - public void isConsistent_duplicates() throws Exception { - // This test ensures that isConsistent catches duplicate transactions, eg, because we submitted the same block - // twice (this is not allowed). - Transaction tx = createFakeTx(params, COIN, myAddress); - Address someOtherGuy = new ECKey().toAddress(params); - TransactionOutput output = new TransactionOutput(params, tx, valueOf(0, 5), someOtherGuy); - tx.addOutput(output); - wallet.receiveFromBlock(tx, null, BlockChain.NewBlockType.BEST_CHAIN, 0); - - assertTrue("Wallet is not consistent", wallet.isConsistent()); - - Transaction txClone = new Transaction(params, tx.bitcoinSerialize()); - try { - wallet.receiveFromBlock(txClone, null, BlockChain.NewBlockType.BEST_CHAIN, 0); - fail("Illegal argument not thrown when it should have been."); - } catch (IllegalStateException ex) { - // expected - } - } - - @Test - public void isConsistent_pools() throws Exception { - // This test ensures that isConsistent catches transactions that are in incompatible pools. - Transaction tx = createFakeTx(params, COIN, myAddress); - Address someOtherGuy = new ECKey().toAddress(params); - TransactionOutput output = new TransactionOutput(params, tx, valueOf(0, 5), someOtherGuy); - tx.addOutput(output); - wallet.receiveFromBlock(tx, null, BlockChain.NewBlockType.BEST_CHAIN, 0); - - assertTrue(wallet.isConsistent()); - - wallet.addWalletTransaction(new WalletTransaction(Pool.PENDING, tx)); - assertFalse(wallet.isConsistent()); - } - - @Test - public void isConsistent_spent() throws Exception { - // This test ensures that isConsistent catches transactions that are marked spent when - // they aren't. - Transaction tx = createFakeTx(params, COIN, myAddress); - Address someOtherGuy = new ECKey().toAddress(params); - TransactionOutput output = new TransactionOutput(params, tx, valueOf(0, 5), someOtherGuy); - tx.addOutput(output); - assertTrue(wallet.isConsistent()); - - wallet.addWalletTransaction(new WalletTransaction(Pool.SPENT, tx)); - assertFalse(wallet.isConsistent()); - } - - @Test - public void transactions() throws Exception { - // This test covers a bug in which Transaction.getValueSentFromMe was calculating incorrectly. - Transaction tx = createFakeTx(params, COIN, myAddress); - // Now add another output (ie, change) that goes to some other address. - Address someOtherGuy = new ECKey().toAddress(params); - TransactionOutput output = new TransactionOutput(params, tx, valueOf(0, 5), someOtherGuy); - tx.addOutput(output); - // Note that tx is no longer valid: it spends more than it imports. However checking transactions balance - // correctly isn't possible in SPV mode because value is a property of outputs not inputs. Without all - // transactions you can't check they add up. - sendMoneyToWallet(tx, AbstractBlockChain.NewBlockType.BEST_CHAIN); - // Now the other guy creates a transaction which spends that change. - Transaction tx2 = new Transaction(params); - tx2.addInput(output); - tx2.addOutput(new TransactionOutput(params, tx2, valueOf(0, 5), myAddress)); - // tx2 doesn't send any coins from us, even though the output is in the wallet. - assertEquals(ZERO, tx2.getValueSentFromMe(wallet)); - } - - @Test - public void bounce() throws Exception { - // This test covers bug 64 (False double spends). Check that if we create a spend and it's immediately sent - // back to us, this isn't considered as a double spend. - Coin coin1 = COIN; - sendMoneyToWallet(coin1, AbstractBlockChain.NewBlockType.BEST_CHAIN); - // Send half to some other guy. Sending only half then waiting for a confirm is important to ensure the tx is - // in the unspent pool, not pending or spent. - Coin coinHalf = valueOf(0, 50); - assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT)); - assertEquals(1, wallet.getTransactions(true).size()); - Address someOtherGuy = new ECKey().toAddress(params); - Transaction outbound1 = wallet.createSend(someOtherGuy, coinHalf); - wallet.commitTx(outbound1); - sendMoneyToWallet(outbound1, AbstractBlockChain.NewBlockType.BEST_CHAIN); - assertTrue(outbound1.getWalletOutputs(wallet).size() <= 1); //the change address at most - // That other guy gives us the coins right back. - Transaction inbound2 = new Transaction(params); - inbound2.addOutput(new TransactionOutput(params, inbound2, coinHalf, myAddress)); - assertTrue(outbound1.getWalletOutputs(wallet).size() >= 1); - inbound2.addInput(outbound1.getOutputs().get(0)); - sendMoneyToWallet(inbound2, AbstractBlockChain.NewBlockType.BEST_CHAIN); - assertEquals(coin1, wallet.getBalance()); - } - - @Test - public void doubleSpendUnspendsOtherInputs() throws Exception { - // Test another Finney attack, but this time the killed transaction was also spending some other outputs in - // our wallet which were not themselves double spent. This test ensures the death of the pending transaction - // frees up the other outputs and makes them spendable again. - - // Receive 1 coin and then 2 coins in separate transactions. - sendMoneyToWallet(COIN, AbstractBlockChain.NewBlockType.BEST_CHAIN); - sendMoneyToWallet(valueOf(2, 0), AbstractBlockChain.NewBlockType.BEST_CHAIN); - // Create a send to a merchant of all our coins. - Transaction send1 = wallet.createSend(new ECKey().toAddress(params), valueOf(2, 90)); - // Create a double spend of just the first one. - Transaction send2 = wallet.createSend(new ECKey().toAddress(params), COIN); - send2 = new Transaction(params, send2.bitcoinSerialize()); - // Broadcast send1, it's now pending. - wallet.commitTx(send1); - assertEquals(ZERO, wallet.getBalance()); - // Receive a block that overrides the send1 using send2. - sendMoneyToWallet(send2, AbstractBlockChain.NewBlockType.BEST_CHAIN); - // send1 got rolled back and replaced with a smaller send that only used one of our received coins, thus ... - assertEquals(valueOf(2, 0), wallet.getBalance()); - assertTrue(wallet.isConsistent()); - } - - @Test - public void doubleSpends() throws Exception { - // Test the case where two semantically identical but bitwise different transactions double spend each other. - // We call the second transaction a "mutant" of the first. - // - // This can (and has!) happened when a wallet is cloned between devices, and both devices decide to make the - // same spend simultaneously - for example due a re-keying operation. It can also happen if there are malicious - // nodes in the P2P network that are mutating transactions on the fly as occurred during Feb 2014. - final Coin value = COIN; - final Coin value2 = valueOf(2, 0); - // Give us three coins and make sure we have some change. - sendMoneyToWallet(value.add(value2), AbstractBlockChain.NewBlockType.BEST_CHAIN); - final Address address = new ECKey().toAddress(params); - Transaction send1 = checkNotNull(wallet.createSend(address, value2)); - Transaction send2 = checkNotNull(wallet.createSend(address, value2)); - byte[] buf = send1.bitcoinSerialize(); - buf[43] = 0; // Break the signature: dogecoinj won't check in SPV mode and this is easier than other mutations. - send1 = new Transaction(params, buf); - wallet.commitTx(send2); - wallet.allowSpendingUnconfirmedTransactions(); - assertEquals(value, wallet.getBalance(Wallet.BalanceType.ESTIMATED)); - // Now spend the change. This transaction should die permanently when the mutant appears in the chain. - Transaction send3 = checkNotNull(wallet.createSend(address, value)); - wallet.commitTx(send3); - assertEquals(ZERO, wallet.getBalance()); - final LinkedList dead = new LinkedList(); - final TransactionConfidence.Listener listener = new TransactionConfidence.Listener() { - @Override - public void onConfidenceChanged(TransactionConfidence confidence, ChangeReason reason) { - final TransactionConfidence.ConfidenceType type = confidence.getConfidenceType(); - if (reason == ChangeReason.TYPE && type == TransactionConfidence.ConfidenceType.DEAD) - dead.add(confidence); - } - }; - send2.getConfidence().addEventListener(listener, Threading.SAME_THREAD); - send3.getConfidence().addEventListener(listener, Threading.SAME_THREAD); - // Double spend! - sendMoneyToWallet(send1, AbstractBlockChain.NewBlockType.BEST_CHAIN); - // Back to having one coin. - assertEquals(value, wallet.getBalance()); - assertEquals(send2.getHash(), dead.poll().getTransactionHash()); - assertEquals(send3.getHash(), dead.poll().getTransactionHash()); - } - - @Test - public void doubleSpendFinneyAttack() throws Exception { - // A Finney attack is where a miner includes a transaction spending coins to themselves but does not - // broadcast it. When they find a solved block, they hold it back temporarily whilst they buy something with - // those same coins. After purchasing, they broadcast the block thus reversing the transaction. It can be - // done by any miner for products that can be bought at a chosen time and very quickly (as every second you - // withold your block means somebody else might find it first, invalidating your work). - // - // Test that we handle the attack correctly: a double spend on the chain moves transactions from pending to dead. - // This needs to work both for transactions we create, and that we receive from others. - final Transaction[] eventDead = new Transaction[1]; - final Transaction[] eventReplacement = new Transaction[1]; - final int[] eventWalletChanged = new int[1]; - wallet.addEventListener(new AbstractWalletEventListener() { - @Override - public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) { - super.onTransactionConfidenceChanged(wallet, tx); - if (tx.getConfidence().getConfidenceType() == - TransactionConfidence.ConfidenceType.DEAD) { - eventDead[0] = tx; - eventReplacement[0] = tx.getConfidence().getOverridingTransaction(); - } - } - - @Override - public void onWalletChanged(Wallet wallet) { - eventWalletChanged[0]++; - } - }); - - // Receive 1 BTC. - Coin nanos = COIN; - sendMoneyToWallet(nanos, AbstractBlockChain.NewBlockType.BEST_CHAIN); - Transaction received = wallet.getTransactions(false).iterator().next(); - // Create a send to a merchant. - Transaction send1 = wallet.createSend(new ECKey().toAddress(params), valueOf(0, 50)); - // Create a double spend. - Transaction send2 = wallet.createSend(new ECKey().toAddress(params), valueOf(0, 50)); - send2 = new Transaction(params, send2.bitcoinSerialize()); - // Broadcast send1. - wallet.commitTx(send1); - assertEquals(send1, received.getOutput(0).getSpentBy().getParentTransaction()); - // Receive a block that overrides it. - sendMoneyToWallet(send2, AbstractBlockChain.NewBlockType.BEST_CHAIN); - Threading.waitForUserCode(); - assertEquals(send1, eventDead[0]); - assertEquals(send2, eventReplacement[0]); - assertEquals(TransactionConfidence.ConfidenceType.DEAD, - send1.getConfidence().getConfidenceType()); - assertEquals(send2, received.getOutput(0).getSpentBy().getParentTransaction()); - - FakeTxBuilder.DoubleSpends doubleSpends = FakeTxBuilder.createFakeDoubleSpendTxns(params, myAddress); - // t1 spends to our wallet. t2 double spends somewhere else. - wallet.receivePending(doubleSpends.t1, null); - assertEquals(TransactionConfidence.ConfidenceType.PENDING, - doubleSpends.t1.getConfidence().getConfidenceType()); - sendMoneyToWallet(doubleSpends.t2, AbstractBlockChain.NewBlockType.BEST_CHAIN); - Threading.waitForUserCode(); - assertEquals(TransactionConfidence.ConfidenceType.DEAD, - doubleSpends.t1.getConfidence().getConfidenceType()); - assertEquals(doubleSpends.t2, doubleSpends.t1.getConfidence().getOverridingTransaction()); - assertEquals(5, eventWalletChanged[0]); - } - - @Test - public void pending1() throws Exception { - // Check that if we receive a pending transaction that is then confirmed, we are notified as appropriate. - final Coin nanos = COIN; - final Transaction t1 = createFakeTx(params, nanos, myAddress); - - // First one is "called" second is "pending". - final boolean[] flags = new boolean[2]; - final Transaction[] notifiedTx = new Transaction[1]; - final int[] walletChanged = new int[1]; - wallet.addEventListener(new AbstractWalletEventListener() { - @Override - public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) { - // Check we got the expected transaction. - assertEquals(tx, t1); - // Check that it's considered to be pending inclusion in the block chain. - assertEquals(prevBalance, ZERO); - assertEquals(newBalance, nanos); - flags[0] = true; - flags[1] = tx.isPending(); - notifiedTx[0] = tx; - } - - @Override - public void onWalletChanged(Wallet wallet) { - walletChanged[0]++; - } - }); - - if (wallet.isPendingTransactionRelevant(t1)) - wallet.receivePending(t1, null); - Threading.waitForUserCode(); - assertTrue(flags[0]); - assertTrue(flags[1]); // is pending - flags[0] = false; - // Check we don't get notified if we receive it again. - assertFalse(wallet.isPendingTransactionRelevant(t1)); - assertFalse(flags[0]); - // Now check again, that we should NOT be notified when we receive it via a block (we were already notified). - // However the confidence should be updated. - // Make a fresh copy of the tx to ensure we're testing realistically. - flags[0] = flags[1] = false; - final TransactionConfidence.Listener.ChangeReason[] reasons = new TransactionConfidence.Listener.ChangeReason[1]; - notifiedTx[0].getConfidence().addEventListener(new TransactionConfidence.Listener() { - @Override - public void onConfidenceChanged(TransactionConfidence confidence, TransactionConfidence.Listener.ChangeReason reason) { - flags[1] = true; - reasons[0] = reason; - } - }); - assertEquals(TransactionConfidence.ConfidenceType.PENDING, - notifiedTx[0].getConfidence().getConfidenceType()); - // Send a block with nothing interesting. Verify we don't get a callback. - wallet.notifyNewBestBlock(createFakeBlock(blockStore).storedBlock); - Threading.waitForUserCode(); - assertNull(reasons[0]); - final Transaction t1Copy = new Transaction(params, t1.bitcoinSerialize()); - sendMoneyToWallet(t1Copy, AbstractBlockChain.NewBlockType.BEST_CHAIN); - Threading.waitForUserCode(); - assertFalse(flags[0]); - assertTrue(flags[1]); - assertEquals(TransactionConfidence.ConfidenceType.BUILDING, notifiedTx[0].getConfidence().getConfidenceType()); - // Check we don't get notified about an irrelevant transaction. - flags[0] = false; - flags[1] = false; - Transaction irrelevant = createFakeTx(params, nanos, new ECKey().toAddress(params)); - if (wallet.isPendingTransactionRelevant(irrelevant)) - wallet.receivePending(irrelevant, null); - Threading.waitForUserCode(); - assertFalse(flags[0]); - assertEquals(3, walletChanged[0]); - } - - @Test - public void pending2() throws Exception { - // Check that if we receive a pending tx we did not send, it updates our spent flags correctly. - final Transaction txn[] = new Transaction[1]; - final Coin bigints[] = new Coin[2]; - wallet.addEventListener(new AbstractWalletEventListener() { - @Override - public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) { - txn[0] = tx; - bigints[0] = prevBalance; - bigints[1] = newBalance; - } - }); - // Receive some coins. - Coin nanos = COIN; - sendMoneyToWallet(nanos, AbstractBlockChain.NewBlockType.BEST_CHAIN); - // Create a spend with them, but don't commit it (ie it's from somewhere else but using our keys). This TX - // will have change as we don't spend our entire balance. - Coin halfNanos = valueOf(0, 50); - Transaction t2 = wallet.createSend(new ECKey().toAddress(params), halfNanos); - // Now receive it as pending. - if (wallet.isPendingTransactionRelevant(t2)) - wallet.receivePending(t2, null); - // We received an onCoinsSent() callback. - Threading.waitForUserCode(); - assertEquals(t2, txn[0]); - assertEquals(nanos, bigints[0]); - assertEquals(halfNanos, bigints[1]); - // Our balance is now 0.50 BTC - assertEquals(halfNanos, wallet.getBalance(Wallet.BalanceType.ESTIMATED)); - } - - @Test - public void pending3() throws Exception { - // Check that if we receive a pending tx, and it's overridden by a double spend from the main chain, we - // are notified that it's dead. This should work even if the pending tx inputs are NOT ours, ie, they don't - // connect to anything. - Coin nanos = COIN; - - // Create two transactions that share the same input tx. - Address badGuy = new ECKey().toAddress(params); - Transaction doubleSpentTx = new Transaction(params); - TransactionOutput doubleSpentOut = new TransactionOutput(params, doubleSpentTx, nanos, badGuy); - doubleSpentTx.addOutput(doubleSpentOut); - Transaction t1 = new Transaction(params); - TransactionOutput o1 = new TransactionOutput(params, t1, nanos, myAddress); - t1.addOutput(o1); - t1.addInput(doubleSpentOut); - Transaction t2 = new Transaction(params); - TransactionOutput o2 = new TransactionOutput(params, t2, nanos, badGuy); - t2.addOutput(o2); - t2.addInput(doubleSpentOut); - - final Transaction[] called = new Transaction[2]; - wallet.addEventListener(new AbstractWalletEventListener() { - @Override - public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) { - called[0] = tx; - } - - @Override - public void onTransactionConfidenceChanged(Wallet wallet, Transaction tx) { - super.onTransactionConfidenceChanged(wallet, tx); - if (tx.getConfidence().getConfidenceType() == - TransactionConfidence.ConfidenceType.DEAD) { - called[0] = tx; - called[1] = tx.getConfidence().getOverridingTransaction(); - } - } - }); - - assertEquals(ZERO, wallet.getBalance()); - if (wallet.isPendingTransactionRelevant(t1)) - wallet.receivePending(t1, null); - Threading.waitForUserCode(); - assertEquals(t1, called[0]); - assertEquals(nanos, wallet.getBalance(Wallet.BalanceType.ESTIMATED)); - // Now receive a double spend on the main chain. - called[0] = called[1] = null; - sendMoneyToWallet(t2, AbstractBlockChain.NewBlockType.BEST_CHAIN); - Threading.waitForUserCode(); - assertEquals(ZERO, wallet.getBalance()); - assertEquals(t1, called[0]); // dead - assertEquals(t2, called[1]); // replacement - } - - @Test - public void transactionsList() throws Exception { - // Check the wallet can give us an ordered list of all received transactions. - Utils.setMockClock(); - Transaction tx1 = sendMoneyToWallet(COIN, AbstractBlockChain.NewBlockType.BEST_CHAIN); - Utils.rollMockClock(60 * 10); - Transaction tx2 = sendMoneyToWallet(valueOf(0, 5), AbstractBlockChain.NewBlockType.BEST_CHAIN); - // Check we got them back in order. - List transactions = wallet.getTransactionsByTime(); - assertEquals(tx2, transactions.get(0)); - assertEquals(tx1, transactions.get(1)); - assertEquals(2, transactions.size()); - // Check we get only the last transaction if we request a subrage. - transactions = wallet.getRecentTransactions(1, false); - assertEquals(1, transactions.size()); - assertEquals(tx2, transactions.get(0)); - - // Create a spend five minutes later. - Utils.rollMockClock(60 * 5); - Transaction tx3 = wallet.createSend(new ECKey().toAddress(params), valueOf(0, 5)); - // Does not appear in list yet. - assertEquals(2, wallet.getTransactionsByTime().size()); - wallet.commitTx(tx3); - // Now it does. - transactions = wallet.getTransactionsByTime(); - assertEquals(3, transactions.size()); - assertEquals(tx3, transactions.get(0)); - - // Verify we can handle the case of older wallets in which the timestamp is null (guessed from the - // block appearances list). - tx1.setUpdateTime(null); - tx3.setUpdateTime(null); - // Check we got them back in order. - transactions = wallet.getTransactionsByTime(); - assertEquals(tx2, transactions.get(0)); - assertEquals(3, transactions.size()); - } - - @Test - public void keyCreationTime() throws Exception { - Utils.setMockClock(); - long now = Utils.currentTimeSeconds(); - wallet = new Wallet(params); - assertEquals(now, wallet.getEarliestKeyCreationTime()); - Utils.rollMockClock(60); - wallet.freshReceiveKey(); - assertEquals(now, wallet.getEarliestKeyCreationTime()); - } - - @Test - public void scriptCreationTime() throws Exception { - Utils.setMockClock(); - long now = Utils.currentTimeSeconds(); - wallet = new Wallet(params); - assertEquals(now, wallet.getEarliestKeyCreationTime()); - Utils.rollMockClock(-120); - wallet.addWatchedAddress(new ECKey().toAddress(params)); - wallet.freshReceiveKey(); - assertEquals(now - 120, wallet.getEarliestKeyCreationTime()); - } - - @Test - public void spendToSameWallet() throws Exception { - // Test that a spend to the same wallet is dealt with correctly. - // It should appear in the wallet and confirm. - // This is a bit of a silly thing to do in the real world as all it does is burn a fee but it is perfectly valid. - Coin coin1 = COIN; - Coin coinHalf = valueOf(0, 50); - // Start by giving us 1 coin. - sendMoneyToWallet(coin1, AbstractBlockChain.NewBlockType.BEST_CHAIN); - // Send half to ourselves. We should then have a balance available to spend of zero. - assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT)); - assertEquals(1, wallet.getTransactions(true).size()); - Transaction outbound1 = wallet.createSend(myAddress, coinHalf); - wallet.commitTx(outbound1); - // We should have a zero available balance before the next block. - assertEquals(ZERO, wallet.getBalance()); - sendMoneyToWallet(outbound1, AbstractBlockChain.NewBlockType.BEST_CHAIN); - // We should have a balance of 1 BTC after the block is received. - assertEquals(coin1, wallet.getBalance()); - } - - @Test - public void lastBlockSeen() throws Exception { - Coin v1 = valueOf(5, 0); - Coin v2 = valueOf(0, 50); - Coin v3 = valueOf(0, 25); - Transaction t1 = createFakeTx(params, v1, myAddress); - Transaction t2 = createFakeTx(params, v2, myAddress); - Transaction t3 = createFakeTx(params, v3, myAddress); - - Block genesis = blockStore.getChainHead().getHeader(); - Block b10 = makeSolvedTestBlock(genesis, t1); - Block b11 = makeSolvedTestBlock(genesis, t2); - Block b2 = makeSolvedTestBlock(b10, t3); - Block b3 = makeSolvedTestBlock(b2); - - // Receive a block on the best chain - this should set the last block seen hash. - chain.add(b10); - assertEquals(b10.getHash(), wallet.getLastBlockSeenHash()); - assertEquals(b10.getTimeSeconds(), wallet.getLastBlockSeenTimeSecs()); - assertEquals(1, wallet.getLastBlockSeenHeight()); - // Receive a block on the side chain - this should not change the last block seen hash. - chain.add(b11); - assertEquals(b10.getHash(), wallet.getLastBlockSeenHash()); - // Receive block 2 on the best chain - this should change the last block seen hash. - chain.add(b2); - assertEquals(b2.getHash(), wallet.getLastBlockSeenHash()); - // Receive block 3 on the best chain - this should change the last block seen hash despite having no txns. - chain.add(b3); - assertEquals(b3.getHash(), wallet.getLastBlockSeenHash()); - } - - @Test - public void pubkeyOnlyScripts() throws Exception { - // Verify that we support outputs like OP_PUBKEY and the corresponding inputs. - ECKey key1 = wallet.freshReceiveKey(); - Coin value = valueOf(5, 0); - Transaction t1 = createFakeTx(params, value, key1); - if (wallet.isPendingTransactionRelevant(t1)) - wallet.receivePending(t1, null); - // TX should have been seen as relevant. - assertEquals(value, wallet.getBalance(Wallet.BalanceType.ESTIMATED)); - assertEquals(ZERO, wallet.getBalance(Wallet.BalanceType.AVAILABLE)); - Block b1 = createFakeBlock(blockStore, t1).block; - chain.add(b1); - // TX should have been seen as relevant, extracted and processed. - assertEquals(value, wallet.getBalance(Wallet.BalanceType.AVAILABLE)); - // Spend it and ensure we can spend the OP_CHECKSIG output correctly. - Transaction t2 = wallet.createSend(new ECKey().toAddress(params), value); - assertNotNull(t2); - // TODO: This code is messy, improve the Script class and fixinate! - assertEquals(t2.toString(), 1, t2.getInputs().get(0).getScriptSig().getChunks().size()); - assertTrue(t2.getInputs().get(0).getScriptSig().getChunks().get(0).data.length > 50); - log.info(t2.toString(chain)); - } - - @Test(expected = ECKey.MissingPrivateKeyException.class) - public void watchingWallet() throws Exception { - DeterministicKey watchKey = wallet.getWatchingKey(); - String serialized = watchKey.serializePubB58(params); - watchKey = DeterministicKey.deserializeB58(null, serialized, params); - Wallet watchingWallet = Wallet.fromWatchingKey(params, watchKey); - DeterministicKey key2 = watchingWallet.freshReceiveKey(); - assertEquals(myKey, key2); - - ECKey key = wallet.freshKey(KeyChain.KeyPurpose.CHANGE); - key2 = watchingWallet.freshKey(KeyChain.KeyPurpose.CHANGE); - assertEquals(key, key2); - key.sign(Sha256Hash.ZERO_HASH); - key2.sign(Sha256Hash.ZERO_HASH); - } - - @Test(expected = ECKey.MissingPrivateKeyException.class) - public void watchingWalletWithCreationTime() throws Exception { - DeterministicKey watchKey = wallet.getWatchingKey(); - String serialized = watchKey.serializePubB58(params); - watchKey = DeterministicKey.deserializeB58(null, serialized, params); - Wallet watchingWallet = Wallet.fromWatchingKey(params, watchKey, 1415282801); - DeterministicKey key2 = watchingWallet.freshReceiveKey(); - assertEquals(myKey, key2); - - ECKey key = wallet.freshKey(KeyChain.KeyPurpose.CHANGE); - key2 = watchingWallet.freshKey(KeyChain.KeyPurpose.CHANGE); - assertEquals(key, key2); - key.sign(Sha256Hash.ZERO_HASH); - key2.sign(Sha256Hash.ZERO_HASH); - } - - @Test - public void watchingScripts() throws Exception { - // Verify that pending transactions to watched addresses are relevant - ECKey key = new ECKey(); - Address watchedAddress = key.toAddress(params); - wallet.addWatchedAddress(watchedAddress); - Coin value = valueOf(5, 0); - Transaction t1 = createFakeTx(params, value, watchedAddress); - assertTrue(t1.getWalletOutputs(wallet).size() >= 1); - assertTrue(wallet.isPendingTransactionRelevant(t1)); - } - - @Test(expected = InsufficientMoneyException.class) - public void watchingScriptsConfirmed() throws Exception { - ECKey key = new ECKey(); - Address watchedAddress = key.toAddress(params); - wallet.addWatchedAddress(watchedAddress); - Transaction t1 = createFakeTx(params, CENT, watchedAddress); - StoredBlock b3 = createFakeBlock(blockStore, t1).storedBlock; - wallet.receiveFromBlock(t1, b3, BlockChain.NewBlockType.BEST_CHAIN, 0); - assertEquals(ZERO, wallet.getBalance()); - assertEquals(CENT, wallet.getWatchedBalance()); - - // We can't spend watched balances - Address notMyAddr = new ECKey().toAddress(params); - wallet.createSend(notMyAddr, CENT); - } - - @Test - public void watchingScriptsSentFrom() throws Exception { - int baseElements = wallet.getBloomFilterElementCount(); - - ECKey key = new ECKey(); - ECKey notMyAddr = new ECKey(); - Address watchedAddress = key.toAddress(params); - wallet.addWatchedAddress(watchedAddress); - assertEquals(baseElements + 1, wallet.getBloomFilterElementCount()); - - Transaction t1 = createFakeTx(params, CENT, watchedAddress); - Transaction t2 = createFakeTx(params, COIN, notMyAddr); - StoredBlock b1 = createFakeBlock(blockStore, t1).storedBlock; - Transaction st2 = new Transaction(params); - st2.addOutput(CENT, notMyAddr); - st2.addOutput(COIN, notMyAddr); - st2.addInput(t1.getOutput(0)); - st2.addInput(t2.getOutput(0)); - wallet.receiveFromBlock(t1, b1, BlockChain.NewBlockType.BEST_CHAIN, 0); - assertEquals(baseElements + 2, wallet.getBloomFilterElementCount()); - wallet.receiveFromBlock(st2, b1, BlockChain.NewBlockType.BEST_CHAIN, 0); - assertEquals(baseElements + 2, wallet.getBloomFilterElementCount()); - assertEquals(CENT, st2.getValueSentFromMe(wallet)); - } - - @Test - public void watchingScriptsBloomFilter() throws Exception { - assertFalse(wallet.isRequiringUpdateAllBloomFilter()); - - ECKey key = new ECKey(); - Address watchedAddress = key.toAddress(params); - wallet.addWatchedAddress(watchedAddress); - - assertTrue(wallet.isRequiringUpdateAllBloomFilter()); - Transaction t1 = createFakeTx(params, CENT, watchedAddress); - StoredBlock b1 = createFakeBlock(blockStore, t1).storedBlock; - - TransactionOutPoint outPoint = new TransactionOutPoint(params, 0, t1); - - // Note that this has a 1e-12 chance of failing this unit test due to a false positive - assertFalse(wallet.getBloomFilter(1e-12).contains(outPoint.bitcoinSerialize())); - - wallet.receiveFromBlock(t1, b1, BlockChain.NewBlockType.BEST_CHAIN, 0); - assertTrue(wallet.getBloomFilter(1e-12).contains(outPoint.bitcoinSerialize())); - } - - @Test - public void getWatchedAddresses() throws Exception { - Address watchedAddress = new ECKey().toAddress(params); - wallet.addWatchedAddress(watchedAddress); - List

watchedAddresses = wallet.getWatchedAddresses(); - assertEquals(1, watchedAddresses.size()); - assertEquals(watchedAddress, watchedAddresses.get(0)); - } - - @Test - public void removeWatchedAddresses() { - List
addressesForRemoval = new ArrayList
(); - for (int i = 0; i < 10; i++) { - ECKey key = new ECKey(); - Address watchedAddress = key.toAddress(params); - addressesForRemoval.add(watchedAddress); - wallet.addWatchedAddress(watchedAddress); - } - - wallet.removeWatchedAddresses(addressesForRemoval); - for (Address addr : addressesForRemoval) - assertFalse(wallet.isAddressWatched(addr)); - - assertFalse(wallet.isRequiringUpdateAllBloomFilter()); - } - - @Test - public void removeWatchedAddress() { - Address watchedAddress = new ECKey().toAddress(params); - wallet.addWatchedAddress(watchedAddress); - wallet.removeWatchedAddress(watchedAddress); - assertFalse(wallet.isAddressWatched(watchedAddress)); - assertFalse(wallet.isRequiringUpdateAllBloomFilter()); - } - - @Test - public void removeScriptsBloomFilter() throws Exception { - List
addressesForRemoval = new ArrayList
(); - for (int i = 0; i < 10; i++) { - ECKey key = new ECKey(); - Address watchedAddress = key.toAddress(params); - addressesForRemoval.add(watchedAddress); - wallet.addWatchedAddress(watchedAddress); - } - - wallet.removeWatchedAddresses(addressesForRemoval); - - for (Address addr : addressesForRemoval) { - Transaction t1 = createFakeTx(params, CENT, addr); - StoredBlock b1 = createFakeBlock(blockStore, t1).storedBlock; - - TransactionOutPoint outPoint = new TransactionOutPoint(params, 0, t1); - - // Note that this has a 1e-12 chance of failing this unit test due to a false positive - assertFalse(wallet.getBloomFilter(1e-12).contains(outPoint.bitcoinSerialize())); - - wallet.receiveFromBlock(t1, b1, BlockChain.NewBlockType.BEST_CHAIN, 0); - assertFalse(wallet.getBloomFilter(1e-12).contains(outPoint.bitcoinSerialize())); - } - } - - @Test - public void marriedKeychainBloomFilter() throws Exception { - createMarriedWallet(2, 2); - Address address = wallet.currentReceiveAddress(); - - assertTrue(wallet.getBloomFilter(0.001).contains(address.getHash160())); - - Transaction t1 = createFakeTx(params, CENT, address); - StoredBlock b1 = createFakeBlock(blockStore, t1).storedBlock; - - TransactionOutPoint outPoint = new TransactionOutPoint(params, 0, t1); - - assertFalse(wallet.getBloomFilter(0.001).contains(outPoint.bitcoinSerialize())); - - wallet.receiveFromBlock(t1, b1, BlockChain.NewBlockType.BEST_CHAIN, 0); - assertTrue(wallet.getBloomFilter(0.001).contains(outPoint.bitcoinSerialize())); - } - - @Test - public void autosaveImmediate() throws Exception { - // Test that the wallet will save itself automatically when it changes. - File f = File.createTempFile("dogecoinj-unit-test", null); - Sha256Hash hash1 = Sha256Hash.hashFileContents(f); - // Start with zero delay and ensure the wallet file changes after adding a key. - wallet.autosaveToFile(f, 0, TimeUnit.SECONDS, null); - ECKey key = wallet.freshReceiveKey(); - Sha256Hash hash2 = Sha256Hash.hashFileContents(f); - assertFalse("Wallet not saved after generating fresh key", hash1.equals(hash2)); // File has changed. - - Transaction t1 = createFakeTx(params, valueOf(5, 0), key); - if (wallet.isPendingTransactionRelevant(t1)) - wallet.receivePending(t1, null); - Sha256Hash hash3 = Sha256Hash.hashFileContents(f); - assertFalse("Wallet not saved after receivePending", hash2.equals(hash3)); // File has changed again. - } - - @Test - public void autosaveDelayed() throws Exception { - // Test that the wallet will save itself automatically when it changes, but not immediately and near-by - // updates are coalesced together. This test is a bit racy, it assumes we can complete the unit test within - // an auto-save cycle of 1 second. - final File[] results = new File[2]; - final CountDownLatch latch = new CountDownLatch(3); - File f = File.createTempFile("dogecoinj-unit-test", null); - Sha256Hash hash1 = Sha256Hash.hashFileContents(f); - wallet.autosaveToFile(f, 1, TimeUnit.SECONDS, - new WalletFiles.Listener() { - @Override - public void onBeforeAutoSave(File tempFile) { - results[0] = tempFile; - } - - @Override - public void onAfterAutoSave(File newlySavedFile) { - results[1] = newlySavedFile; - latch.countDown(); - } - } - ); - ECKey key = wallet.freshReceiveKey(); - Sha256Hash hash2 = Sha256Hash.hashFileContents(f); - assertFalse(hash1.equals(hash2)); // File has changed immediately despite the delay, as keys are important. - assertNotNull(results[0]); - assertEquals(f, results[1]); - results[0] = results[1] = null; - - Block b0 = createFakeBlock(blockStore).block; - chain.add(b0); - Sha256Hash hash3 = Sha256Hash.hashFileContents(f); - assertEquals(hash2, hash3); // File has NOT changed yet. Just new blocks with no txns - delayed. - assertNull(results[0]); - assertNull(results[1]); - - Transaction t1 = createFakeTx(params, valueOf(5, 0), key); - Block b1 = createFakeBlock(blockStore, t1).block; - chain.add(b1); - Sha256Hash hash4 = Sha256Hash.hashFileContents(f); - assertFalse(hash3.equals(hash4)); // File HAS changed. - results[0] = results[1] = null; - - // A block that contains some random tx we don't care about. - Block b2 = b1.createNextBlock(new ECKey().toAddress(params)); - chain.add(b2); - assertEquals(hash4, Sha256Hash.hashFileContents(f)); // File has NOT changed. - assertNull(results[0]); - assertNull(results[1]); - - // Wait for an auto-save to occur. - latch.await(); - Sha256Hash hash5 = Sha256Hash.hashFileContents(f); - assertFalse(hash4.equals(hash5)); // File has now changed. - assertNotNull(results[0]); - assertEquals(f, results[1]); - - // Now we shutdown auto-saving and expect wallet changes to remain unsaved, even "important" changes. - wallet.shutdownAutosaveAndWait(); - results[0] = results[1] = null; - ECKey key2 = new ECKey(); - wallet.importKey(key2); - assertEquals(hash5, Sha256Hash.hashFileContents(f)); // File has NOT changed. - Transaction t2 = createFakeTx(params, valueOf(5, 0), key2); - Block b3 = createFakeBlock(blockStore, t2).block; - chain.add(b3); - Thread.sleep(2000); // Wait longer than autosave delay. TODO Fix the racyness. - assertEquals(hash5, Sha256Hash.hashFileContents(f)); // File has still NOT changed. - assertNull(results[0]); - assertNull(results[1]); - } - - @Test - public void spendOutputFromPendingTransaction() throws Exception { - // We'll set up a wallet that receives a coin, then sends a coin of lesser value and keeps the change. - Coin v1 = COIN; - sendMoneyToWallet(v1, AbstractBlockChain.NewBlockType.BEST_CHAIN); - // First create our current transaction - ECKey k2 = wallet.freshReceiveKey(); - Coin v2 = valueOf(0, 50); - Transaction t2 = new Transaction(params); - TransactionOutput o2 = new TransactionOutput(params, t2, v2, k2.toAddress(params)); - t2.addOutput(o2); - SendRequest req = SendRequest.forTx(t2); - req.ensureMinRequiredFee = false; - wallet.completeTx(req); - - // Commit t2, so it is placed in the pending pool - wallet.commitTx(t2); - assertEquals(0, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT)); - assertEquals(1, wallet.getPoolSize(WalletTransaction.Pool.PENDING)); - assertEquals(2, wallet.getTransactions(true).size()); - - // Now try to the spend the output. - ECKey k3 = new ECKey(); - Coin v3 = valueOf(0, 25); - Transaction t3 = new Transaction(params); - t3.addOutput(v3, k3.toAddress(params)); - t3.addInput(o2); - wallet.signTransaction(SendRequest.forTx(t3)); - - // Commit t3, so the coins from the pending t2 are spent - wallet.commitTx(t3); - assertEquals(0, wallet.getPoolSize(WalletTransaction.Pool.UNSPENT)); - assertEquals(2, wallet.getPoolSize(WalletTransaction.Pool.PENDING)); - assertEquals(3, wallet.getTransactions(true).size()); - - // Now the output of t2 must not be available for spending - assertFalse(o2.isAvailableForSpending()); - } - - @Test - public void replayWhilstPending() throws Exception { - // Check that if a pending transaction spends outputs of chain-included transactions, we mark them as spent. - // See bug 345. This can happen if there is a pending transaction floating around and then you replay the - // chain without emptying the memory pool (or refilling it from a peer). - Coin value = COIN; - Transaction tx1 = createFakeTx(params, value, myAddress); - Transaction tx2 = new Transaction(params); - tx2.addInput(tx1.getOutput(0)); - tx2.addOutput(valueOf(0, 9), someOtherAddress); - // Add a change address to ensure this tx is relevant. - tx2.addOutput(CENT, wallet.getChangeAddress()); - wallet.receivePending(tx2, null); - BlockPair bp = createFakeBlock(blockStore, tx1); - wallet.receiveFromBlock(tx1, bp.storedBlock, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); - wallet.notifyNewBestBlock(bp.storedBlock); - assertEquals(ZERO, wallet.getBalance()); - assertEquals(1, wallet.getPoolSize(Pool.SPENT)); - assertEquals(1, wallet.getPoolSize(Pool.PENDING)); - assertEquals(0, wallet.getPoolSize(Pool.UNSPENT)); - } - - @Test - public void outOfOrderPendingTxns() throws Exception { - // Check that if there are two pending transactions which we receive out of order, they are marked as spent - // correctly. For instance, we are watching a wallet, someone pays us (A) and we then pay someone else (B) - // with a change address but the network delivers the transactions to us in order B then A. - Coin value = COIN; - Transaction a = createFakeTx(params, value, myAddress); - Transaction b = new Transaction(params); - b.addInput(a.getOutput(0)); - b.addOutput(CENT, someOtherAddress); - Coin v = COIN.subtract(CENT); - b.addOutput(v, wallet.getChangeAddress()); - a = roundTripTransaction(params, a); - b = roundTripTransaction(params, b); - wallet.receivePending(b, null); - assertEquals(v, wallet.getBalance(Wallet.BalanceType.ESTIMATED)); - wallet.receivePending(a, null); - assertEquals(v, wallet.getBalance(Wallet.BalanceType.ESTIMATED)); - } - - @Test - public void encryptionDecryptionAESBasic() throws Exception { - Wallet encryptedWallet = new Wallet(params); - encryptedWallet.encrypt(PASSWORD1); - KeyCrypter keyCrypter = encryptedWallet.getKeyCrypter(); - KeyParameter aesKey = keyCrypter.deriveKey(PASSWORD1); - - assertEquals(EncryptionType.ENCRYPTED_SCRYPT_AES, encryptedWallet.getEncryptionType()); - assertTrue(encryptedWallet.checkPassword(PASSWORD1)); - assertTrue(encryptedWallet.checkAESKey(aesKey)); - assertFalse(encryptedWallet.checkPassword(WRONG_PASSWORD)); - assertTrue("The keyCrypter is missing but should not be", keyCrypter != null); - encryptedWallet.decrypt(aesKey); - - // Wallet should now be unencrypted. - assertTrue("Wallet is not an unencrypted wallet", encryptedWallet.getKeyCrypter() == null); - try { - encryptedWallet.checkPassword(PASSWORD1); - fail(); - } catch (IllegalStateException e) { - } - } - - @Test - public void encryptionDecryptionPasswordBasic() throws Exception { - Wallet encryptedWallet = new Wallet(params); - encryptedWallet.encrypt(PASSWORD1); - - assertTrue(encryptedWallet.isEncrypted()); - encryptedWallet.decrypt(PASSWORD1); - assertFalse(encryptedWallet.isEncrypted()); - - // Wallet should now be unencrypted. - assertTrue("Wallet is not an unencrypted wallet", encryptedWallet.getKeyCrypter() == null); - try { - encryptedWallet.checkPassword(PASSWORD1); - fail(); - } catch (IllegalStateException e) { - } - } - - @Test - public void encryptionDecryptionBadPassword() throws Exception { - Wallet encryptedWallet = new Wallet(params); - encryptedWallet.encrypt(PASSWORD1); - KeyCrypter keyCrypter = encryptedWallet.getKeyCrypter(); - KeyParameter wrongAesKey = keyCrypter.deriveKey(WRONG_PASSWORD); - - // Check the wallet is currently encrypted - assertTrue("Wallet is not an encrypted wallet", encryptedWallet.getEncryptionType() == EncryptionType.ENCRYPTED_SCRYPT_AES); - assertFalse(encryptedWallet.checkAESKey(wrongAesKey)); - - // Check that the wrong password does not decrypt the wallet. - try { - encryptedWallet.decrypt(wrongAesKey); - fail("Incorrectly decoded wallet with wrong password"); - } catch (KeyCrypterException ede) { - // Expected. - } - } - - @Test - public void changePasswordTest() { - Wallet encryptedWallet = new Wallet(params); - encryptedWallet.encrypt(PASSWORD1); - CharSequence newPassword = "My name is Tom"; - encryptedWallet.changeEncryptionPassword(PASSWORD1, newPassword); - assertTrue(encryptedWallet.checkPassword(newPassword)); - assertFalse(encryptedWallet.checkPassword(WRONG_PASSWORD)); - } - - @Test - public void changeAesKeyTest() { - Wallet encryptedWallet = new Wallet(params); - encryptedWallet.encrypt(PASSWORD1); - - KeyCrypter keyCrypter = encryptedWallet.getKeyCrypter(); - KeyParameter aesKey = keyCrypter.deriveKey(PASSWORD1); - - CharSequence newPassword = "My name is Tom"; - KeyParameter newAesKey = keyCrypter.deriveKey(newPassword); - - encryptedWallet.changeEncryptionKey(keyCrypter, aesKey, newAesKey); - - assertTrue(encryptedWallet.checkAESKey(newAesKey)); - assertFalse(encryptedWallet.checkAESKey(aesKey)); - } - - @Test - public void encryptionDecryptionCheckExceptions() throws Exception { - Wallet encryptedWallet = new Wallet(params); - encryptedWallet.encrypt(PASSWORD1); - KeyCrypter keyCrypter = encryptedWallet.getKeyCrypter(); - KeyParameter aesKey = keyCrypter.deriveKey(PASSWORD1); - - // Check the wallet is currently encrypted - assertTrue("Wallet is not an encrypted wallet", encryptedWallet.getEncryptionType() == EncryptionType.ENCRYPTED_SCRYPT_AES); - - // Decrypt wallet. - assertTrue("The keyCrypter is missing but should not be.1", keyCrypter != null); - encryptedWallet.decrypt(aesKey); - - // Try decrypting it again - try { - assertTrue("The keyCrypter is missing but should not be.2", keyCrypter != null); - encryptedWallet.decrypt(aesKey); - fail("Should not be able to decrypt a decrypted wallet"); - } catch (IllegalStateException e) { - assertTrue("Expected behaviour", true); - } - assertTrue("Wallet is not an unencrypted wallet.2", encryptedWallet.getKeyCrypter() == null); - - // Encrypt wallet. - encryptedWallet.encrypt(keyCrypter, aesKey); - - assertTrue("Wallet is not an encrypted wallet.2", encryptedWallet.getEncryptionType() == EncryptionType.ENCRYPTED_SCRYPT_AES); - - // Try encrypting it again - try { - encryptedWallet.encrypt(keyCrypter, aesKey); - fail("Should not be able to encrypt an encrypted wallet"); - } catch (IllegalStateException e) { - assertTrue("Expected behaviour", true); - } - assertTrue("Wallet is not an encrypted wallet.3", encryptedWallet.getEncryptionType() == EncryptionType.ENCRYPTED_SCRYPT_AES); - } - - @Test(expected = KeyCrypterException.class) - public void addUnencryptedKeyToEncryptedWallet() throws Exception { - Wallet encryptedWallet = new Wallet(params); - encryptedWallet.encrypt(PASSWORD1); - - ECKey key1 = new ECKey(); - encryptedWallet.importKey(key1); - } - - @Test(expected = KeyCrypterException.class) - public void addEncryptedKeyToUnencryptedWallet() throws Exception { - Wallet encryptedWallet = new Wallet(params); - encryptedWallet.encrypt(PASSWORD1); - KeyCrypter keyCrypter = encryptedWallet.getKeyCrypter(); - - ECKey key1 = new ECKey(); - key1 = key1.encrypt(keyCrypter, keyCrypter.deriveKey("PASSWORD!")); - wallet.importKey(key1); - } - - @Test(expected = KeyCrypterException.class) - public void mismatchedCrypter() throws Exception { - Wallet encryptedWallet = new Wallet(params); - encryptedWallet.encrypt(PASSWORD1); - KeyCrypter keyCrypter = encryptedWallet.getKeyCrypter(); - KeyParameter aesKey = keyCrypter.deriveKey(PASSWORD1); - - // Try added an ECKey that was encrypted with a differenct ScryptParameters (i.e. a non-homogenous key). - // This is not allowed as the ScryptParameters is stored at the Wallet level. - byte[] salt = new byte[KeyCrypterScrypt.SALT_LENGTH]; - secureRandom.nextBytes(salt); - Protos.ScryptParameters.Builder scryptParametersBuilder = Protos.ScryptParameters.newBuilder().setSalt(ByteString.copyFrom(salt)); - Protos.ScryptParameters scryptParameters = scryptParametersBuilder.build(); - KeyCrypter keyCrypterDifferent = new KeyCrypterScrypt(scryptParameters); - ECKey ecKeyDifferent = new ECKey(); - ecKeyDifferent = ecKeyDifferent.encrypt(keyCrypterDifferent, aesKey); - encryptedWallet.importKey(ecKeyDifferent); - } - - @Test - public void importAndEncrypt() throws InsufficientMoneyException { - Wallet encryptedWallet = new Wallet(params); - encryptedWallet.encrypt(PASSWORD1); - - final ECKey key = new ECKey(); - encryptedWallet.importKeysAndEncrypt(ImmutableList.of(key), PASSWORD1); - assertEquals(1, encryptedWallet.getImportedKeys().size()); - assertEquals(key.getPubKeyPoint(), encryptedWallet.getImportedKeys().get(0).getPubKeyPoint()); - sendMoneyToWallet(encryptedWallet, Coin.COIN, key.toAddress(params), AbstractBlockChain.NewBlockType.BEST_CHAIN); - assertEquals(Coin.COIN, encryptedWallet.getBalance()); - SendRequest req = Wallet.SendRequest.emptyWallet(new ECKey().toAddress(params)); - req.aesKey = checkNotNull(encryptedWallet.getKeyCrypter()).deriveKey(PASSWORD1); - encryptedWallet.sendCoinsOffline(req); - } - - @Test - public void ageMattersDuringSelection() throws Exception { - // Test that we prefer older coins to newer coins when building spends. This reduces required fees and improves - // time to confirmation as the transaction will appear less spammy. - final int ITERATIONS = 10; - Transaction[] txns = new Transaction[ITERATIONS]; - for (int i = 0; i < ITERATIONS; i++) { - txns[i] = sendMoneyToWallet(COIN, AbstractBlockChain.NewBlockType.BEST_CHAIN); - } - // Check that we spend transactions in order of reception. - for (int i = 0; i < ITERATIONS; i++) { - Transaction spend = wallet.createSend(new ECKey().toAddress(params), COIN); - assertEquals(spend.getInputs().size(), 1); - assertEquals("Failed on iteration " + i, spend.getInput(0).getOutpoint().getHash(), txns[i].getHash()); - wallet.commitTx(spend); - } - } - - @Test(expected = Wallet.ExceededMaxTransactionSize.class) - public void respectMaxStandardSize() throws Exception { - // Check that we won't create txns > 100kb. Average tx size is ~220 bytes so this would have to be enormous. - sendMoneyToWallet(valueOf(100, 0), AbstractBlockChain.NewBlockType.BEST_CHAIN); - Transaction tx = new Transaction(params); - byte[] bits = new byte[20]; - new Random().nextBytes(bits); - Coin v = CENT; - // 3100 outputs to a random address. - for (int i = 0; i < 3100; i++) { - tx.addOutput(v, new Address(params, bits)); - } - Wallet.SendRequest req = Wallet.SendRequest.forTx(tx); - wallet.completeTx(req); - } - - @Test - public void opReturnOneOutputTest() throws Exception { - // Tests basic send of transaction with one output that doesn't transfer any value but just writes OP_RETURN. - receiveATransaction(wallet, myAddress); - Transaction tx = new Transaction(params); - Coin messagePrice = Coin.ZERO; - Script script = ScriptBuilder.createOpReturnScript("hello world!".getBytes()); - tx.addOutput(messagePrice, script); - SendRequest request = Wallet.SendRequest.forTx(tx); - wallet.completeTx(request); - } - - @Test - public void opReturnOneOutputWithValueTest() throws Exception { - // Tests basic send of transaction with one output that destroys coins and has an OP_RETURN. - receiveATransaction(wallet, myAddress); - Transaction tx = new Transaction(params); - Coin messagePrice = CENT; - Script script = ScriptBuilder.createOpReturnScript("hello world!".getBytes()); - tx.addOutput(messagePrice, script); - SendRequest request = Wallet.SendRequest.forTx(tx); - wallet.completeTx(request); - } - - @Test - public void opReturnTwoOutputsTest() throws Exception { - // Tests sending transaction where one output transfers BTC, the other one writes OP_RETURN. - receiveATransaction(wallet, myAddress); - Address notMyAddr = new ECKey().toAddress(params); - Transaction tx = new Transaction(params); - Coin messagePrice = Coin.ZERO; - Script script = ScriptBuilder.createOpReturnScript("hello world!".getBytes()); - tx.addOutput(CENT, notMyAddr); - tx.addOutput(messagePrice, script); - SendRequest request = Wallet.SendRequest.forTx(tx); - wallet.completeTx(request); - } - - @Test(expected = Wallet.MultipleOpReturnRequested.class) - public void twoOpReturnsPerTransactionTest() throws Exception { - // Tests sending transaction where there are 2 attempts to write OP_RETURN scripts - this should fail and throw MultipleOpReturnRequested. - receiveATransaction(wallet, myAddress); - Transaction tx = new Transaction(params); - Coin messagePrice = Coin.ZERO; - Script script1 = ScriptBuilder.createOpReturnScript("hello world 1!".getBytes()); - Script script2 = ScriptBuilder.createOpReturnScript("hello world 2!".getBytes()); - tx.addOutput(messagePrice, script1); - tx.addOutput(messagePrice, script2); - SendRequest request = Wallet.SendRequest.forTx(tx); - wallet.completeTx(request); - } - - @Test(expected = Wallet.DustySendRequested.class) - public void sendDustTest() throws InsufficientMoneyException { - // Tests sending dust, should throw DustySendRequested. - Transaction tx = new Transaction(params); - Address notMyAddr = new ECKey().toAddress(params); - tx.addOutput(Transaction.MIN_NONDUST_OUTPUT.subtract(SATOSHI), notMyAddr); - SendRequest request = Wallet.SendRequest.forTx(tx); - wallet.completeTx(request); - } - - @Test - public void sendMultipleCentsTest() throws Exception { - receiveATransactionAmount(wallet, myAddress, Coin.COIN); - Transaction tx = new Transaction(params); - Address notMyAddr = new ECKey().toAddress(params); - Coin c = CENT.subtract(SATOSHI); - tx.addOutput(c, notMyAddr); - tx.addOutput(c, notMyAddr); - tx.addOutput(c, notMyAddr); - tx.addOutput(c, notMyAddr); - SendRequest request = Wallet.SendRequest.forTx(tx); - wallet.completeTx(request); - } - - @Test(expected = Wallet.DustySendRequested.class) - public void sendDustAndOpReturnWithoutValueTest() throws Exception { - // Tests sending dust and OP_RETURN without value, should throw DustySendRequested because sending sending dust is not allowed in any case. - receiveATransactionAmount(wallet, myAddress, Coin.COIN); - Transaction tx = new Transaction(params); - Address notMyAddr = new ECKey().toAddress(params); - Script script = new ScriptBuilder().op(ScriptOpCodes.OP_RETURN).data("hello world!".getBytes()).build(); - tx.addOutput(Coin.ZERO, script); - tx.addOutput(Coin.SATOSHI, notMyAddr); - SendRequest request = Wallet.SendRequest.forTx(tx); - wallet.completeTx(request); - } - - @Test(expected = Wallet.DustySendRequested.class) - public void sendDustAndMessageWithValueTest() throws Exception { - //Tests sending dust and OP_RETURN with value, should throw DustySendRequested - receiveATransaction(wallet, myAddress); - Transaction tx = new Transaction(params); - Address notMyAddr = new ECKey().toAddress(params); - Script script = new ScriptBuilder().op(ScriptOpCodes.OP_RETURN).data("hello world!".getBytes()).build(); - tx.addOutput(Coin.CENT, script); - tx.addOutput(Transaction.MIN_NONDUST_OUTPUT.subtract(SATOSHI), notMyAddr); - SendRequest request = Wallet.SendRequest.forTx(tx); - wallet.completeTx(request); - } - - @Test - public void sendRequestP2PKTest() { - ECKey key = new ECKey(); - Address notMyAddr = key.toAddress(params); - SendRequest req = SendRequest.to(notMyAddr.getParameters(), key, SATOSHI.multiply(12)); - assertArrayEquals(key.getPubKey(), req.tx.getOutputs().get(0).getScriptPubKey().getPubKey()); - } - - @Test - public void sendRequestP2PKHTest() { - ECKey key = new ECKey(); - Address notMyAddr = key.toAddress(params); - SendRequest req = SendRequest.to(notMyAddr, SATOSHI.multiply(12)); - assertEquals(notMyAddr, req.tx.getOutputs().get(0).getScriptPubKey().getToAddress(params)); - } - - @Test - public void feeSolverAndCoinSelectionTest() throws Exception { - // Tests basic fee solving works - - // Make sure TestWithWallet isnt doing anything crazy. - assertEquals(0, wallet.getTransactions(true).size()); - - Address notMyAddr = new ECKey().toAddress(params); - - // Generate a few outputs to us that are far too small to spend reasonably - StoredBlock block = new StoredBlock(makeSolvedTestBlock(blockStore, notMyAddr), BigInteger.ONE, 1); - Transaction tx1 = createFakeTx(params, SATOSHI, myAddress); - wallet.receiveFromBlock(tx1, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); - Transaction tx2 = createFakeTx(params, SATOSHI, myAddress); - assertTrue(!tx1.getHash().equals(tx2.getHash())); - wallet.receiveFromBlock(tx2, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 1); - Transaction tx3 = createFakeTx(params, SATOSHI.multiply(10), myAddress); - wallet.receiveFromBlock(tx3, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 2); - - // Not allowed to send dust. - try { - wallet.createSend(notMyAddr, SATOSHI); - fail(); - } catch (Wallet.DustySendRequested e) { - // Expected. - } - // Spend it all without fee enforcement - SendRequest req = SendRequest.to(notMyAddr, SATOSHI.multiply(12)); - req.ensureMinRequiredFee = false; - assertNotNull(wallet.sendCoinsOffline(req)); - assertEquals(ZERO, wallet.getBalance()); - - // Add some reasonable-sized outputs - block = new StoredBlock(makeSolvedTestBlock(blockStore, notMyAddr), BigInteger.ONE, 1); - Transaction tx4 = createFakeTx(params, Coin.COIN, myAddress); - wallet.receiveFromBlock(tx4, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); - - // Simple test to make sure if we have an ouput < 0.01 we get a fee - Transaction spend1 = wallet.createSend(notMyAddr, CENT.subtract(SATOSHI)); - assertEquals(2, spend1.getOutputs().size()); - // We optimize for priority, so the output selected should be the largest one. - // We should have paid the default minfee. - assertEquals(spend1.getOutput(0).getValue().add(spend1.getOutput(1).getValue()), - Coin.COIN.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE)); - - // But not at exactly 0.01 - Transaction spend2 = wallet.createSend(notMyAddr, CENT); - assertEquals(2, spend2.getOutputs().size()); - // We optimize for priority, so the output selected should be the largest one - assertEquals(Coin.COIN, spend2.getOutput(0).getValue().add(spend2.getOutput(1).getValue())); - - // ...but not more fee than what we request - SendRequest request3 = SendRequest.to(notMyAddr, CENT.subtract(SATOSHI)); - request3.fee = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(SATOSHI); - wallet.completeTx(request3); - assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(SATOSHI), request3.tx.getFee()); - Transaction spend3 = request3.tx; - assertEquals(2, spend3.getOutputs().size()); - // We optimize for priority, so the output selected should be the largest one. - assertEquals(spend3.getOutput(0).getValue().add(spend3.getOutput(1).getValue()), - Coin.COIN.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(SATOSHI))); - - // ...unless we need it - SendRequest request4 = SendRequest.to(notMyAddr, CENT.subtract(SATOSHI)); - request4.fee = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.subtract(SATOSHI); - wallet.completeTx(request4); - assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request4.tx.getFee()); - Transaction spend4 = request4.tx; - assertEquals(2, spend4.getOutputs().size()); - // We optimize for priority, so the output selected should be the largest one. - assertEquals(spend4.getOutput(0).getValue().add(spend4.getOutput(1).getValue()), - Coin.COIN.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE)); - - SendRequest request5 = SendRequest.to(notMyAddr, Coin.COIN.subtract(CENT.subtract(SATOSHI))); - wallet.completeTx(request5); - assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request5.tx.getFee()); - Transaction spend5 = request5.tx; - // If we would have a change output < 0.01, it should add the fee - assertEquals(2, spend5.getOutputs().size()); - // We optimize for priority, so the output selected should be the largest one. - assertEquals(spend5.getOutput(0).getValue().add(spend5.getOutput(1).getValue()), - Coin.COIN.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE)); - - SendRequest request6 = SendRequest.to(notMyAddr, Coin.COIN.subtract(CENT)); - wallet.completeTx(request6); - assertEquals(ZERO, request6.tx.getFee()); - Transaction spend6 = request6.tx; - // ...but not if change output == 0.01 - assertEquals(2, spend6.getOutputs().size()); - // We optimize for priority, so the output selected should be the largest one - assertEquals(Coin.COIN, spend6.getOutput(0).getValue().add(spend6.getOutput(1).getValue())); - - SendRequest request7 = SendRequest.to(notMyAddr, Coin.COIN.subtract(CENT.subtract(SATOSHI.multiply(2)).multiply(2))); - request7.tx.addOutput(CENT.subtract(SATOSHI), notMyAddr); - wallet.completeTx(request7); - assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request7.tx.getFee()); - Transaction spend7 = request7.tx; - // If change is 0.1-satoshi and we already have a 0.1-satoshi output, fee should be reference fee - assertEquals(3, spend7.getOutputs().size()); - // We optimize for priority, so the output selected should be the largest one. - assertEquals(spend7.getOutput(0).getValue().add(spend7.getOutput(1).getValue()).add(spend7.getOutput(2).getValue()), - Coin.COIN.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE)); - - SendRequest request8 = SendRequest.to(notMyAddr, COIN.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE)); - wallet.completeTx(request8); - assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request8.tx.getFee()); - Transaction spend8 = request8.tx; - // If we would have a change output == REFERENCE_DEFAULT_MIN_TX_FEE that would cause a fee, throw it away and make it fee - assertEquals(1, spend8.getOutputs().size()); - // We optimize for priority, so the output selected should be the largest one - assertEquals(spend8.getOutput(0).getValue(), COIN.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE)); - - SendRequest request9 = SendRequest.to(notMyAddr, COIN.subtract( - Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT))); - wallet.completeTx(request9); - assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT), request9.tx.getFee()); - Transaction spend9 = request9.tx; - // ...in fact, also add fee if we would get back less than MIN_NONDUST_OUTPUT - assertEquals(1, spend9.getOutputs().size()); - // We optimize for priority, so the output selected should be the largest one. - assertEquals(spend9.getOutput(0).getValue(), - COIN.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT))); - - SendRequest request10 = SendRequest.to(notMyAddr, COIN.subtract( - Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT).add(SATOSHI))); - wallet.completeTx(request10); - assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request10.tx.getFee()); - Transaction spend10 = request10.tx; - // ...but if we get back any more than that, we should get a refund (but still pay fee) - assertEquals(2, spend10.getOutputs().size()); - // We optimize for priority, so the output selected should be the largest one - assertEquals(spend10.getOutput(0).getValue().add(spend10.getOutput(1).getValue()), - COIN.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE)); - - SendRequest request11 = SendRequest.to(notMyAddr, COIN.subtract( - Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT).add(SATOSHI.multiply(2)))); - request11.fee = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(SATOSHI); - wallet.completeTx(request11); - assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(SATOSHI), request11.tx.getFee()); - Transaction spend11 = request11.tx; - // ...of course fee should be min(request.fee, MIN_TX_FEE) so we should get MIN_TX_FEE.add(SATOSHI) here - assertEquals(2, spend11.getOutputs().size()); - // We optimize for priority, so the output selected should be the largest one. - assertEquals(spend11.getOutput(0).getValue().add(spend11.getOutput(1).getValue()), - COIN.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(SATOSHI))); - - // Remove the coin from our wallet - wallet.commitTx(spend11); - Transaction tx5 = createFakeTx(params, CENT, myAddress); - wallet.receiveFromBlock(tx5, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); - assertEquals(CENT, wallet.getBalance()); - - // Now test coin selection properly selects coin*depth - for (int i = 0; i < 100; i++) { - block = new StoredBlock(makeSolvedTestBlock(blockStore, notMyAddr), BigInteger.ONE, 1); - wallet.notifyNewBestBlock(block); - } - - block = new StoredBlock(makeSolvedTestBlock(blockStore, notMyAddr), BigInteger.ONE, 1); - Transaction tx6 = createFakeTx(params, COIN, myAddress); - wallet.receiveFromBlock(tx6, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 1); - assertTrue(tx5.getOutput(0).isMine(wallet) && tx5.getOutput(0).isAvailableForSpending() && tx5.getConfidence().getDepthInBlocks() == 100); - assertTrue(tx6.getOutput(0).isMine(wallet) && tx6.getOutput(0).isAvailableForSpending() && tx6.getConfidence().getDepthInBlocks() == 1); - - // tx5 and tx6 have exactly the same coin*depth, so the larger should be selected... - Transaction spend12 = wallet.createSend(notMyAddr, CENT); - assertTrue(spend12.getOutputs().size() == 2 && spend12.getOutput(0).getValue().add(spend12.getOutput(1).getValue()).equals(COIN)); - - wallet.notifyNewBestBlock(block); - assertTrue(tx5.getOutput(0).isMine(wallet) && tx5.getOutput(0).isAvailableForSpending() && tx5.getConfidence().getDepthInBlocks() == 101); - assertTrue(tx6.getOutput(0).isMine(wallet) && tx6.getOutput(0).isAvailableForSpending() && tx6.getConfidence().getDepthInBlocks() == 1); - // Now tx5 has slightly higher coin*depth than tx6... - Transaction spend13 = wallet.createSend(notMyAddr, CENT); - assertTrue(spend13.getOutputs().size() == 1 && spend13.getOutput(0).getValue().equals(CENT)); - - block = new StoredBlock(makeSolvedTestBlock(blockStore, notMyAddr), BigInteger.ONE, 1); - wallet.notifyNewBestBlock(block); - assertTrue(tx5.getOutput(0).isMine(wallet) && tx5.getOutput(0).isAvailableForSpending() && tx5.getConfidence().getDepthInBlocks() == 102); - assertTrue(tx6.getOutput(0).isMine(wallet) && tx6.getOutput(0).isAvailableForSpending() && tx6.getConfidence().getDepthInBlocks() == 2); - // Now tx6 has higher coin*depth than tx5... - Transaction spend14 = wallet.createSend(notMyAddr, CENT); - assertTrue(spend14.getOutputs().size() == 2 && spend14.getOutput(0).getValue().add(spend14.getOutput(1).getValue()).equals(COIN)); - - // Now test feePerKb - SendRequest request15 = SendRequest.to(notMyAddr, CENT); - for (int i = 0; i < 29; i++) - request15.tx.addOutput(CENT, notMyAddr); - assertTrue(request15.tx.bitcoinSerialize().length > 1000); - request15.feePerKb = SATOSHI; - wallet.completeTx(request15); - assertEquals(SATOSHI.multiply(2), request15.tx.getFee()); - Transaction spend15 = request15.tx; - // If a transaction is over 1kb, 2 satoshis should be added. - assertEquals(31, spend15.getOutputs().size()); - // We optimize for priority, so the output selected should be the largest one - Coin outValue15 = ZERO; - for (TransactionOutput out : spend15.getOutputs()) - outValue15 = outValue15.add(out.getValue()); - assertEquals(COIN.subtract(SATOSHI.multiply(2)), outValue15); - - SendRequest request16 = SendRequest.to(notMyAddr, CENT); - request16.feePerKb = ZERO; - for (int i = 0; i < 29; i++) - request16.tx.addOutput(CENT, notMyAddr); - assertTrue(request16.tx.bitcoinSerialize().length > 1000); - wallet.completeTx(request16); - // Of course the fee shouldn't be added if feePerKb == 0 - assertEquals(ZERO, request16.tx.getFee()); - Transaction spend16 = request16.tx; - assertEquals(31, spend16.getOutputs().size()); - // We optimize for priority, so the output selected should be the largest one - Coin outValue16 = ZERO; - for (TransactionOutput out : spend16.getOutputs()) - outValue16 = outValue16.add(out.getValue()); - assertEquals(COIN, outValue16); - - // Create a transaction whose max size could be up to 999 (if signatures were maximum size) - SendRequest request17 = SendRequest.to(notMyAddr, CENT); - for (int i = 0; i < 22; i++) - request17.tx.addOutput(CENT, notMyAddr); - request17.tx.addOutput(new TransactionOutput(params, request17.tx, CENT, new byte[15])); - request17.feePerKb = SATOSHI; - wallet.completeTx(request17); - assertEquals(SATOSHI, request17.tx.getFee()); - assertEquals(1, request17.tx.getInputs().size()); - // Calculate its max length to make sure it is indeed 999 - int theoreticalMaxLength17 = request17.tx.bitcoinSerialize().length + myKey.getPubKey().length + 75; - for (TransactionInput in : request17.tx.getInputs()) - theoreticalMaxLength17 -= in.getScriptBytes().length; - assertEquals(999, theoreticalMaxLength17); - Transaction spend17 = request17.tx; - { - // Its actual size must be between 996 and 999 (inclusive) as signatures have a 3-byte size range (almost always) - final int length = spend17.bitcoinSerialize().length; - assertTrue(Integer.toString(length), length >= 996 && length <= 999); - } - // Now check that it got a fee of 1 since its max size is 999 (1kb). - assertEquals(25, spend17.getOutputs().size()); - // We optimize for priority, so the output selected should be the largest one - Coin outValue17 = ZERO; - for (TransactionOutput out : spend17.getOutputs()) - outValue17 = outValue17.add(out.getValue()); - assertEquals(COIN.subtract(SATOSHI), outValue17); - - // Create a transaction who's max size could be up to 1001 (if signatures were maximum size) - SendRequest request18 = SendRequest.to(notMyAddr, CENT); - for (int i = 0; i < 22; i++) - request18.tx.addOutput(CENT, notMyAddr); - request18.tx.addOutput(new TransactionOutput(params, request18.tx, CENT, new byte[17])); - request18.feePerKb = SATOSHI; - wallet.completeTx(request18); - assertEquals(SATOSHI.multiply(2), request18.tx.getFee()); - assertEquals(1, request18.tx.getInputs().size()); - // Calculate its max length to make sure it is indeed 1001 - Transaction spend18 = request18.tx; - int theoreticalMaxLength18 = spend18.bitcoinSerialize().length + myKey.getPubKey().length + 75; - for (TransactionInput in : spend18.getInputs()) - theoreticalMaxLength18 -= in.getScriptBytes().length; - assertEquals(1001, theoreticalMaxLength18); - // Its actual size must be between 998 and 1000 (inclusive) as signatures have a 3-byte size range (almost always) - assertTrue(spend18.bitcoinSerialize().length >= 998); - assertTrue(spend18.bitcoinSerialize().length <= 1001); - // Now check that it did get a fee since its max size is 1000 - assertEquals(25, spend18.getOutputs().size()); - // We optimize for priority, so the output selected should be the largest one - Coin outValue18 = ZERO; - for (TransactionOutput out : spend18.getOutputs()) - outValue18 = outValue18.add(out.getValue()); - assertEquals(outValue18, COIN.subtract(SATOSHI.multiply(2))); - - // Now create a transaction that will spend COIN + fee, which makes it require both inputs - assertEquals(wallet.getBalance(), CENT.add(COIN)); - SendRequest request19 = SendRequest.to(notMyAddr, CENT); - request19.feePerKb = ZERO; - for (int i = 0; i < 99; i++) - request19.tx.addOutput(CENT, notMyAddr); - // If we send now, we shouldn't need a fee and should only have to spend our COIN - wallet.completeTx(request19); - assertEquals(ZERO, request19.tx.getFee()); - assertEquals(1, request19.tx.getInputs().size()); - assertEquals(100, request19.tx.getOutputs().size()); - // Now reset request19 and give it a fee per kb - request19.tx.clearInputs(); - request19 = SendRequest.forTx(request19.tx); - request19.feePerKb = SATOSHI; - request19.shuffleOutputs = false; - wallet.completeTx(request19); - assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request19.tx.getFee()); - assertEquals(2, request19.tx.getInputs().size()); - Coin outValue19 = ZERO; - for (TransactionOutput out : request19.tx.getOutputs()) - outValue19 = outValue19.add(out.getValue()); - // But now our change output is CENT-minfee, so we have to pay min fee - assertEquals(request19.tx.getOutput(request19.tx.getOutputs().size() - 1).getValue(), CENT.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE)); - assertEquals(outValue19, COIN.add(CENT).subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE)); - - // Create another transaction that will spend COIN + fee, which makes it require both inputs - SendRequest request20 = SendRequest.to(notMyAddr, CENT); - request20.feePerKb = ZERO; - for (int i = 0; i < 99; i++) - request20.tx.addOutput(CENT, notMyAddr); - // If we send now, we shouldn't have a fee and should only have to spend our COIN - wallet.completeTx(request20); - assertEquals(ZERO, request20.tx.getFee()); - assertEquals(1, request20.tx.getInputs().size()); - assertEquals(100, request20.tx.getOutputs().size()); - // Now reset request19 and give it a fee per kb - request20.tx.clearInputs(); - request20 = SendRequest.forTx(request20.tx); - request20.feePerKb = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE; - wallet.completeTx(request20); - // 4kb tx. - assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.multiply(4), request20.tx.getFee()); - assertEquals(2, request20.tx.getInputs().size()); - Coin outValue20 = ZERO; - for (TransactionOutput out : request20.tx.getOutputs()) - outValue20 = outValue20.add(out.getValue()); - // This time the fee we wanted to pay was more, so that should be what we paid - assertEquals(outValue20, COIN.add(CENT).subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.multiply(4))); - - // Same as request 19, but make the change 0 (so it doesnt force fee) and make us require min fee as a - // result of an output < CENT. - SendRequest request21 = SendRequest.to(notMyAddr, CENT); - request21.feePerKb = ZERO; - for (int i = 0; i < 99; i++) - request21.tx.addOutput(CENT, notMyAddr); - request21.tx.addOutput(CENT.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE), notMyAddr); - // If we send without a feePerKb, we should still require REFERENCE_DEFAULT_MIN_TX_FEE because we have an output < 0.01 - wallet.completeTx(request21); - assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request21.tx.getFee()); - assertEquals(2, request21.tx.getInputs().size()); - Coin outValue21 = ZERO; - for (TransactionOutput out : request21.tx.getOutputs()) - outValue21 = outValue21.add(out.getValue()); - assertEquals(outValue21, COIN.add(CENT).subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE)); - - // Test feePerKb when we aren't using ensureMinRequiredFee - // Same as request 19 - SendRequest request25 = SendRequest.to(notMyAddr, CENT); - request25.feePerKb = ZERO; - for (int i = 0; i < 70; i++) - request25.tx.addOutput(CENT, notMyAddr); - // If we send now, we shouldn't need a fee and should only have to spend our COIN - wallet.completeTx(request25); - assertEquals(ZERO, request25.tx.getFee()); - assertEquals(1, request25.tx.getInputs().size()); - assertEquals(72, request25.tx.getOutputs().size()); - // Now reset request19 and give it a fee per kb - request25.tx.clearInputs(); - request25 = SendRequest.forTx(request25.tx); - request25.feePerKb = CENT.divide(3); - request25.ensureMinRequiredFee = false; - request25.shuffleOutputs = false; - wallet.completeTx(request25); - assertEquals(CENT.subtract(SATOSHI), request25.tx.getFee()); - assertEquals(2, request25.tx.getInputs().size()); - Coin outValue25 = ZERO; - for (TransactionOutput out : request25.tx.getOutputs()) - outValue25 = outValue25.add(out.getValue()); - // Our change output should be one satoshi - assertEquals(SATOSHI, request25.tx.getOutput(request25.tx.getOutputs().size() - 1).getValue()); - // and our fee should be CENT-1 satoshi - assertEquals(outValue25, COIN.add(SATOSHI)); - - // Spend our CENT output. - Transaction spendTx5 = new Transaction(params); - spendTx5.addOutput(CENT, notMyAddr); - spendTx5.addInput(tx5.getOutput(0)); - wallet.signTransaction(SendRequest.forTx(spendTx5)); - - wallet.receiveFromBlock(spendTx5, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 4); - assertEquals(COIN, wallet.getBalance()); - - // Ensure change is discarded if it results in a fee larger than the chain (same as 8 and 9 but with feePerKb) - SendRequest request26 = SendRequest.to(notMyAddr, CENT); - for (int i = 0; i < 98; i++) - request26.tx.addOutput(CENT, notMyAddr); - request26.tx.addOutput(CENT.subtract( - Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT)), notMyAddr); - assertTrue(request26.tx.bitcoinSerialize().length > 1000); - request26.feePerKb = SATOSHI; - wallet.completeTx(request26); - assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT), request26.tx.getFee()); - Transaction spend26 = request26.tx; - // If a transaction is over 1kb, the set fee should be added - assertEquals(100, spend26.getOutputs().size()); - // We optimize for priority, so the output selected should be the largest one - Coin outValue26 = ZERO; - for (TransactionOutput out : spend26.getOutputs()) - outValue26 = outValue26.add(out.getValue()); - assertEquals(outValue26, COIN.subtract( - Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.add(Transaction.MIN_NONDUST_OUTPUT))); - } - - @Test - public void basicCategoryStepTest() throws Exception { - // Creates spends that step through the possible fee solver categories - SendRequest.DEFAULT_FEE_PER_KB = ZERO; - // Make sure TestWithWallet isnt doing anything crazy. - assertEquals(0, wallet.getTransactions(true).size()); - - Address notMyAddr = new ECKey().toAddress(params); - - // Generate a ton of small outputs - StoredBlock block = new StoredBlock(makeSolvedTestBlock(blockStore, notMyAddr), BigInteger.ONE, 1); - int i = 0; - Coin tenThousand = Coin.valueOf(10000); - while (i <= 100) { - Transaction tx = createFakeTxWithChangeAddress(params, tenThousand, myAddress, notMyAddr); - tx.getInput(0).setSequenceNumber(i++); // Keep every transaction unique - wallet.receiveFromBlock(tx, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, i); - } - Coin balance = wallet.getBalance(); - - // Create a spend that will throw away change (category 3 type 2 in which the change causes fee which is worth more than change) - SendRequest request1 = SendRequest.to(notMyAddr, balance.subtract(SATOSHI)); - wallet.completeTx(request1); - assertEquals(SATOSHI, request1.tx.getFee()); - assertEquals(request1.tx.getInputs().size(), i); // We should have spent all inputs - - // Give us one more input... - Transaction tx1 = createFakeTxWithChangeAddress(params, tenThousand, myAddress, notMyAddr); - tx1.getInput(0).setSequenceNumber(i++); // Keep every transaction unique - wallet.receiveFromBlock(tx1, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, i); - - // ... and create a spend that will throw away change (category 3 type 1 in which the change causes dust output) - SendRequest request2 = SendRequest.to(notMyAddr, balance.subtract(SATOSHI)); - wallet.completeTx(request2); - assertEquals(SATOSHI, request2.tx.getFee()); - assertEquals(request2.tx.getInputs().size(), i - 1); // We should have spent all inputs - 1 - - // Give us one more input... - Transaction tx2 = createFakeTxWithChangeAddress(params, tenThousand, myAddress, notMyAddr); - tx2.getInput(0).setSequenceNumber(i++); // Keep every transaction unique - wallet.receiveFromBlock(tx2, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, i); - - // ... and create a spend that will throw away change (category 3 type 1 in which the change causes dust output) - // but that also could have been category 2 if it wanted - SendRequest request3 = SendRequest.to(notMyAddr, CENT.add(tenThousand).subtract(SATOSHI)); - wallet.completeTx(request3); - assertEquals(SATOSHI, request3.tx.getFee()); - assertEquals(request3.tx.getInputs().size(), i - 2); // We should have spent all inputs - 2 - - // - SendRequest request4 = SendRequest.to(notMyAddr, balance.subtract(SATOSHI)); - request4.feePerKb = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.divide(request3.tx.bitcoinSerialize().length); - wallet.completeTx(request4); - assertEquals(SATOSHI, request4.tx.getFee()); - assertEquals(request4.tx.getInputs().size(), i - 2); // We should have spent all inputs - 2 - - // Give us a few more inputs... - while (wallet.getBalance().compareTo(CENT.multiply(2)) < 0) { - Transaction tx3 = createFakeTxWithChangeAddress(params, tenThousand, myAddress, notMyAddr); - tx3.getInput(0).setSequenceNumber(i++); // Keep every transaction unique - wallet.receiveFromBlock(tx3, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, i); - } - - // ...that is just slightly less than is needed for category 1 - SendRequest request5 = SendRequest.to(notMyAddr, CENT.add(tenThousand).subtract(SATOSHI)); - wallet.completeTx(request5); - assertEquals(SATOSHI, request5.tx.getFee()); - assertEquals(1, request5.tx.getOutputs().size()); // We should have no change output - - // Give us one more input... - Transaction tx4 = createFakeTxWithChangeAddress(params, tenThousand, myAddress, notMyAddr); - tx4.getInput(0).setSequenceNumber(i); // Keep every transaction unique - wallet.receiveFromBlock(tx4, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, i); - - // ... that puts us in category 1 (no fee!) - SendRequest request6 = SendRequest.to(notMyAddr, CENT.add(tenThousand).subtract(SATOSHI)); - wallet.completeTx(request6); - assertEquals(ZERO, request6.tx.getFee()); - assertEquals(2, request6.tx.getOutputs().size()); // We should have a change output - - SendRequest.DEFAULT_FEE_PER_KB = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE; - } - - @Test - public void testCategory2WithChange() throws Exception { - // Specifically target case 2 with significant change - - // Make sure TestWithWallet isnt doing anything crazy. - assertEquals(0, wallet.getTransactions(true).size()); - - Address notMyAddr = new ECKey().toAddress(params); - - // Generate a ton of small outputs - StoredBlock block = new StoredBlock(makeSolvedTestBlock(blockStore, notMyAddr), BigInteger.ONE, 1); - int i = 0; - while (i <= CENT.divide(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.multiply(10))) { - Transaction tx = createFakeTxWithChangeAddress(params, Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.multiply(10), myAddress, notMyAddr); - tx.getInput(0).setSequenceNumber(i++); // Keep every transaction unique - wallet.receiveFromBlock(tx, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, i); - } - - // The selector will choose 2 with MIN_TX_FEE fee - SendRequest request1 = SendRequest.to(notMyAddr, CENT.add(SATOSHI)); - wallet.completeTx(request1); - assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request1.tx.getFee()); - assertEquals(request1.tx.getInputs().size(), i); // We should have spent all inputs - assertEquals(2, request1.tx.getOutputs().size()); // and gotten change back - } - - @Test - public void transactionGetFeeTest() throws Exception { - Address notMyAddr = new ECKey().toAddress(params); - - // Prepare wallet to spend - StoredBlock block = new StoredBlock(makeSolvedTestBlock(blockStore, notMyAddr), BigInteger.ONE, 1); - Transaction tx = createFakeTx(params, COIN, myAddress); - wallet.receiveFromBlock(tx, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); - - // Create a transaction - SendRequest request = SendRequest.to(notMyAddr, CENT); - request.feePerKb = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE; - wallet.completeTx(request); - assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request.tx.getFee()); - } - - @Test - public void lowerThanDefaultFee() throws InsufficientMoneyException { - Coin fee = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.divide(10); - receiveATransactionAmount(wallet, myAddress, Coin.COIN); - SendRequest req = SendRequest.to(myAddress, Coin.CENT); - req.feePerKb = fee; - wallet.completeTx(req); - assertEquals(fee, req.tx.getFee()); - wallet.commitTx(req.tx); - SendRequest emptyReq = SendRequest.emptyWallet(myAddress); - emptyReq.feePerKb = fee; - emptyReq.emptyWallet = true; - emptyReq.coinSelector = AllowUnconfirmedCoinSelector.get(); - wallet.completeTx(emptyReq); - assertEquals(fee, emptyReq.tx.getFee()); - wallet.commitTx(emptyReq.tx); - } - - @Test - public void higherThanDefaultFee() throws InsufficientMoneyException { - Coin fee = Transaction.REFERENCE_DEFAULT_MIN_TX_FEE.multiply(10); - receiveATransactionAmount(wallet, myAddress, Coin.COIN); - SendRequest req = SendRequest.to(myAddress, Coin.CENT); - req.feePerKb = fee; - wallet.completeTx(req); - assertEquals(fee, req.tx.getFee()); - wallet.commitTx(req.tx); - SendRequest emptyReq = SendRequest.emptyWallet(myAddress); - emptyReq.feePerKb = fee; - emptyReq.emptyWallet = true; - emptyReq.coinSelector = AllowUnconfirmedCoinSelector.get(); - wallet.completeTx(emptyReq); - assertEquals(fee, emptyReq.tx.getFee()); - wallet.commitTx(emptyReq.tx); - } - - @Test - public void feePerKbCategoryJumpTest() throws Exception { - // Simple test of boundary condition on fee per kb in category fee solver - - // Make sure TestWithWallet isnt doing anything crazy. - assertEquals(0, wallet.getTransactions(true).size()); - - Address notMyAddr = new ECKey().toAddress(params); - - // Generate a ton of small outputs - StoredBlock block = new StoredBlock(makeSolvedTestBlock(blockStore, notMyAddr), BigInteger.ONE, 1); - Transaction tx = createFakeTx(params, COIN, myAddress); - wallet.receiveFromBlock(tx, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); - Transaction tx2 = createFakeTx(params, CENT, myAddress); - wallet.receiveFromBlock(tx2, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 1); - Transaction tx3 = createFakeTx(params, SATOSHI, myAddress); - wallet.receiveFromBlock(tx3, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 2); - - // Create a transaction who's max size could be up to 1000 (if signatures were maximum size) - SendRequest request1 = SendRequest.to(notMyAddr, COIN.subtract(CENT.multiply(17))); - for (int i = 0; i < 16; i++) - request1.tx.addOutput(CENT, notMyAddr); - request1.tx.addOutput(new TransactionOutput(params, request1.tx, CENT, new byte[16])); - request1.fee = SATOSHI; - request1.feePerKb = SATOSHI; - // We get a category 2 using COIN+CENT - // It spends COIN + 1(fee) and because its output is thus < CENT, we have to pay MIN_TX_FEE - // When it tries category 1, its too large and requires COIN + 2 (fee) - // This adds the next input, but still has a < CENT output which means it cant reach category 1 - wallet.completeTx(request1); - assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request1.tx.getFee()); - assertEquals(2, request1.tx.getInputs().size()); - - // We then add one more satoshi output to the wallet - Transaction tx4 = createFakeTx(params, SATOSHI, myAddress); - wallet.receiveFromBlock(tx4, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 3); - - // Create a transaction who's max size could be up to 1000 (if signatures were maximum size) - SendRequest request2 = SendRequest.to(notMyAddr, COIN.subtract(CENT.multiply(17))); - for (int i = 0; i < 16; i++) - request2.tx.addOutput(CENT, notMyAddr); - request2.tx.addOutput(new TransactionOutput(params, request2.tx, CENT, new byte[16])); - request2.feePerKb = SATOSHI; - // The process is the same as above, but now we can complete category 1 with one more input, and pay a fee of 2 - wallet.completeTx(request2); - assertEquals(SATOSHI.multiply(2), request2.tx.getFee()); - assertEquals(4, request2.tx.getInputs().size()); - } - - @Test - public void testCompleteTxWithExistingInputs() throws Exception { - // Tests calling completeTx with a SendRequest that already has a few inputs in it - // Make sure TestWithWallet isnt doing anything crazy. - assertEquals(0, wallet.getTransactions(true).size()); - - Address notMyAddr = new ECKey().toAddress(params); - - // Generate a few outputs to us - StoredBlock block = new StoredBlock(makeSolvedTestBlock(blockStore, notMyAddr), BigInteger.ONE, 1); - Transaction tx1 = createFakeTx(params, COIN, myAddress); - wallet.receiveFromBlock(tx1, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); - Transaction tx2 = createFakeTx(params, COIN, myAddress); assertTrue(!tx1.getHash().equals(tx2.getHash())); - wallet.receiveFromBlock(tx2, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 1); - Transaction tx3 = createFakeTx(params, CENT, myAddress); - wallet.receiveFromBlock(tx3, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 2); - - SendRequest request1 = SendRequest.to(notMyAddr, CENT); - // If we just complete as-is, we will use one of the COIN outputs to get higher priority, - // resulting in a change output - request1.shuffleOutputs = false; - wallet.completeTx(request1); - assertEquals(1, request1.tx.getInputs().size()); - assertEquals(2, request1.tx.getOutputs().size()); - assertEquals(CENT, request1.tx.getOutput(0).getValue()); - assertEquals(COIN.subtract(CENT), request1.tx.getOutput(1).getValue()); - - // Now create an identical request2 and add an unsigned spend of the CENT output - SendRequest request2 = SendRequest.to(notMyAddr, CENT); - request2.tx.addInput(tx3.getOutput(0)); - // Now completeTx will result in one input, one output - wallet.completeTx(request2); - assertEquals(1, request2.tx.getInputs().size()); - assertEquals(1, request2.tx.getOutputs().size()); - assertEquals(CENT, request2.tx.getOutput(0).getValue()); - // Make sure it was properly signed - request2.tx.getInput(0).getScriptSig().correctlySpends(request2.tx, 0, tx3.getOutput(0).getScriptPubKey()); - - // However, if there is no connected output, we will grab a COIN output anyway and add the CENT to fee - SendRequest request3 = SendRequest.to(notMyAddr, CENT); - request3.tx.addInput(new TransactionInput(params, request3.tx, new byte[]{}, new TransactionOutPoint(params, 0, tx3.getHash()))); - // Now completeTx will result in two inputs, two outputs and a fee of a CENT - // Note that it is simply assumed that the inputs are correctly signed, though in fact the first is not - request3.shuffleOutputs = false; - wallet.completeTx(request3); - assertEquals(2, request3.tx.getInputs().size()); - assertEquals(2, request3.tx.getOutputs().size()); - assertEquals(CENT, request3.tx.getOutput(0).getValue()); - assertEquals(COIN.subtract(CENT), request3.tx.getOutput(1).getValue()); - - SendRequest request4 = SendRequest.to(notMyAddr, CENT); - request4.tx.addInput(tx3.getOutput(0)); - // Now if we manually sign it, completeTx will not replace our signature - wallet.signTransaction(request4); - byte[] scriptSig = request4.tx.getInput(0).getScriptBytes(); - wallet.completeTx(request4); - assertEquals(1, request4.tx.getInputs().size()); - assertEquals(1, request4.tx.getOutputs().size()); - assertEquals(CENT, request4.tx.getOutput(0).getValue()); - assertArrayEquals(scriptSig, request4.tx.getInput(0).getScriptBytes()); - } - - // There is a test for spending a coinbase transaction as it matures in BlockChainTest#coinbaseTransactionAvailability - - // Support for offline spending is tested in PeerGroupTest - - @Test - public void exceptionsDoNotBlockAllListeners() throws Exception { - // Check that if a wallet listener throws an exception, the others still run. - wallet.addEventListener(new AbstractWalletEventListener() { - @Override - public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) { - log.info("onCoinsReceived 1"); - throw new RuntimeException("barf"); - } - }); - final AtomicInteger flag = new AtomicInteger(); - wallet.addEventListener(new AbstractWalletEventListener() { - @Override - public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) { - log.info("onCoinsReceived 2"); - flag.incrementAndGet(); - } - }); - - sendMoneyToWallet(COIN, AbstractBlockChain.NewBlockType.BEST_CHAIN); - log.info("Wait for user thread"); - Threading.waitForUserCode(); - log.info("... and test flag."); - assertEquals(1, flag.get()); - } - - @Test - public void testEmptyRandomWallet() throws Exception { - // Add a random set of outputs - StoredBlock block = new StoredBlock(makeSolvedTestBlock(blockStore, new ECKey().toAddress(params)), BigInteger.ONE, 1); - Random rng = new Random(); - for (int i = 0; i < rng.nextInt(100) + 1; i++) { - Transaction tx = createFakeTx(params, Coin.valueOf(rng.nextInt((int) COIN.value)), myAddress); - wallet.receiveFromBlock(tx, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, i); - } - SendRequest request = SendRequest.emptyWallet(new ECKey().toAddress(params)); - wallet.completeTx(request); - wallet.commitTx(request.tx); - assertEquals(ZERO, wallet.getBalance()); - } - - @Test - public void testEmptyWallet() throws Exception { - Address outputKey = new ECKey().toAddress(params); - // Add exactly 0.01 - StoredBlock block = new StoredBlock(makeSolvedTestBlock(blockStore, outputKey), BigInteger.ONE, 1); - Transaction tx = createFakeTx(params, CENT, myAddress); - wallet.receiveFromBlock(tx, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); - SendRequest request = SendRequest.emptyWallet(outputKey); - wallet.completeTx(request); - assertEquals(Wallet.SendRequest.DEFAULT_FEE_PER_KB, request.tx.getFee()); - wallet.commitTx(request.tx); - assertEquals(ZERO, wallet.getBalance()); - assertEquals(CENT, request.tx.getOutput(0).getValue()); - - // Add 1 confirmed cent and 1 unconfirmed cent. Verify only one cent is emptied because of the coin selection - // policies that are in use by default. - block = new StoredBlock(makeSolvedTestBlock(blockStore, outputKey), BigInteger.ONE, 1); - tx = createFakeTx(params, CENT, myAddress); - wallet.receiveFromBlock(tx, block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); - tx = createFakeTx(params, CENT, myAddress); - wallet.receivePending(tx, null); - request = SendRequest.emptyWallet(outputKey); - wallet.completeTx(request); - assertEquals(Wallet.SendRequest.DEFAULT_FEE_PER_KB, request.tx.getFee()); - wallet.commitTx(request.tx); - assertEquals(ZERO, wallet.getBalance()); - assertEquals(CENT, request.tx.getOutput(0).getValue()); - - // Add just under 0.01 - StoredBlock block2 = new StoredBlock(block.getHeader().createNextBlock(outputKey), BigInteger.ONE, 2); - tx = createFakeTx(params, CENT.subtract(SATOSHI), myAddress); - wallet.receiveFromBlock(tx, block2, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); - request = SendRequest.emptyWallet(outputKey); - wallet.completeTx(request); - assertEquals(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE, request.tx.getFee()); - wallet.commitTx(request.tx); - assertEquals(ZERO, wallet.getBalance()); - assertEquals(CENT.subtract(SATOSHI).subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE), request.tx.getOutput(0).getValue()); - - // Add an unsendable value - StoredBlock block3 = new StoredBlock(block2.getHeader().createNextBlock(outputKey), BigInteger.ONE, 3); - Coin outputValue = Transaction.MIN_NONDUST_OUTPUT.add(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE).subtract(SATOSHI); - tx = createFakeTx(params, outputValue, myAddress); - wallet.receiveFromBlock(tx, block3, AbstractBlockChain.NewBlockType.BEST_CHAIN, 0); - try { - request = SendRequest.emptyWallet(outputKey); - wallet.completeTx(request); - fail(); - } catch (Wallet.CouldNotAdjustDownwards e) {} - request = SendRequest.emptyWallet(outputKey); - request.ensureMinRequiredFee = false; - wallet.completeTx(request); - assertEquals(ZERO, request.tx.getFee()); - wallet.commitTx(request.tx); - assertEquals(ZERO, wallet.getBalance()); - assertEquals(outputValue, request.tx.getOutput(0).getValue()); - } - - @Test - public void keyRotationRandom() throws Exception { - Utils.setMockClock(); - // Start with an empty wallet (no HD chain). - wallet = new Wallet(params); - // Watch out for wallet-initiated broadcasts. - MockTransactionBroadcaster broadcaster = new MockTransactionBroadcaster(wallet); - // Send three cents to two different random keys, then add a key and mark the initial keys as compromised. - ECKey key1 = new ECKey(); - key1.setCreationTimeSeconds(Utils.currentTimeSeconds() - (86400 * 2)); - ECKey key2 = new ECKey(); - key2.setCreationTimeSeconds(Utils.currentTimeSeconds() - 86400); - wallet.importKey(key1); - wallet.importKey(key2); - sendMoneyToWallet(wallet, CENT, key1.toAddress(params), AbstractBlockChain.NewBlockType.BEST_CHAIN); - sendMoneyToWallet(wallet, CENT, key2.toAddress(params), AbstractBlockChain.NewBlockType.BEST_CHAIN); - sendMoneyToWallet(wallet, CENT, key2.toAddress(params), AbstractBlockChain.NewBlockType.BEST_CHAIN); - Date compromiseTime = Utils.now(); - assertEquals(0, broadcaster.size()); - assertFalse(wallet.isKeyRotating(key1)); - - // We got compromised! - Utils.rollMockClock(1); - wallet.setKeyRotationTime(compromiseTime); - assertTrue(wallet.isKeyRotating(key1)); - wallet.doMaintenance(null, true); - - Transaction tx = broadcaster.waitForTransactionAndSucceed(); - final Coin THREE_CENTS = CENT.add(CENT).add(CENT); - assertEquals(THREE_CENTS, tx.getValueSentFromMe(wallet)); - assertEquals(THREE_CENTS.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE), tx.getValueSentToMe(wallet)); - // TX sends to one of our addresses (for now we ignore married wallets). - final Address toAddress = tx.getOutput(0).getScriptPubKey().getToAddress(params); - final ECKey rotatingToKey = wallet.findKeyFromPubHash(toAddress.getHash160()); - assertNotNull(rotatingToKey); - assertFalse(wallet.isKeyRotating(rotatingToKey)); - assertEquals(3, tx.getInputs().size()); - // It confirms. - sendMoneyToWallet(tx, AbstractBlockChain.NewBlockType.BEST_CHAIN); - - // Now receive some more money to the newly derived address via a new block and check that nothing happens. - sendMoneyToWallet(wallet, CENT, toAddress, AbstractBlockChain.NewBlockType.BEST_CHAIN); - assertTrue(wallet.doMaintenance(null, true).get().isEmpty()); - assertEquals(0, broadcaster.size()); - - // Receive money via a new block on key1 and ensure it shows up as a maintenance task. - sendMoneyToWallet(wallet, CENT, key1.toAddress(params), AbstractBlockChain.NewBlockType.BEST_CHAIN); - wallet.doMaintenance(null, true); - tx = broadcaster.waitForTransactionAndSucceed(); - assertNotNull(wallet.findKeyFromPubHash(tx.getOutput(0).getScriptPubKey().getPubKeyHash())); - log.info("Unexpected thing: {}", tx); - assertEquals(1, tx.getInputs().size()); - assertEquals(1, tx.getOutputs().size()); - assertEquals(CENT.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE), tx.getOutput(0).getValue()); - - assertEquals(Transaction.Purpose.KEY_ROTATION, tx.getPurpose()); - - // We don't attempt to race an attacker against unconfirmed transactions. - - // Now round-trip the wallet and check the protobufs are storing the data correctly. - wallet = roundTrip(wallet); - - tx = wallet.getTransaction(tx.getHash()); - checkNotNull(tx); - assertEquals(Transaction.Purpose.KEY_ROTATION, tx.getPurpose()); - // Have to divide here to avoid mismatch due to second-level precision in serialisation. - assertEquals(compromiseTime.getTime() / 1000, wallet.getKeyRotationTime().getTime() / 1000); - - // Make a normal spend and check it's all ok. - final Address address = new ECKey().toAddress(params); - wallet.sendCoins(broadcaster, address, wallet.getBalance()); - tx = broadcaster.waitForTransaction(); - assertArrayEquals(address.getHash160(), tx.getOutput(0).getScriptPubKey().getPubKeyHash()); - } - - private Wallet roundTrip(Wallet wallet) throws UnreadableWalletException { - Protos.Wallet protos = new WalletProtobufSerializer().walletToProto(wallet); - return new WalletProtobufSerializer().readWallet(params, null, protos); - } - - @Test - public void keyRotationHD() throws Exception { - // Test that if we rotate an HD chain, a new one is created and all arrivals on the old keys are moved. - Utils.setMockClock(); - wallet = new Wallet(params); - ECKey key1 = wallet.freshReceiveKey(); - ECKey key2 = wallet.freshReceiveKey(); - sendMoneyToWallet(wallet, CENT, key1.toAddress(params), AbstractBlockChain.NewBlockType.BEST_CHAIN); - sendMoneyToWallet(wallet, CENT, key2.toAddress(params), AbstractBlockChain.NewBlockType.BEST_CHAIN); - DeterministicKey watchKey1 = wallet.getWatchingKey(); - - // A day later, we get compromised. - Utils.rollMockClock(86400); - wallet.setKeyRotationTime(Utils.currentTimeSeconds()); - - List txns = wallet.doMaintenance(null, false).get(); - assertEquals(1, txns.size()); - DeterministicKey watchKey2 = wallet.getWatchingKey(); - assertNotEquals(watchKey1, watchKey2); - } - - @SuppressWarnings("ConstantConditions") - @Test - public void keyRotationHD2() throws Exception { - // Check we handle the following scenario: a weak random key is created, then some good random keys are created - // but the weakness of the first isn't known yet. The wallet is upgraded to HD based on the weak key. Later, we - // find out about the weakness and set the rotation time to after the bad key's creation date. A new HD chain - // should be created based on the oldest known good key and the old chain + bad random key should rotate to it. - - // We fix the private keys just to make the test deterministic (last byte differs). - Utils.setMockClock(); - ECKey badKey = ECKey.fromPrivate(Utils.HEX.decode("00905b93f990267f4104f316261fc10f9f983551f9ef160854f40102eb71cffdbb")); - badKey.setCreationTimeSeconds(Utils.currentTimeSeconds()); - Utils.rollMockClock(86400); - ECKey goodKey = ECKey.fromPrivate(Utils.HEX.decode("00905b93f990267f4104f316261fc10f9f983551f9ef160854f40102eb71cffdcc")); - goodKey.setCreationTimeSeconds(Utils.currentTimeSeconds()); - - // Do an upgrade based on the bad key. - final AtomicReference> fChains = new AtomicReference>(); - KeyChainGroup kcg = new KeyChainGroup(params) { - - { - fChains.set(chains); - } - }; - kcg.importKeys(badKey, goodKey); - Utils.rollMockClock(86400); - wallet = new Wallet(params, kcg); // This avoids the automatic HD initialisation - assertTrue(fChains.get().isEmpty()); - wallet.upgradeToDeterministic(null); - DeterministicKey badWatchingKey = wallet.getWatchingKey(); - assertEquals(badKey.getCreationTimeSeconds(), badWatchingKey.getCreationTimeSeconds()); - sendMoneyToWallet(wallet, CENT, badWatchingKey.toAddress(params), AbstractBlockChain.NewBlockType.BEST_CHAIN); - - // Now we set the rotation time to the time we started making good keys. This should create a new HD chain. - wallet.setKeyRotationTime(goodKey.getCreationTimeSeconds()); - List txns = wallet.doMaintenance(null, false).get(); - assertEquals(1, txns.size()); - Address output = txns.get(0).getOutput(0).getAddressFromP2PKHScript(params); - ECKey usedKey = wallet.findKeyFromPubHash(output.getHash160()); - assertEquals(goodKey.getCreationTimeSeconds(), usedKey.getCreationTimeSeconds()); - assertEquals(goodKey.getCreationTimeSeconds(), wallet.freshReceiveKey().getCreationTimeSeconds()); - assertEquals("mrM3TpCnav5YQuVA1xLercCGJH4DXujMtv", usedKey.toAddress(params).toString()); - DeterministicKeyChain c = fChains.get().get(1); - assertEquals(c.getEarliestKeyCreationTime(), goodKey.getCreationTimeSeconds()); - assertEquals(2, fChains.get().size()); - - // Commit the maint txns. - wallet.commitTx(txns.get(0)); - - // Check next maintenance does nothing. - assertTrue(wallet.doMaintenance(null, false).get().isEmpty()); - assertEquals(c, fChains.get().get(1)); - assertEquals(2, fChains.get().size()); - } - - @Test(expected = IllegalArgumentException.class) - public void importOfHDKeyForbidden() throws Exception { - wallet.importKey(wallet.freshReceiveKey()); - } - - //@Test //- this test is slow, disable for now. - public void fragmentedReKeying() throws Exception { - // Send lots of small coins and check the fee is correct. - ECKey key = wallet.freshReceiveKey(); - Address address = key.toAddress(params); - Utils.setMockClock(); - Utils.rollMockClock(86400); - for (int i = 0; i < 800; i++) { - sendMoneyToWallet(wallet, CENT, address, AbstractBlockChain.NewBlockType.BEST_CHAIN); - } - - MockTransactionBroadcaster broadcaster = new MockTransactionBroadcaster(wallet); - - Date compromise = Utils.now(); - Utils.rollMockClock(86400); - wallet.freshReceiveKey(); - wallet.setKeyRotationTime(compromise); - wallet.doMaintenance(null, true); - - Transaction tx = broadcaster.waitForTransactionAndSucceed(); - final Coin valueSentToMe = tx.getValueSentToMe(wallet); - Coin fee = tx.getValueSentFromMe(wallet).subtract(valueSentToMe); - assertEquals(Coin.valueOf(900000), fee); - assertEquals(KeyTimeCoinSelector.MAX_SIMULTANEOUS_INPUTS, tx.getInputs().size()); - assertEquals(Coin.valueOf(599100000), valueSentToMe); - - tx = broadcaster.waitForTransaction(); - assertNotNull(tx); - assertEquals(200, tx.getInputs().size()); - } - - @Test - public void completeTxPartiallySignedWithDummySigs() throws Exception { - byte[] dummySig = TransactionSignature.dummy().encodeToBitcoin(); - completeTxPartiallySigned(Wallet.MissingSigsMode.USE_DUMMY_SIG, dummySig); - } - - @Test - public void completeTxPartiallySignedWithEmptySig() throws Exception { - byte[] emptySig = new byte[]{}; - completeTxPartiallySigned(Wallet.MissingSigsMode.USE_OP_ZERO, emptySig); - } - - @Test (expected = ECKey.MissingPrivateKeyException.class) - public void completeTxPartiallySignedThrows() throws Exception { - byte[] emptySig = new byte[]{}; - completeTxPartiallySigned(Wallet.MissingSigsMode.THROW, emptySig); - } - - @Test - public void completeTxPartiallySignedMarriedWithDummySigs() throws Exception { - byte[] dummySig = TransactionSignature.dummy().encodeToBitcoin(); - completeTxPartiallySignedMarried(Wallet.MissingSigsMode.USE_DUMMY_SIG, dummySig); - } - - @Test - public void completeTxPartiallySignedMarriedWithEmptySig() throws Exception { - byte[] emptySig = new byte[]{}; - completeTxPartiallySignedMarried(Wallet.MissingSigsMode.USE_OP_ZERO, emptySig); - } - - @Test (expected = TransactionSigner.MissingSignatureException.class) - public void completeTxPartiallySignedMarriedThrows() throws Exception { - byte[] emptySig = new byte[]{}; - completeTxPartiallySignedMarried(Wallet.MissingSigsMode.THROW, emptySig); - } - - @Test (expected = TransactionSigner.MissingSignatureException.class) - public void completeTxPartiallySignedMarriedThrowsByDefault() throws Exception { - createMarriedWallet(2, 2, false); - myAddress = wallet.currentAddress(KeyChain.KeyPurpose.RECEIVE_FUNDS); - sendMoneyToWallet(wallet, COIN, myAddress, AbstractBlockChain.NewBlockType.BEST_CHAIN); - - Wallet.SendRequest req = Wallet.SendRequest.emptyWallet(new ECKey().toAddress(params)); - wallet.completeTx(req); - } - - public void completeTxPartiallySignedMarried(Wallet.MissingSigsMode missSigMode, byte[] expectedSig) throws Exception { - // create married wallet without signer - createMarriedWallet(2, 2, false); - myAddress = wallet.currentAddress(KeyChain.KeyPurpose.RECEIVE_FUNDS); - sendMoneyToWallet(wallet, COIN, myAddress, AbstractBlockChain.NewBlockType.BEST_CHAIN); - - ECKey dest = new ECKey(); - Wallet.SendRequest req = Wallet.SendRequest.emptyWallet(dest.toAddress(params)); - req.missingSigsMode = missSigMode; - wallet.completeTx(req); - TransactionInput input = req.tx.getInput(0); - - boolean firstSigIsMissing = Arrays.equals(expectedSig, input.getScriptSig().getChunks().get(1).data); - boolean secondSigIsMissing = Arrays.equals(expectedSig, input.getScriptSig().getChunks().get(2).data); - - assertTrue("Only one of the signatures should be missing/dummy", firstSigIsMissing ^ secondSigIsMissing); - int localSigIndex = firstSigIsMissing ? 2 : 1; - int length = input.getScriptSig().getChunks().get(localSigIndex).data.length; - assertTrue("Local sig should be present: " + length, length > 70); - } - - - @SuppressWarnings("ConstantConditions") - public void completeTxPartiallySigned(Wallet.MissingSigsMode missSigMode, byte[] expectedSig) throws Exception { - // Check the wallet will write dummy scriptSigs for inputs that we have only pubkeys for without the privkey. - ECKey priv = new ECKey(); - ECKey pub = ECKey.fromPublicOnly(priv.getPubKeyPoint()); - wallet.importKey(pub); - ECKey priv2 = wallet.freshReceiveKey(); - // Send three transactions, with one being an address type and the other being a raw CHECKSIG type pubkey only, - // and the final one being a key we do have. We expect the first two inputs to be dummy values and the last - // to be signed correctly. - Transaction t1 = sendMoneyToWallet(wallet, CENT, pub.toAddress(params), AbstractBlockChain.NewBlockType.BEST_CHAIN); - Transaction t2 = sendMoneyToWallet(wallet, CENT, pub, AbstractBlockChain.NewBlockType.BEST_CHAIN); - Transaction t3 = sendMoneyToWallet(wallet, CENT, priv2, AbstractBlockChain.NewBlockType.BEST_CHAIN); - - ECKey dest = new ECKey(); - Wallet.SendRequest req = Wallet.SendRequest.emptyWallet(dest.toAddress(params)); - req.missingSigsMode = missSigMode; - wallet.completeTx(req); - byte[] dummySig = TransactionSignature.dummy().encodeToBitcoin(); - // Selected inputs can be in any order. - for (int i = 0; i < req.tx.getInputs().size(); i++) { - TransactionInput input = req.tx.getInput(i); - if (input.getConnectedOutput().getParentTransaction().equals(t1)) { - assertArrayEquals(expectedSig, input.getScriptSig().getChunks().get(0).data); - } else if (input.getConnectedOutput().getParentTransaction().equals(t2)) { - assertArrayEquals(expectedSig, input.getScriptSig().getChunks().get(0).data); - } else if (input.getConnectedOutput().getParentTransaction().equals(t3)) { - input.getScriptSig().correctlySpends(req.tx, i, t3.getOutput(0).getScriptPubKey()); - } - } - assertTrue(TransactionSignature.isEncodingCanonical(dummySig)); - } - - @Test - public void riskAnalysis() throws Exception { - // Send a tx that is considered risky to the wallet, verify it doesn't show up in the balances. - final Transaction tx = createFakeTx(params, COIN, myAddress); - final AtomicBoolean bool = new AtomicBoolean(); - wallet.setRiskAnalyzer(new RiskAnalysis.Analyzer() { - @Override - public RiskAnalysis create(Wallet wallet, Transaction wtx, List dependencies) { - RiskAnalysis.Result result = RiskAnalysis.Result.OK; - if (wtx.getHash().equals(tx.getHash())) - result = RiskAnalysis.Result.NON_STANDARD; - final RiskAnalysis.Result finalResult = result; - return new RiskAnalysis() { - @Override - public Result analyze() { - bool.set(true); - return finalResult; - } - }; - } - }); - assertTrue(wallet.isPendingTransactionRelevant(tx)); - assertEquals(Coin.ZERO, wallet.getBalance()); - assertEquals(Coin.ZERO, wallet.getBalance(Wallet.BalanceType.ESTIMATED)); - wallet.receivePending(tx, null); - assertEquals(Coin.ZERO, wallet.getBalance()); - assertEquals(Coin.ZERO, wallet.getBalance(Wallet.BalanceType.ESTIMATED)); - assertTrue(bool.get()); - // Confirm it in the same manner as how Bloom filtered blocks do. Verify it shows up. - StoredBlock block = createFakeBlock(blockStore, tx).storedBlock; - wallet.notifyTransactionIsInBlock(tx.getHash(), block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 1); - assertEquals(COIN, wallet.getBalance()); - } - - @Test - public void transactionInBlockNotification() { - final Transaction tx = createFakeTx(params, COIN, myAddress); - StoredBlock block = createFakeBlock(blockStore, tx).storedBlock; - wallet.receivePending(tx, null); - boolean notification = wallet.notifyTransactionIsInBlock(tx.getHash(), block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 1); - assertTrue(notification); - - Address notMyAddr = new ECKey().toAddress(params); - final Transaction tx2 = createFakeTx(params, COIN, notMyAddr); - wallet.receivePending(tx2, null); - StoredBlock block2 = createFakeBlock(blockStore, tx2).storedBlock; - boolean notification2 = wallet.notifyTransactionIsInBlock(tx2.getHash(), block2, AbstractBlockChain.NewBlockType.BEST_CHAIN, 1); - assertFalse(notification2); - } - - @Test - public void duplicatedBlock() { - final Transaction tx = createFakeTx(params, COIN, myAddress); - StoredBlock block = createFakeBlock(blockStore, tx).storedBlock; - wallet.notifyNewBestBlock(block); - wallet.notifyNewBestBlock(block); - } - - @Test - public void keyEvents() throws Exception { - // Check that we can register an event listener, generate some keys and the callbacks are invoked properly. - wallet = new Wallet(params); - final List keys = Lists.newLinkedList(); - wallet.addEventListener(new AbstractWalletEventListener() { - @Override - public void onKeysAdded(List k) { - keys.addAll(k); - } - }, Threading.SAME_THREAD); - wallet.freshReceiveKey(); - assertEquals(1, keys.size()); - } - - @Test - public void upgradeToHDUnencrypted() throws Exception { - // This isn't very deep because most of it is tested in KeyChainGroupTest and Wallet just forwards most logic - // there. We're mostly concerned with the slightly different auto upgrade logic: KeyChainGroup won't do an - // on-demand auto upgrade of the wallet to HD even in the unencrypted case, because the key rotation time is - // a property of the Wallet, not the KeyChainGroup (it should perhaps be moved at some point - it doesn't matter - // much where it goes). Wallet on the other hand will try to auto-upgrade you when possible. - - // Create an old-style random wallet. - KeyChainGroup group = new KeyChainGroup(params); - group.importKeys(new ECKey(), new ECKey()); - wallet = new Wallet(params, group); - assertTrue(wallet.isDeterministicUpgradeRequired()); - // Use an HD feature. - wallet.freshReceiveKey(); - assertFalse(wallet.isDeterministicUpgradeRequired()); - } - - @Test - public void upgradeToHDEncrypted() throws Exception { - // Create an old-style random wallet. - KeyChainGroup group = new KeyChainGroup(params); - group.importKeys(new ECKey(), new ECKey()); - wallet = new Wallet(params, group); - assertTrue(wallet.isDeterministicUpgradeRequired()); - KeyCrypter crypter = new KeyCrypterScrypt(); - KeyParameter aesKey = crypter.deriveKey("abc"); - wallet.encrypt(crypter, aesKey); - try { - wallet.freshReceiveKey(); - } catch (DeterministicUpgradeRequiresPassword e) { - // Expected. - } - wallet.upgradeToDeterministic(aesKey); - assertFalse(wallet.isDeterministicUpgradeRequired()); - wallet.freshReceiveKey(); // works. - } - - @Test(expected = IllegalStateException.class) - public void shouldNotAddTransactionSignerThatIsNotReady() throws Exception { - wallet.addTransactionSigner(new NopTransactionSigner(false)); - } - - @Test - public void transactionSignersShouldBeSerializedAlongWithWallet() throws Exception { - TransactionSigner signer = new NopTransactionSigner(true); - wallet.addTransactionSigner(signer); - assertEquals(2, wallet.getTransactionSigners().size()); - wallet = roundTrip(wallet); - assertEquals(2, wallet.getTransactionSigners().size()); - assertTrue(wallet.getTransactionSigners().get(1).isReady()); - } - - @Test - public void watchingMarriedWallet() throws Exception { - DeterministicKey watchKey = wallet.getWatchingKey(); - String serialized = watchKey.serializePubB58(params); - watchKey = DeterministicKey.deserializeB58(null, serialized, params); - Wallet wallet = Wallet.fromWatchingKey(params, watchKey); - blockStore = new MemoryBlockStore(params); - chain = new BlockChain(params, wallet, blockStore); - - final DeterministicKeyChain keyChain = new DeterministicKeyChain(new SecureRandom()); - DeterministicKey partnerKey = DeterministicKey.deserializeB58(null, keyChain.getWatchingKey().serializePubB58(params), params); - - TransactionSigner signer = new StatelessTransactionSigner() { - @Override - public boolean isReady() { - return true; - } - - @Override - public boolean signInputs(ProposedTransaction propTx, KeyBag keyBag) { - assertEquals(propTx.partialTx.getInputs().size(), propTx.keyPaths.size()); - List externalZeroLeaf = ImmutableList.builder() - .addAll(DeterministicKeyChain.EXTERNAL_PATH).add(ChildNumber.ZERO).build(); - for (TransactionInput input : propTx.partialTx.getInputs()) { - List keypath = propTx.keyPaths.get(input.getConnectedOutput().getScriptPubKey()); - assertNotNull(keypath); - assertEquals(externalZeroLeaf, keypath); - } - return true; - } - }; - wallet.addTransactionSigner(signer); - MarriedKeyChain chain = MarriedKeyChain.builder() - .random(new SecureRandom()) - .followingKeys(partnerKey) - .build(); - wallet.addAndActivateHDChain(chain); - - myAddress = wallet.currentAddress(KeyChain.KeyPurpose.RECEIVE_FUNDS); - sendMoneyToWallet(wallet, COIN, myAddress, AbstractBlockChain.NewBlockType.BEST_CHAIN); - - ECKey dest = new ECKey(); - Wallet.SendRequest req = Wallet.SendRequest.emptyWallet(dest.toAddress(params)); - req.missingSigsMode = Wallet.MissingSigsMode.USE_DUMMY_SIG; - wallet.completeTx(req); - } - - @Test - public void sendRequestExchangeRate() throws Exception { - receiveATransaction(wallet, myAddress); - SendRequest sendRequest = SendRequest.to(myAddress, Coin.COIN); - sendRequest.exchangeRate = new ExchangeRate(Fiat.parseFiat("EUR", "500")); - wallet.completeTx(sendRequest); - assertEquals(sendRequest.exchangeRate, sendRequest.tx.getExchangeRate()); - } - - @Test - public void sendRequestMemo() throws Exception { - receiveATransaction(wallet, myAddress); - SendRequest sendRequest = SendRequest.to(myAddress, Coin.COIN); - sendRequest.memo = "memo"; - wallet.completeTx(sendRequest); - assertEquals(sendRequest.memo, sendRequest.tx.getMemo()); - } - - @Test(expected = java.lang.IllegalStateException.class) - public void sendCoinsNoBroadcasterTest() throws InsufficientMoneyException { - ECKey key = ECKey.fromPrivate(BigInteger.TEN); - Address notMyAddr = key.toAddress(params); - SendRequest req = SendRequest.to(notMyAddr.getParameters(), key, SATOSHI.multiply(12)); - wallet.sendCoins(req); - } - - @Test - public void sendCoinsWithBroadcasterTest() throws InsufficientMoneyException { - ECKey key = ECKey.fromPrivate(BigInteger.TEN); - Address notMyAddr = key.toAddress(params); - receiveATransactionAmount(wallet, myAddress, Coin.COIN); - MockTransactionBroadcaster broadcaster = new MockTransactionBroadcaster(wallet); - wallet.setTransactionBroadcaster(broadcaster); - SendRequest req = SendRequest.to(notMyAddr.getParameters(), key, Coin.CENT); - wallet.sendCoins(req); - } - - @Test - public void fromKeys() { - ECKey key = ECKey.fromPrivate(Utils.HEX.decode("00905b93f990267f4104f316261fc10f9f983551f9ef160854f40102eb71cffdcc")); - Wallet wallet = Wallet.fromKeys(params, Arrays.asList(key)); - assertEquals(1, wallet.getImportedKeys().size()); - assertEquals(key, wallet.getImportedKeys().get(0)); - wallet.upgradeToDeterministic(null); - String seed = wallet.getKeyChainSeed().toHexString(); - assertEquals("5ca8cd6c01aa004d3c5396c628b78a4a89462f412f460a845b594ac42eceaa264b0e14dcd4fe73d4ed08ce06f4c28facfa85042d26d784ab2798a870bb7af556", seed); - } -} diff --git a/src/test/java/org/altcoinj/core/AuxPoWTest.java b/src/test/java/org/bitcoinj/core/AuxPoWTest.java similarity index 93% rename from src/test/java/org/altcoinj/core/AuxPoWTest.java rename to src/test/java/org/bitcoinj/core/AuxPoWTest.java index 5fbbff3c..ddedd559 100644 --- a/src/test/java/org/altcoinj/core/AuxPoWTest.java +++ b/src/test/java/org/bitcoinj/core/AuxPoWTest.java @@ -1,12 +1,9 @@ package org.bitcoinj.core; -import java.io.ByteArrayOutputStream; - import org.bitcoinj.params.TestNet3Params; -import org.junit.Before; import org.junit.Test; -import static org.bitcoinj.core.CoinbaseBlockTest.getBytes; +import static org.bitcoinj.core.Util.getBytes; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/org/bitcoinj/core/DogecoinBlockTest.java b/src/test/java/org/bitcoinj/core/DogecoinBlockTest.java index 7784a988..9eb929f3 100644 --- a/src/test/java/org/bitcoinj/core/DogecoinBlockTest.java +++ b/src/test/java/org/bitcoinj/core/DogecoinBlockTest.java @@ -86,7 +86,6 @@ public class DogecoinBlockTest { }; assertArrayEquals(expected, coinbaseMerkleBranch.getHashes().toArray(new Sha256Hash[coinbaseMerkleBranch.getSize()])); - System.out.println(block.toString()); assertEquals(6, block.getTransactions().size()); } } diff --git a/src/test/java/org/altcoinj/core/MerkleBranchTest.java b/src/test/java/org/bitcoinj/core/MerkleBranchTest.java similarity index 95% rename from src/test/java/org/altcoinj/core/MerkleBranchTest.java rename to src/test/java/org/bitcoinj/core/MerkleBranchTest.java index 8b2510d0..fa1f7473 100644 --- a/src/test/java/org/altcoinj/core/MerkleBranchTest.java +++ b/src/test/java/org/bitcoinj/core/MerkleBranchTest.java @@ -1,12 +1,10 @@ package org.bitcoinj.core; -import java.io.ByteArrayOutputStream; import org.bitcoinj.params.TestNet3Params; -import org.junit.Before; import org.junit.Test; -import static org.bitcoinj.core.CoinbaseBlockTest.getBytes; +import static org.bitcoinj.core.Util.getBytes; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; diff --git a/src/test/java/org/bitcoinj/core/Util.java b/src/test/java/org/bitcoinj/core/Util.java new file mode 100644 index 00000000..62907d52 --- /dev/null +++ b/src/test/java/org/bitcoinj/core/Util.java @@ -0,0 +1,35 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.bitcoinj.core; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * + * @author jrn + */ +public class Util { + + public static byte[] getBytes(InputStream inputStream) throws IOException { + assert null != inputStream; + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + int numberRead; + byte[] data = new byte[BUFFER_SIZE]; + + while ((numberRead = inputStream.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, numberRead); + } + + buffer.flush(); + + return buffer.toByteArray(); + } + private static final int BUFFER_SIZE = 1024; + +} diff --git a/src/test/resources/com/dogecoin/dogecoinj/core/block169482.dat b/src/test/resources/com/dogecoin/dogecoinj/core/block169482.dat deleted file mode 100644 index 9821206e..00000000 Binary files a/src/test/resources/com/dogecoin/dogecoinj/core/block169482.dat and /dev/null differ diff --git a/src/test/resources/com/dogecoin/dogecoinj/core/first-100k-blocks.dat b/src/test/resources/com/dogecoin/dogecoinj/core/first-100k-blocks.dat deleted file mode 100644 index 6cfef239..00000000 Binary files a/src/test/resources/com/dogecoin/dogecoinj/core/first-100k-blocks.dat and /dev/null differ diff --git a/src/test/resources/com/dogecoin/dogecoinj/core/sig_canonical.json b/src/test/resources/com/dogecoin/dogecoinj/core/sig_canonical.json deleted file mode 100644 index e43a0862..00000000 --- a/src/test/resources/com/dogecoin/dogecoinj/core/sig_canonical.json +++ /dev/null @@ -1,7 +0,0 @@ -[ - "300602010002010001", - "3008020200ff020200ff01", - "304402203932c892e2e550f3af8ee4ce9c215a87f9bb831dcac87b2838e2c2eaa891df0c022030b61dd36543125d56b9f9f3a1f9353189e5af33cdda8d77a5209aec03978fa001", - "30450220076045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01", - "3046022100876045be6f9eca28ff1ec606b833d0b87e70b2a630f5e3a496b110967a40f90a0221008fffd599910eefe00bc803c688c2eca1d2ba7f6b180620eaa03488e6585db6ba01" -] diff --git a/src/test/resources/com/dogecoin/dogecoinj/core/sig_noncanonical.json b/src/test/resources/com/dogecoin/dogecoinj/core/sig_noncanonical.json deleted file mode 100644 index d9a6c1cd..00000000 --- a/src/test/resources/com/dogecoin/dogecoinj/core/sig_noncanonical.json +++ /dev/null @@ -1,22 +0,0 @@ -[ - "non-hex strings are ignored", - - "too short:", "30050201FF020001", - "too long:", "30470221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105022200002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", - "hashtype:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed11", - "type:", "314402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", - "total length:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", - "S len oob:", "301F01205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb101", - "R+S:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed0001", - - "R type:", "304401205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", - "R len = 0:", "3024020002202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", - "R<0:", "304402208990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", - "R padded:", "30450221005990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610502202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", - - - "S type:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba610501202d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", - "S len = 0:", "302402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba6105020001", - "S<0:", "304402205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61050220fd5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01", - "S padded:", "304502205990e0584b2b238e1dfaad8d6ed69ecc1a4a13ac85fc0b31d0df395eb1ba61050221002d5876262c288beb511d061691bf26777344b702b00f8fe28621fe4e566695ed01" -] diff --git a/src/test/resources/com/dogecoin/dogecoinj/crypto/comodo-smime.crt b/src/test/resources/com/dogecoin/dogecoinj/crypto/comodo-smime.crt deleted file mode 100644 index 8f6d782a..00000000 --- a/src/test/resources/com/dogecoin/dogecoinj/crypto/comodo-smime.crt +++ /dev/null @@ -1,30 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFMTCCBBmgAwIBAgIQV2O4gJQ5NHgn/PPvDsU1djANBgkqhkiG9w0BAQUFADCB -kzELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxOTA3BgNV -BAMTMENPTU9ETyBDbGllbnQgQXV0aGVudGljYXRpb24gYW5kIFNlY3VyZSBFbWFp -bCBDQTAeFw0xNDAzMjkwMDAwMDBaFw0xNTAzMjkyMzU5NTlaMCkxJzAlBgkqhkiG -9w0BCQEWGGNvbW9kby5jb21Ac2NoaWxkYmFjaC5kZTCCASIwDQYJKoZIhvcNAQEB -BQADggEPADCCAQoCggEBAM61nbZo3ZN0Ojzn7UzoHBf07ZyTDm3KnwK4BdLKLgNS -NbGAJtgaYN91qKRbXf97VAFIN6FGhoXT+7MXSzlHgQHn7RkForMyREsD6F32TtyV -ZY9RuMGWjmPtABPRgeCVfNJNh9Hu87Uhhkj3Ma+H//ykfkJdDiOyBWIOJdjBFSZZ -M6bsZnyH8JCHqmxvK2qHpk+qNqpsNOZV83GYPA2gTFWd1AHjo5+A7W1Bo/qyJMrz -tpab0i+ieJPJdi6eJkMt3+nfr57Q2o4A3ZxH0Axq2D1a2dElhMK/JQilh2D+IDUp -VjoKkHgV9yji9UGOc3VHq+Sx8bNTumL7OFLCFYky9J8CAwEAAaOCAegwggHkMB8G -A1UdIwQYMBaAFHoTTgB0W8Z4Y2QnwS/ioFu8ecV7MB0GA1UdDgQWBBRWUNGbH8V3 -av0ESrIUwnvmq4aEEDAOBgNVHQ8BAf8EBAMCBaAwDAYDVR0TAQH/BAIwADAgBgNV -HSUEGTAXBggrBgEFBQcDBAYLKwYBBAGyMQEDBQIwEQYJYIZIAYb4QgEBBAQDAgUg -MEYGA1UdIAQ/MD0wOwYMKwYBBAGyMQECAQEBMCswKQYIKwYBBQUHAgEWHWh0dHBz -Oi8vc2VjdXJlLmNvbW9kby5uZXQvQ1BTMFcGA1UdHwRQME4wTKBKoEiGRmh0dHA6 -Ly9jcmwuY29tb2RvY2EuY29tL0NPTU9ET0NsaWVudEF1dGhlbnRpY2F0aW9uYW5k -U2VjdXJlRW1haWxDQS5jcmwwgYgGCCsGAQUFBwEBBHwwejBSBggrBgEFBQcwAoZG -aHR0cDovL2NydC5jb21vZG9jYS5jb20vQ09NT0RPQ2xpZW50QXV0aGVudGljYXRp -b25hbmRTZWN1cmVFbWFpbENBLmNydDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au -Y29tb2RvY2EuY29tMCMGA1UdEQQcMBqBGGNvbW9kby5jb21Ac2NoaWxkYmFjaC5k -ZTANBgkqhkiG9w0BAQUFAAOCAQEAMFhmP1Zy16m5L9gaGCDy847tJI3btBFFZMu/ -MMqamC5515QayLfwf9K2nmu1W63nehEAKqNw+PR1xTYnhPT4fopw5zFndiNg0L5u -blEbRgSdQYBh1I2dkzzPRDRJig4LfxVzRzL66FbllLEiJ6oR/XgdsH+JFgyjhk3Y -uJt+29sXoZ+ZR29d7l07OikQGI0HWCmp/UiwBcQ4dcTrDB72JYLHyli+OTAkcu9I -rBpsIbWJq+7NjaQ/8CJjvQ2neTgDS1Dq5DzMqqRlhxQwRl4dhfCSCcF81Vf0as4S -vVDNR8vJ9puGlYyGVJHhQ6mEoFEIvpetS7E9ELHnybSC9ev8CA== ------END CERTIFICATE----- diff --git a/src/test/resources/com/dogecoin/dogecoinj/crypto/startssl-client.crt b/src/test/resources/com/dogecoin/dogecoinj/crypto/startssl-client.crt deleted file mode 100644 index 44bed530..00000000 --- a/src/test/resources/com/dogecoin/dogecoinj/crypto/startssl-client.crt +++ /dev/null @@ -1,41 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIHPjCCBiagAwIBAgICH8wwDQYJKoZIhvcNAQEFBQAwgYwxCzAJBgNVBAYTAklM -MRYwFAYDVQQKEw1TdGFydENvbSBMdGQuMSswKQYDVQQLEyJTZWN1cmUgRGlnaXRh -bCBDZXJ0aWZpY2F0ZSBTaWduaW5nMTgwNgYDVQQDEy9TdGFydENvbSBDbGFzcyAx -IFByaW1hcnkgSW50ZXJtZWRpYXRlIENsaWVudCBDQTAeFw0wODA2MjIyMzA4MTJa -Fw0wOTA2MjIyMzA4MTJaMIHEMQswCQYDVQQGEwJERTEPMA0GA1UECBMGQmF5ZXJu -MREwDwYDVQQHEwhNdWVuY2hlbjEbMBkGA1UEChMSQW5kcmVhcyBTY2hpbGRiYWNo -MR4wHAYDVQQLExVQZXJzb25hIG5vdCB2YWxpZGF0ZWQxKTAnBgNVBAMTIFN0YXJ0 -Q29tIEZyZWUgQ2VydGlmaWNhdGUgTWVtYmVyMSkwJwYJKoZIhvcNAQkBFhpzdGFy -dHNzbC5jb21Ac2NoaWxkYmFjaC5kZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBAOhtSryPHR3gB5E48JZS9y8R3A9I2gRGGon+kRLNh+LCAJJ1hm28Lr41 -leH0uApWs1WP//qzkXaFUoLlilu/XzkDU48J6HCeUq+7zkxFhq7UxK2lq7J1P8fH -tbKYSBWMfzZuVmwhrbaurggfCmq/o5/angbhN7Pn+aV1aPegjAKd8n94HVvVgzkp -DDYTA5vFbX/3241MIeKRU5InYw9KzXAC1aE0BYVM21f5Z/UQ+V4PEfXrSH9OHPVW -3GWasmjzR9h+/u1omJzejkXY6Ygd15tnmatqMoxRRVMWhWS9Hg7D+AgeiZNlEQZV -NTZxIiPA8618x51Wlq0XAiV5UvkMImECAwEAAaOCA24wggNqMAwGA1UdEwQFMAMC -AQAwCwYDVR0PBAQDAgSwMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDBDAd -BgNVHQ4EFgQUeMIc15HHtjl2TDpGnc9X2UkUV2EwgagGA1UdIwSBoDCBnYAUU3Lt -kpzg2ssBXHx+ljVO8tS4UYKhgYGkfzB9MQswCQYDVQQGEwJJTDEWMBQGA1UEChMN -U3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNh -dGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRo -b3JpdHmCAQ0wggFHBgNVHSAEggE+MIIBOjCCATYGCysGAQQBgbU3AQEFMIIBJTAu -BggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNzbC5jb20vcG9saWN5LnBkZjA0 -BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFydHNzbC5jb20vaW50ZXJtZWRpYXRl -LnBkZjCBvAYIKwYBBQUHAgIwga8wFBYNU3RhcnRDb20gTHRkLjADAgEBGoGWTGlt -aXRlZCBMaWFiaWxpdHksIHJlYWQgdGhlIHNlY3Rpb24gKkxlZ2FsIExpbWl0YXRp -b25zKiBvZiB0aGUgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUG9s -aWN5IGF2YWlsYWJsZSBhdCBodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3ku -cGRmMGMGA1UdHwRcMFowK6ApoCeGJWh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2Ny -dHUxLWNybC5jcmwwK6ApoCeGJWh0dHA6Ly9jcmwuc3RhcnRzc2wuY29tL2NydHUx -LWNybC5jcmwwgY4GCCsGAQUFBwEBBIGBMH8wOQYIKwYBBQUHMAGGLWh0dHA6Ly9v -Y3NwLnN0YXJ0c3NsLmNvbS9zdWIvY2xhc3MxL2NsaWVudC9jYTBCBggrBgEFBQcw -AoY2aHR0cDovL3d3dy5zdGFydHNzbC5jb20vY2VydHMvc3ViLmNsYXNzMS5jbGll -bnQuY2EuY3J0MCMGA1UdEgQcMBqGGGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tLzAN -BgkqhkiG9w0BAQUFAAOCAQEAIsKaduVCShmIKRsUCqTSeJSDIjgSdRiRmvDig+vT -NkRrfhZhtpkp03lfe71agFlaV6UWtFF2nrgFaoUmq2KxMnCD1gkQPQu01TqrDDwi -+dKFkh4tSGyj++BRCX4jpYgY7pDzh0Dtb261ovpzYB3e36mMO4AiLHby10VHir+k -AUI87JVffsgsKCEEEkywA//KcXqyVfgW3FgicNczCiwXdWCLJcnBAq8aundebdIH -hTFoWB/5BuRRCY2Je9XFR8vb1EUC5SuTL+wT0mGdx2T+qNskNtbZKyHLQSp9fCoD -yupR1THhr7iqF4zRI6r5r8tRuu8jr55NgN5ZA+LCisEJ7A== ------END CERTIFICATE----- diff --git a/src/test/resources/com/dogecoin/dogecoinj/crypto/startssl-smime.crt b/src/test/resources/com/dogecoin/dogecoinj/crypto/startssl-smime.crt deleted file mode 100644 index ac8ae271..00000000 --- a/src/test/resources/com/dogecoin/dogecoinj/crypto/startssl-smime.crt +++ /dev/null @@ -1,40 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIHFDCCBfygAwIBAgIDAILwMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ -TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0 -YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg -MSBQcmltYXJ5IEludGVybWVkaWF0ZSBDbGllbnQgQ0EwHhcNMDkwNjA5MDAwMDAx -WhcNMTAwNjA5MjM1OTU5WjB2MR4wHAYDVQQKExVQZXJzb25hIE5vdCBWYWxpZGF0 -ZWQxKTAnBgNVBAMTIFN0YXJ0Q29tIEZyZWUgQ2VydGlmaWNhdGUgTWVtYmVyMSkw -JwYJKoZIhvcNAQkBFhpzdGFydHNzbC5jb21Ac2NoaWxkYmFjaC5kZTCCASIwDQYJ -KoZIhvcNAQEBBQADggEPADCCAQoCggEBALA4dtu1FlTbhZQ+M9pyTFte40zotk3J -fqvEkDpWLBz3orN4SkMAUDOgTWdvNm+PakX2tEsZGD+nnWzkO3NI8x5ZhrOF3HwW -zeCaYzaDjhhRw4G1K2FKVBHK6TUkZ/LoLimVMsV8AbsAWWlmxTCXB1vyoiOMISiK -rMFsRFAQdtB5wHVuZdtVnO1++yLfQo+ckuTT35RBztpcP63GkVyo0ucFC8DxNQOA -+k8cEIVrfsr9PrLUlhTx+P5jQAaURqcVf0IAR6bNV7WdJmli7yjlWeQm7ymh8YFE -6xsy16TO24GQWR5waBFRqGaJPqRnpAdhiUc+1nbNGuaOYYCD6kATVycCAwEAAaOC -A5IwggOOMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdJQQWMBQGCCsGAQUF -BwMCBggrBgEFBQcDBDAdBgNVHQ4EFgQUY819Gv9zSrHpLGP3e9WbCJfzEgAwJQYD -VR0RBB4wHIEac3RhcnRzc2wuY29tQHNjaGlsZGJhY2guZGUwgagGA1UdIwSBoDCB -nYAUU3Ltkpzg2ssBXHx+ljVO8tS4UYKhgYGkfzB9MQswCQYDVQQGEwJJTDEWMBQG -A1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwgQ2Vy -dGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNhdGlv -biBBdXRob3JpdHmCAQ0wggFHBgNVHSAEggE+MIIBOjCCATYGCysGAQQBgbU3AQIA -MIIBJTAuBggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNzbC5jb20vcG9saWN5 -LnBkZjA0BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFydHNzbC5jb20vaW50ZXJt -ZWRpYXRlLnBkZjCBvAYIKwYBBQUHAgIwga8wFBYNU3RhcnRDb20gTHRkLjADAgEB -GoGWTGltaXRlZCBMaWFiaWxpdHksIHJlYWQgdGhlIHNlY3Rpb24gKkxlZ2FsIExp -bWl0YXRpb25zKiBvZiB0aGUgU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3Jp -dHkgUG9saWN5IGF2YWlsYWJsZSBhdCBodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9w -b2xpY3kucGRmMGMGA1UdHwRcMFowK6ApoCeGJWh0dHA6Ly93d3cuc3RhcnRzc2wu -Y29tL2NydHUxLWNybC5jcmwwK6ApoCeGJWh0dHA6Ly9jcmwuc3RhcnRzc2wuY29t -L2NydHUxLWNybC5jcmwwgY4GCCsGAQUFBwEBBIGBMH8wOQYIKwYBBQUHMAGGLWh0 -dHA6Ly9vY3NwLnN0YXJ0c3NsLmNvbS9zdWIvY2xhc3MxL2NsaWVudC9jYTBCBggr -BgEFBQcwAoY2aHR0cDovL3d3dy5zdGFydHNzbC5jb20vY2VydHMvc3ViLmNsYXNz -MS5jbGllbnQuY2EuY3J0MCMGA1UdEgQcMBqGGGh0dHA6Ly93d3cuc3RhcnRzc2wu -Y29tLzANBgkqhkiG9w0BAQUFAAOCAQEAaJgOEPjkRcKMVbbofA+GVlc1iMR+kJHk -bQNmojAmgDL1pXabFuNZqx7FVUBk7MQQOUaC1vd3RbyOE+AzdXaq7/pFk5/Zxalv -xn4gSA/wGHDB0oAi+efWQy7ZsskIOWkjg7tKqy0KCRlA6ZlQhL0aTFZe2X6fu/fI -eebFb6gQ3vhOwIgAGz7CZMjRBqPjiqpPrD/Uac2LORUdLw/wowTV1YBnNwsZGnzJ -/WquZB7n/yJjaSqhSL0s37AOg3TvXEXYS2GpoA02lQKfq3Lo86piAxSh7aJf7dpT -JMVnE6/+5FyjpP8Hpl8FARv1m51c9n788cDzS4/qFibKf9s6yt1/0A== ------END CERTIFICATE----- diff --git a/src/test/resources/com/dogecoin/dogecoinj/protocols/payments/README b/src/test/resources/com/dogecoin/dogecoinj/protocols/payments/README deleted file mode 100644 index 024eb16d..00000000 --- a/src/test/resources/com/dogecoin/dogecoinj/protocols/payments/README +++ /dev/null @@ -1,6 +0,0 @@ -# Create key store for CA certificate -keytool -keystore test-cacerts -importcert -file test-cacert.pem -alias test-cacert -deststorepass password - -# Create key store for certificate and private key -openssl pkcs12 -export -in test-valid-cert.pem -inkey test-valid-key.pem -passin pass:password -out test-valid.p12 -passout pass:password -name test-valid -keytool -importkeystore -deststorepass password -destkeypass password -destkeystore test-valid-cert -srckeystore test-valid.p12 -srcstoretype PKCS12 -srcstorepass password -alias test-valid diff --git a/src/test/resources/com/dogecoin/dogecoinj/protocols/payments/pki_test.bitcoinpaymentrequest b/src/test/resources/com/dogecoin/dogecoinj/protocols/payments/pki_test.bitcoinpaymentrequest deleted file mode 100644 index a7390377..00000000 Binary files a/src/test/resources/com/dogecoin/dogecoinj/protocols/payments/pki_test.bitcoinpaymentrequest and /dev/null differ diff --git a/src/test/resources/com/dogecoin/dogecoinj/protocols/payments/test-cacert.key b/src/test/resources/com/dogecoin/dogecoinj/protocols/payments/test-cacert.key deleted file mode 100644 index 0fd86807..00000000 --- a/src/test/resources/com/dogecoin/dogecoinj/protocols/payments/test-cacert.key +++ /dev/null @@ -1,54 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -Proc-Type: 4,ENCRYPTED -DEK-Info: DES-EDE3-CBC,621C9B6A0E9C192A - -zj5A0/qeYJ5rmvJqcNoQxaUyEonVZQgLj9Jxw76Wvc1kIMNXsT7MGq2jHaDaUMVd -LZDhRgNtirGVdfMFvsNGMB+F1SDq3Dftn/w1jKsNRwCXR958r7ciYp37ohldTEuX -0rPQfltHQHkwpCDfi7xOQa06wdSA+Ke8Sek9u77RRhT+nEWOLwJHaIyIbSQr835q -bcdW7oTFpAj7OQnEgpKMi2fU9t89N4X+F3foarfSwWGP+e8o9J7/UKKmrWGkB30Q -H3U4CbZTXP07ti+ALh86/UaBdaZdDp/pXcJK9OyRSUw693NutSRFw5bXcbobessG -lRcgJ5lrKy3F4WhyZMCQNTgr3LzymVn4DkBI3aNCI3a3hbIUi6BRyLF2zUZan5Pl -IhsTQM4HLGpuq1AfbWwPvSWoTh+uI9qM9Fenc9kwZvkiMYDf+7kiY6Pt0e8gg16j -QQoemZeI+TivyBVerUPV1j+0eBru6ogdxiWoBmZFTFjwpqObV05Zm1BxVAjp3x3+ -q2gzaYdV/Gca0IaHnmqlZQHwWv5Z0+79bGFta2ThiUR+7Ofgteh0ojlAmAvpHp0n -cy6NNr4T81z6QpsHM1zeKbiuUgLlCchwEH0fCsHl0u/EJ7i+4bbugyTdAUiULqxH -OpHU2FpuNvSS6BZc2fCmdPflG9yP1jOoAEKb7bcdPRfiJoyMf/ngNaSXsrjzs7NA -Z2fZyKC45wtmfpfcQuHP+svWafDx3DCNhQ7Wo7YFBFacV242cjLaYnkgy8XHFHjM -KW1Wct5Xg5FEnEcyhczLTZbylSwap9vTAk65cUjLmp/7fE8pLKGfvdRA6VLfbJQ/ -lnJvBI8valjtCfEMC8s5dNcsn7ISFyTzKMaxjs8DxBRg5eKwr/BPVeXkP21Cf+sO -OUAZcgOBJxhb/MQ68Rx2pcjTbmOG81LINkCrwfNGez1gVg3CELneIZGi2ZSn2s5r -tFXVJvCrUpSGvx3IC4xKXJ6R6euBE7JdxG0J8aizytlorEhSk294ksupEQUjdeEW -RPHqp3LqVlRO1tFYZQrwZs26vgXa15LYXq63EewUCIM4TjNTm3FuovW1d11mCiFl -dljkCMGYN+14YnHzd3G96JGxkZUlOCFN+y5Xa2I1x4jkUCvdD3gfMXBxGptkyT+K -DlJJQ8JMrRMhRu2K/t8LVorPyHGoYRUoaXLgx/x8xgazLiA8vY8sCJ9A+YM78Bjd -ytGQeuUzt5syAXuW3s6AStuMH0Scos674i0qcsd2j5TY4Td6+svuCluvKvsmWW4/ -pDPNW5c/TXMVU3J9H1AnuHoNQ7rX9++qbptOQHXsf2MY9HtgzYDuY4i/vmJFtTVe -zbUqh3trTJ/ihvzq6to6b/AZqsljit7PzLBkXlmQozvlAqy3ycWvyFnVjPgjyEm5 -9C3uwnD4hiXfmf46nMv+YkaAhYESavLKkbcdQ+cONYnQ2zTJJaKLMHbl+TI5Tjph -azuTmQKG72/V8aQBbIVgppoN7FtlIAvZl+k48uZAj2uN7/15ceIBP9Vh0O07EmNa -birsXDWm2naQNKYBGrbMCRol8NSnqT3MvG075uZ0mXcyKO39YNxJmdfYgQohTosC -dYD20mqdYKbygtvjfucXJoEUJKcB2I795XeZoZl32JgoE0h7q7gLtnUrSnyw8YVo -C4s4DL9wXaxuReXQVGczHwPtW9X1Hjm07iuBbkb10Adbl03bd+5J4XbVtdjlshOw -YVXHXLY5NfS+hu6jErxNNDjHY0lT+rwif4S9eBjepnpXyZWQRwoJ3SooyK9D6YR4 -4wpxc4JEglXOPtzqjErGBYxZZdZSD04eVjDV22+Hf6GVcFyEjEFqaEMl0NzOyi+n -Svf7ixeo6x3xfUnx9T0mv4YqP62t/RkM9nkFcwKQkZ59cNw+/7XD6DgxO6ev5/25 -DemqP83feR2MEgwwfh2txi9N5WM0/zJhfxbyv3hImfKa6Br2UoC3O57uKyRVEQ+7 -dP6wOjJ5swe6kCvk4yj60V/Vr0urVW8xC6IN+2FIfiocJS8mIY5NZRd0CbNkiuZP -ntVJwgQ2xwbIOp/+4Od3vBI6ujWmXyaR8k9EpnhM5wP7fb38PprxKdLjRLuGEPNP -Z+Cov09oh6cR1GrBqM/gH3mggLZgO4h4WD8gKFkmepXit9Xcigd0ytXfDWE2jgx8 -du41SrDqYOwVwbkarRA9NDf5Db9dm/vNnw31/cVwUq10Mb7QD/wXPwSIpQbvyJBt -1tYcH983hNFKQddNRm+hBP9Vz+nhHPneGjTKU6SxDMcQ3Baep3DwRPl9r9x09z0Y -xkBUcCUZ5q+wgFepXYCB9lOBtATnFViFnTdvQuXqvLeOWDjAHBT3TDxzaB+vJMal -qD+S4x3BSO64ZIxepl4CHa1Zajp8qzVWYh1rBlTL/Uqjg3O5MuvfO0DGpRCn/6t0 -CpJF/bcmRBogOvNM7zjMcDSRtIMOVgsfCqqIyXpvA5yZqocwd2o8tdiG0hKQxASV -qxvTNTXQZut/xD0enHtDaoYYTHj2c6Ayu7DZfPHvcx40mdYjGI9ZKvXcSrYkfTqc -mugXa29jah+1abRWfokV/0S9xuFTkBGPt8/Byw4oT7e8nkJGFQorObqj4gSJhCOf -/+wTqhkappSHM0mkF72mNqJLWqMPGFnUq/5x5hws3qNgDbk48TDMWKyM3UEn8IUb -zQViQNNVRxtZGTXO8Yhpqv/LgD3I9nk99xFALcBncrkrBIK121pVVM1Yf4TjsdCx -zqykQY0cghi6zVE8wkDj6f7Sh8uYe5fP1gorp0rzxyKQh1RwsI6po3GmAA12aIiX -3Z5XHE3qL7zeaiN0Mc8EkA7zVVI5Id8Wssdmf3TWRG36J99qzUWxiMsL3lKvgi9d -X5Bbxo5l+3hdC31jqrt1w2vemr4bSs5SyBQMnBL2HEsbk7PWzbxD/NdKWYecyYAz -OtFy7vAtURxYvS0IbX4uRoeAehyJ7+Ak7tulM4MG9O+w/WseBV7VS1beI9NLZg3S -tLLTc/EyLsR9us5AMjDeuIoOSN4mEtFzlq72nyVbUGELN7fXl8Hv75QYh7/SUZt4 -nH+DbSxMon0SybKTywuwuSoFo/K2lwfyZvNb4R0ImlPpJobANG0knKgzKCTA+m5P ------END RSA PRIVATE KEY----- diff --git a/src/test/resources/com/dogecoin/dogecoinj/protocols/payments/test-cacerts b/src/test/resources/com/dogecoin/dogecoinj/protocols/payments/test-cacerts deleted file mode 100644 index c10128f6..00000000 Binary files a/src/test/resources/com/dogecoin/dogecoinj/protocols/payments/test-cacerts and /dev/null differ diff --git a/src/test/resources/com/dogecoin/dogecoinj/protocols/payments/test-expired-cert b/src/test/resources/com/dogecoin/dogecoinj/protocols/payments/test-expired-cert deleted file mode 100644 index a6d7ac53..00000000 Binary files a/src/test/resources/com/dogecoin/dogecoinj/protocols/payments/test-expired-cert and /dev/null differ diff --git a/src/test/resources/com/dogecoin/dogecoinj/protocols/payments/test-valid-cert b/src/test/resources/com/dogecoin/dogecoinj/protocols/payments/test-valid-cert deleted file mode 100644 index e9f00671..00000000 Binary files a/src/test/resources/com/dogecoin/dogecoinj/protocols/payments/test-valid-cert and /dev/null differ diff --git a/src/test/resources/com/dogecoin/dogecoinj/script/script_invalid.json b/src/test/resources/com/dogecoin/dogecoinj/script/script_invalid.json deleted file mode 100644 index 75de4716..00000000 --- a/src/test/resources/com/dogecoin/dogecoinj/script/script_invalid.json +++ /dev/null @@ -1,377 +0,0 @@ -[ -["", "DEPTH", "P2SH,STRICTENC", "Test the test: we should have an empty stack after scriptSig evaluation"], -[" ", "DEPTH", "P2SH,STRICTENC", "and multiple spaces should not change that."], -[" ", "DEPTH", "P2SH,STRICTENC"], -[" ", "DEPTH", "P2SH,STRICTENC"], - -["", "", "P2SH,STRICTENC"], -["", "NOP", "P2SH,STRICTENC"], -["", "NOP DEPTH", "P2SH,STRICTENC"], -["NOP", "", "P2SH,STRICTENC"], -["NOP", "DEPTH", "P2SH,STRICTENC"], -["NOP","NOP", "P2SH,STRICTENC"], -["NOP","NOP DEPTH", "P2SH,STRICTENC"], - -["DEPTH", "", "P2SH,STRICTENC"], - -["0x4c01","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA1 with not enough bytes"], -["0x4d0200ff","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA2 with not enough bytes"], -["0x4e03000000ffff","0x01 NOP", "P2SH,STRICTENC", "PUSHDATA4 with not enough bytes"], - -["1", "IF 0x50 ENDIF 1", "P2SH,STRICTENC", "0x50 is reserved"], -["0x52", "0x5f ADD 0x60 EQUAL", "P2SH,STRICTENC", "0x51 through 0x60 push 1 through 16 onto stack"], -["0","NOP", "P2SH,STRICTENC"], -["1", "IF VER ELSE 1 ENDIF", "P2SH,STRICTENC", "VER non-functional"], -["0", "IF VERIF ELSE 1 ENDIF", "P2SH,STRICTENC", "VERIF illegal everywhere"], -["0", "IF ELSE 1 ELSE VERIF ENDIF", "P2SH,STRICTENC", "VERIF illegal everywhere"], -["0", "IF VERNOTIF ELSE 1 ENDIF", "P2SH,STRICTENC", "VERNOTIF illegal everywhere"], -["0", "IF ELSE 1 ELSE VERNOTIF ENDIF", "P2SH,STRICTENC", "VERNOTIF illegal everywhere"], - -["1 IF", "1 ENDIF", "P2SH,STRICTENC", "IF/ENDIF can't span scriptSig/scriptPubKey"], -["1 IF 0 ENDIF", "1 ENDIF", "P2SH,STRICTENC"], -["1 ELSE 0 ENDIF", "1", "P2SH,STRICTENC"], -["0 NOTIF", "123", "P2SH,STRICTENC"], - -["0", "DUP IF ENDIF", "P2SH,STRICTENC"], -["0", "IF 1 ENDIF", "P2SH,STRICTENC"], -["0", "DUP IF ELSE ENDIF", "P2SH,STRICTENC"], -["0", "IF 1 ELSE ENDIF", "P2SH,STRICTENC"], -["0", "NOTIF ELSE 1 ENDIF", "P2SH,STRICTENC"], - -["0 1", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], -["0 0", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], -["1 0", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], -["0 1", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], - -["0 0", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], -["0 1", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], -["1 1", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], -["0 0", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], - -["1", "IF RETURN ELSE ELSE 1 ENDIF", "P2SH,STRICTENC", "Multiple ELSEs"], -["1", "IF 1 ELSE ELSE RETURN ENDIF", "P2SH,STRICTENC"], - -["1", "ENDIF", "P2SH,STRICTENC", "Malformed IF/ELSE/ENDIF sequence"], -["1", "ELSE ENDIF", "P2SH,STRICTENC"], -["1", "ENDIF ELSE", "P2SH,STRICTENC"], -["1", "ENDIF ELSE IF", "P2SH,STRICTENC"], -["1", "IF ELSE ENDIF ELSE", "P2SH,STRICTENC"], -["1", "IF ELSE ENDIF ELSE ENDIF", "P2SH,STRICTENC"], -["1", "IF ENDIF ENDIF", "P2SH,STRICTENC"], -["1", "IF ELSE ELSE ENDIF ENDIF", "P2SH,STRICTENC"], - -["1", "RETURN", "P2SH,STRICTENC"], -["1", "DUP IF RETURN ENDIF", "P2SH,STRICTENC"], - -["1", "RETURN 'data'", "P2SH,STRICTENC", "canonical prunable txout format"], -["0 IF", "RETURN ENDIF 1", "P2SH,STRICTENC", "still prunable because IF/ENDIF can't span scriptSig/scriptPubKey"], - -["0", "VERIFY 1", "P2SH,STRICTENC"], -["1", "VERIFY", "P2SH,STRICTENC"], -["1", "VERIFY 0", "P2SH,STRICTENC"], - -["1 TOALTSTACK", "FROMALTSTACK 1", "P2SH,STRICTENC", "alt stack not shared between sig/pubkey"], - -["IFDUP", "DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["DROP", "DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["DUP", "DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["1", "DUP 1 ADD 2 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC"], -["NOP", "NIP", "P2SH,STRICTENC"], -["NOP", "1 NIP", "P2SH,STRICTENC"], -["NOP", "1 0 NIP", "P2SH,STRICTENC"], -["NOP", "OVER 1", "P2SH,STRICTENC"], -["1", "OVER", "P2SH,STRICTENC"], -["0 1", "OVER DEPTH 3 EQUALVERIFY", "P2SH,STRICTENC"], -["19 20 21", "PICK 19 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], -["NOP", "0 PICK", "P2SH,STRICTENC"], -["1", "-1 PICK", "P2SH,STRICTENC"], -["19 20 21", "0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"], -["19 20 21", "1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"], -["19 20 21", "2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"], -["NOP", "0 ROLL", "P2SH,STRICTENC"], -["1", "-1 ROLL", "P2SH,STRICTENC"], -["19 20 21", "0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], -["19 20 21", "1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], -["19 20 21", "2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], -["NOP", "ROT 1", "P2SH,STRICTENC"], -["NOP", "1 ROT 1", "P2SH,STRICTENC"], -["NOP", "1 2 ROT 1", "P2SH,STRICTENC"], -["NOP", "0 1 2 ROT", "P2SH,STRICTENC"], -["NOP", "SWAP 1", "P2SH,STRICTENC"], -["1", "SWAP 1", "P2SH,STRICTENC"], -["0 1", "SWAP 1 EQUALVERIFY", "P2SH,STRICTENC"], -["NOP", "TUCK 1", "P2SH,STRICTENC"], -["1", "TUCK 1", "P2SH,STRICTENC"], -["1 0", "TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP", "P2SH,STRICTENC"], -["NOP", "2DUP 1", "P2SH,STRICTENC"], -["1", "2DUP 1", "P2SH,STRICTENC"], -["NOP", "3DUP 1", "P2SH,STRICTENC"], -["1", "3DUP 1", "P2SH,STRICTENC"], -["1 2", "3DUP 1", "P2SH,STRICTENC"], -["NOP", "2OVER 1", "P2SH,STRICTENC"], -["1", "2 3 2OVER 1", "P2SH,STRICTENC"], -["NOP", "2SWAP 1", "P2SH,STRICTENC"], -["1", "2 3 2SWAP 1", "P2SH,STRICTENC"], - -["'a' 'b'", "CAT", "P2SH,STRICTENC", "CAT disabled"], -["'a' 'b' 0", "IF CAT ELSE 1 ENDIF", "P2SH,STRICTENC", "CAT disabled"], -["'abc' 1 1", "SUBSTR", "P2SH,STRICTENC", "SUBSTR disabled"], -["'abc' 1 1 0", "IF SUBSTR ELSE 1 ENDIF", "P2SH,STRICTENC", "SUBSTR disabled"], -["'abc' 2 0", "IF LEFT ELSE 1 ENDIF", "P2SH,STRICTENC", "LEFT disabled"], -["'abc' 2 0", "IF RIGHT ELSE 1 ENDIF", "P2SH,STRICTENC", "RIGHT disabled"], - -["NOP", "SIZE 1", "P2SH,STRICTENC"], - -["'abc'", "IF INVERT ELSE 1 ENDIF", "P2SH,STRICTENC", "INVERT disabled"], -["1 2 0 IF AND ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "AND disabled"], -["1 2 0 IF OR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "OR disabled"], -["1 2 0 IF XOR ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "XOR disabled"], -["2 0 IF 2MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "2MUL disabled"], -["2 0 IF 2DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "2DIV disabled"], -["2 2 0 IF MUL ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "MUL disabled"], -["2 2 0 IF DIV ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "DIV disabled"], -["2 2 0 IF MOD ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "MOD disabled"], -["2 2 0 IF LSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "LSHIFT disabled"], -["2 2 0 IF RSHIFT ELSE 1 ENDIF", "NOP", "P2SH,STRICTENC", "RSHIFT disabled"], - -["0 1","EQUAL", "P2SH,STRICTENC"], -["1 1 ADD", "0 EQUAL", "P2SH,STRICTENC"], -["11 1 ADD 12 SUB", "11 EQUAL", "P2SH,STRICTENC"], - -["2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "arithmetic operands must be in range [-2^31...2^31] "], -["-2147483648 0 ADD", "NOP", "P2SH,STRICTENC", "arithmetic operands must be in range [-2^31...2^31] "], -["2147483647 DUP ADD", "4294967294 NUMEQUAL", "P2SH,STRICTENC", "NUMEQUAL must be in numeric range"], -["'abcdef' NOT", "0 EQUAL", "P2SH,STRICTENC", "NOT is an arithmetic operand"], - -["2 DUP MUL", "4 EQUAL", "P2SH,STRICTENC", "disabled"], -["2 DUP DIV", "1 EQUAL", "P2SH,STRICTENC", "disabled"], -["2 2MUL", "4 EQUAL", "P2SH,STRICTENC", "disabled"], -["2 2DIV", "1 EQUAL", "P2SH,STRICTENC", "disabled"], -["7 3 MOD", "1 EQUAL", "P2SH,STRICTENC", "disabled"], -["2 2 LSHIFT", "8 EQUAL", "P2SH,STRICTENC", "disabled"], -["2 1 RSHIFT", "1 EQUAL", "P2SH,STRICTENC", "disabled"], - -["1","NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 2 EQUAL", "P2SH,STRICTENC"], -["'NOP_1_to_10' NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_11' EQUAL", "P2SH,STRICTENC"], - -["0x50","1", "P2SH,STRICTENC", "opcode 0x50 is reserved"], -["1", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "opcodes above NOP10 invalid if executed"], -["1", "IF 0xbb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc1 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc2 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc3 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc4 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc5 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc6 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc7 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc8 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xc9 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xca ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xcb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xcc ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xcd ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xce ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xcf ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd1 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd2 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd3 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd4 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd5 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd6 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd7 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd8 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xd9 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xda ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xdb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xdc ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xdd ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xde ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xdf ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe1 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe2 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe3 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe4 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe5 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe6 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe7 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe8 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xe9 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xea ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xeb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xec ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xed ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xee ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xef ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf1 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf2 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf3 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf4 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf5 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf6 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf7 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf8 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xf9 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xfa ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xfb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xfc ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xfd ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xfe ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 0xff ELSE 1 ENDIF", "P2SH,STRICTENC"], - -["1 IF 1 ELSE", "0xff ENDIF", "P2SH,STRICTENC", "invalid because scriptSig and scriptPubKey are processed separately"], - -["NOP", "RIPEMD160", "P2SH,STRICTENC"], -["NOP", "SHA1", "P2SH,STRICTENC"], -["NOP", "SHA256", "P2SH,STRICTENC"], -["NOP", "HASH160", "P2SH,STRICTENC"], -["NOP", "HASH256", "P2SH,STRICTENC"], - -["NOP", -"'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'", -"P2SH,STRICTENC", -">520 byte push"], -["0", -"IF 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' ENDIF 1", -"P2SH,STRICTENC", -">520 byte push in non-executed IF branch"], -["1", -"0x61616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", -"P2SH,STRICTENC", -">201 opcodes executed. 0x61 is NOP"], -["0", -"IF 0x6161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161 ENDIF 1", -"P2SH,STRICTENC", -">201 opcodes including non-executed IF branch. 0x61 is NOP"], -["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", -"1 2 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", -"P2SH,STRICTENC", -">1,000 stack size (0x6f is 3DUP)"], -["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", -"1 TOALTSTACK 2 TOALTSTACK 3 4 5 6 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", -"P2SH,STRICTENC", -">1,000 stack+altstack size"], -["NOP", -"0 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", -"P2SH,STRICTENC", -"10,001-byte scriptPubKey"], - -["NOP1","NOP10", "P2SH,STRICTENC"], - -["1","VER", "P2SH,STRICTENC", "OP_VER is reserved"], -["1","VERIF", "P2SH,STRICTENC", "OP_VERIF is reserved"], -["1","VERNOTIF", "P2SH,STRICTENC", "OP_VERNOTIF is reserved"], -["1","RESERVED", "P2SH,STRICTENC", "OP_RESERVED is reserved"], -["1","RESERVED1", "P2SH,STRICTENC", "OP_RESERVED1 is reserved"], -["1","RESERVED2", "P2SH,STRICTENC", "OP_RESERVED2 is reserved"], -["1","0xba", "P2SH,STRICTENC", "0xba == OP_NOP10 + 1"], - -["2147483648", "1ADD 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers"], -["2147483648", "NEGATE 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers"], -["-2147483648", "1ADD 1", "P2SH,STRICTENC", "Because we use a sign bit, -2147483648 is also 5 bytes"], -["2147483647", "1ADD 1SUB 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers, even if the result is 4-bytes"], -["2147483648", "1SUB 1", "P2SH,STRICTENC", "We cannot do math on 5-byte integers, even if the result is 4-bytes"], - -["2147483648 1", "BOOLOR 1", "P2SH,STRICTENC", "We cannot do BOOLOR on 5-byte integers (but we can still do IF etc)"], -["2147483648 1", "BOOLAND 1", "P2SH,STRICTENC", "We cannot do BOOLAND on 5-byte integers"], - -["1", "1 ENDIF", "P2SH,STRICTENC", "ENDIF without IF"], -["1", "IF 1", "P2SH,STRICTENC", "IF without ENDIF"], -["1 IF 1", "ENDIF", "P2SH,STRICTENC", "IFs don't carry over"], - -["NOP", "IF 1 ENDIF", "P2SH,STRICTENC", "The following tests check the if(stack.size() < N) tests in each opcode"], -["NOP", "NOTIF 1 ENDIF", "P2SH,STRICTENC", "They are here to catch copy-and-paste errors"], -["NOP", "VERIFY 1", "P2SH,STRICTENC", "Most of them are duplicated elsewhere,"], - -["NOP", "TOALTSTACK 1", "P2SH,STRICTENC", "but, hey, more is always better, right?"], -["1", "FROMALTSTACK", "P2SH,STRICTENC"], -["1", "2DROP 1", "P2SH,STRICTENC"], -["1", "2DUP", "P2SH,STRICTENC"], -["1 1", "3DUP", "P2SH,STRICTENC"], -["1 1 1", "2OVER", "P2SH,STRICTENC"], -["1 1 1 1 1", "2ROT", "P2SH,STRICTENC"], -["1 1 1", "2SWAP", "P2SH,STRICTENC"], -["NOP", "IFDUP 1", "P2SH,STRICTENC"], -["NOP", "DROP 1", "P2SH,STRICTENC"], -["NOP", "DUP 1", "P2SH,STRICTENC"], -["1", "NIP", "P2SH,STRICTENC"], -["1", "OVER", "P2SH,STRICTENC"], -["1 1 1 3", "PICK", "P2SH,STRICTENC"], -["0", "PICK 1", "P2SH,STRICTENC"], -["1 1 1 3", "ROLL", "P2SH,STRICTENC"], -["0", "ROLL 1", "P2SH,STRICTENC"], -["1 1", "ROT", "P2SH,STRICTENC"], -["1", "SWAP", "P2SH,STRICTENC"], -["1", "TUCK", "P2SH,STRICTENC"], - -["NOP", "SIZE 1", "P2SH,STRICTENC"], - -["1", "EQUAL 1", "P2SH,STRICTENC"], -["1", "EQUALVERIFY 1", "P2SH,STRICTENC"], - -["NOP", "1ADD 1", "P2SH,STRICTENC"], -["NOP", "1SUB 1", "P2SH,STRICTENC"], -["NOP", "NEGATE 1", "P2SH,STRICTENC"], -["NOP", "ABS 1", "P2SH,STRICTENC"], -["NOP", "NOT 1", "P2SH,STRICTENC"], -["NOP", "0NOTEQUAL 1", "P2SH,STRICTENC"], - -["1", "ADD", "P2SH,STRICTENC"], -["1", "SUB", "P2SH,STRICTENC"], -["1", "BOOLAND", "P2SH,STRICTENC"], -["1", "BOOLOR", "P2SH,STRICTENC"], -["1", "NUMEQUAL", "P2SH,STRICTENC"], -["1", "NUMEQUALVERIFY 1", "P2SH,STRICTENC"], -["1", "NUMNOTEQUAL", "P2SH,STRICTENC"], -["1", "LESSTHAN", "P2SH,STRICTENC"], -["1", "GREATERTHAN", "P2SH,STRICTENC"], -["1", "LESSTHANOREQUAL", "P2SH,STRICTENC"], -["1", "GREATERTHANOREQUAL", "P2SH,STRICTENC"], -["1", "MIN", "P2SH,STRICTENC"], -["1", "MAX", "P2SH,STRICTENC"], -["1 1", "WITHIN", "P2SH,STRICTENC"], - -["NOP", "RIPEMD160 1", "P2SH,STRICTENC"], -["NOP", "SHA1 1", "P2SH,STRICTENC"], -["NOP", "SHA256 1", "P2SH,STRICTENC"], -["NOP", "HASH160 1", "P2SH,STRICTENC"], -["NOP", "HASH256 1", "P2SH,STRICTENC"], - -["", -"0 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG", -"P2SH,STRICTENC", -"202 CHECKMULTISIGS, fails due to 201 op limit"], - -["1", -"0 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY 0 0 CHECKMULTISIGVERIFY", -"P2SH,STRICTENC"], - -["", -"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG", -"P2SH,STRICTENC", -"Fails due to 201 sig op limit"], - -["1", -"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY", -"P2SH,STRICTENC"], - - -["0 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21", "21 CHECKMULTISIG 1", "P2SH,STRICTENC", "nPubKeys > 20"], -["0 'sig' 1 0", "CHECKMULTISIG 1", "P2SH,STRICTENC", "nSigs > nPubKeys"], - - -["NOP 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC", "Tests for Script.IsPushOnly()"], -["NOP1 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC"], - -["0 0x01 0x50", "HASH160 0x14 0xece424a6bb6ddf4db592c0faed60685047a361b1 EQUAL", "P2SH,STRICTENC", "OP_RESERVED in P2SH should fail"], -["0 0x01 VER", "HASH160 0x14 0x0f4d7845db968f2a81b530b6f3c1d6246d4c7e01 EQUAL", "P2SH,STRICTENC", "OP_VER in P2SH should fail"], - -["0x00", "'00' EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"] -] diff --git a/src/test/resources/com/dogecoin/dogecoinj/script/script_valid.json b/src/test/resources/com/dogecoin/dogecoinj/script/script_valid.json deleted file mode 100644 index c1db4c60..00000000 --- a/src/test/resources/com/dogecoin/dogecoinj/script/script_valid.json +++ /dev/null @@ -1,522 +0,0 @@ -[ -["", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "Test the test: we should have an empty stack after scriptSig evaluation"], -[" ", "DEPTH 0 EQUAL", "P2SH,STRICTENC", "and multiple spaces should not change that."], -[" ", "DEPTH 0 EQUAL", "P2SH,STRICTENC"], -[" ", "DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["1 2", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC", "Similarly whitespace around and between symbols"], -["1 2", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC"], -[" 1 2", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC"], -["1 2 ", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC"], -[" 1 2 ", "2 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC"], - -["1", "", "P2SH,STRICTENC"], -["0x02 0x01 0x00", "", "P2SH,STRICTENC", "all bytes are significant, not only the last one"], -["0x09 0x00000000 0x00000000 0x10", "", "P2SH,STRICTENC", "equals zero when cast to Int64"], - -["0x01 0x0b", "11 EQUAL", "P2SH,STRICTENC", "push 1 byte"], -["0x02 0x417a", "'Az' EQUAL", "P2SH,STRICTENC"], -["0x4b 0x417a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a7a", - "'Azzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz' EQUAL", "P2SH,STRICTENC", "push 75 bytes"], - -["0x4c 0x01 0x07","7 EQUAL", "P2SH,STRICTENC", "0x4c is OP_PUSHDATA1"], -["0x4d 0x0100 0x08","8 EQUAL", "P2SH,STRICTENC", "0x4d is OP_PUSHDATA2"], -["0x4e 0x01000000 0x09","9 EQUAL", "P2SH,STRICTENC", "0x4e is OP_PUSHDATA4"], - -["0x4c 0x00","0 EQUAL", "P2SH,STRICTENC"], -["0x4d 0x0000","0 EQUAL", "P2SH,STRICTENC"], -["0x4e 0x00000000","0 EQUAL", "P2SH,STRICTENC"], -["0x4f 1000 ADD","999 EQUAL", "P2SH,STRICTENC"], -["0", "IF 0x50 ENDIF 1", "P2SH,STRICTENC", "0x50 is reserved (ok if not executed)"], -["0x51", "0x5f ADD 0x60 EQUAL", "P2SH,STRICTENC", "0x51 through 0x60 push 1 through 16 onto stack"], -["1","NOP", "P2SH,STRICTENC"], -["0", "IF VER ELSE 1 ENDIF", "P2SH,STRICTENC", "VER non-functional (ok if not executed)"], -["0", "IF RESERVED RESERVED1 RESERVED2 ELSE 1 ENDIF", "P2SH,STRICTENC", "RESERVED ok in un-executed IF"], - -["1", "DUP IF ENDIF", "P2SH,STRICTENC"], -["1", "IF 1 ENDIF", "P2SH,STRICTENC"], -["1", "DUP IF ELSE ENDIF", "P2SH,STRICTENC"], -["1", "IF 1 ELSE ENDIF", "P2SH,STRICTENC"], -["0", "IF ELSE 1 ENDIF", "P2SH,STRICTENC"], - -["1 1", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], -["1 0", "IF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], -["1 1", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], -["0 0", "IF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], - -["1 0", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], -["1 1", "NOTIF IF 1 ELSE 0 ENDIF ENDIF", "P2SH,STRICTENC"], -["1 0", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], -["0 1", "NOTIF IF 1 ELSE 0 ENDIF ELSE IF 0 ELSE 1 ENDIF ENDIF", "P2SH,STRICTENC"], - -["0", "IF 0 ELSE 1 ELSE 0 ENDIF", "P2SH,STRICTENC", "Multiple ELSE's are valid and executed inverts on each ELSE encountered"], -["1", "IF 1 ELSE 0 ELSE ENDIF", "P2SH,STRICTENC"], -["1", "IF ELSE 0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["1", "IF 1 ELSE 0 ELSE 1 ENDIF ADD 2 EQUAL", "P2SH,STRICTENC"], -["'' 1", "IF SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ENDIF 0x14 0x68ca4fec736264c13b859bac43d5173df6871682 EQUAL", "P2SH,STRICTENC"], - -["1", "NOTIF 0 ELSE 1 ELSE 0 ENDIF", "P2SH,STRICTENC", "Multiple ELSE's are valid and execution inverts on each ELSE encountered"], -["0", "NOTIF 1 ELSE 0 ELSE ENDIF", "P2SH,STRICTENC"], -["0", "NOTIF ELSE 0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "NOTIF 1 ELSE 0 ELSE 1 ENDIF ADD 2 EQUAL", "P2SH,STRICTENC"], -["'' 0", "NOTIF SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ELSE ELSE SHA1 ENDIF 0x14 0x68ca4fec736264c13b859bac43d5173df6871682 EQUAL", "P2SH,STRICTENC"], - -["0", "IF 1 IF RETURN ELSE RETURN ELSE RETURN ENDIF ELSE 1 IF 1 ELSE RETURN ELSE 1 ENDIF ELSE RETURN ENDIF ADD 2 EQUAL", "P2SH,STRICTENC", "Nested ELSE ELSE"], -["1", "NOTIF 0 NOTIF RETURN ELSE RETURN ELSE RETURN ENDIF ELSE 0 NOTIF 1 ELSE RETURN ELSE 1 ENDIF ELSE RETURN ENDIF ADD 2 EQUAL", "P2SH,STRICTENC"], - -["0", "IF RETURN ENDIF 1", "P2SH,STRICTENC", "RETURN only works if executed"], - -["1 1", "VERIFY", "P2SH,STRICTENC"], -["1 0x05 0x01 0x00 0x00 0x00 0x00", "VERIFY", "P2SH,STRICTENC", "values >4 bytes can be cast to boolean"], - -["10 0 11 TOALTSTACK DROP FROMALTSTACK", "ADD 21 EQUAL", "P2SH,STRICTENC"], -["'gavin_was_here' TOALTSTACK 11 FROMALTSTACK", "'gavin_was_here' EQUALVERIFY 11 EQUAL", "P2SH,STRICTENC"], - -["0 IFDUP", "DEPTH 1 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC"], -["1 IFDUP", "DEPTH 2 EQUALVERIFY 1 EQUALVERIFY 1 EQUAL", "P2SH,STRICTENC"], -["0 DROP", "DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["0", "DUP 1 ADD 1 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC"], -["0 1", "NIP", "P2SH,STRICTENC"], -["1 0", "OVER DEPTH 3 EQUALVERIFY", "P2SH,STRICTENC"], -["22 21 20", "0 PICK 20 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"], -["22 21 20", "1 PICK 21 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"], -["22 21 20", "2 PICK 22 EQUALVERIFY DEPTH 3 EQUAL", "P2SH,STRICTENC"], -["22 21 20", "0 ROLL 20 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], -["22 21 20", "1 ROLL 21 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], -["22 21 20", "2 ROLL 22 EQUALVERIFY DEPTH 2 EQUAL", "P2SH,STRICTENC"], -["22 21 20", "ROT 22 EQUAL", "P2SH,STRICTENC"], -["22 21 20", "ROT DROP 20 EQUAL", "P2SH,STRICTENC"], -["22 21 20", "ROT DROP DROP 21 EQUAL", "P2SH,STRICTENC"], -["22 21 20", "ROT ROT 21 EQUAL", "P2SH,STRICTENC"], -["22 21 20", "ROT ROT ROT 20 EQUAL", "P2SH,STRICTENC"], -["25 24 23 22 21 20", "2ROT 24 EQUAL", "P2SH,STRICTENC"], -["25 24 23 22 21 20", "2ROT DROP 25 EQUAL", "P2SH,STRICTENC"], -["25 24 23 22 21 20", "2ROT 2DROP 20 EQUAL", "P2SH,STRICTENC"], -["25 24 23 22 21 20", "2ROT 2DROP DROP 21 EQUAL", "P2SH,STRICTENC"], -["25 24 23 22 21 20", "2ROT 2DROP 2DROP 22 EQUAL", "P2SH,STRICTENC"], -["25 24 23 22 21 20", "2ROT 2DROP 2DROP DROP 23 EQUAL", "P2SH,STRICTENC"], -["25 24 23 22 21 20", "2ROT 2ROT 22 EQUAL", "P2SH,STRICTENC"], -["25 24 23 22 21 20", "2ROT 2ROT 2ROT 20 EQUAL", "P2SH,STRICTENC"], -["1 0", "SWAP 1 EQUALVERIFY 0 EQUAL", "P2SH,STRICTENC"], -["0 1", "TUCK DEPTH 3 EQUALVERIFY SWAP 2DROP", "P2SH,STRICTENC"], -["13 14", "2DUP ROT EQUALVERIFY EQUAL", "P2SH,STRICTENC"], -["-1 0 1 2", "3DUP DEPTH 7 EQUALVERIFY ADD ADD 3 EQUALVERIFY 2DROP 0 EQUALVERIFY", "P2SH,STRICTENC"], -["1 2 3 5", "2OVER ADD ADD 8 EQUALVERIFY ADD ADD 6 EQUAL", "P2SH,STRICTENC"], -["1 3 5 7", "2SWAP ADD 4 EQUALVERIFY ADD 12 EQUAL", "P2SH,STRICTENC"], -["0", "SIZE 0 EQUAL", "P2SH,STRICTENC"], -["1", "SIZE 1 EQUAL", "P2SH,STRICTENC"], -["127", "SIZE 1 EQUAL", "P2SH,STRICTENC"], -["128", "SIZE 2 EQUAL", "P2SH,STRICTENC"], -["32767", "SIZE 2 EQUAL", "P2SH,STRICTENC"], -["32768", "SIZE 3 EQUAL", "P2SH,STRICTENC"], -["8388607", "SIZE 3 EQUAL", "P2SH,STRICTENC"], -["8388608", "SIZE 4 EQUAL", "P2SH,STRICTENC"], -["2147483647", "SIZE 4 EQUAL", "P2SH,STRICTENC"], -["2147483648", "SIZE 5 EQUAL", "P2SH,STRICTENC"], -["549755813887", "SIZE 5 EQUAL", "P2SH,STRICTENC"], -["549755813888", "SIZE 6 EQUAL", "P2SH,STRICTENC"], -["9223372036854775807", "SIZE 8 EQUAL", "P2SH,STRICTENC"], -["-1", "SIZE 1 EQUAL", "P2SH,STRICTENC"], -["-127", "SIZE 1 EQUAL", "P2SH,STRICTENC"], -["-128", "SIZE 2 EQUAL", "P2SH,STRICTENC"], -["-32767", "SIZE 2 EQUAL", "P2SH,STRICTENC"], -["-32768", "SIZE 3 EQUAL", "P2SH,STRICTENC"], -["-8388607", "SIZE 3 EQUAL", "P2SH,STRICTENC"], -["-8388608", "SIZE 4 EQUAL", "P2SH,STRICTENC"], -["-2147483647", "SIZE 4 EQUAL", "P2SH,STRICTENC"], -["-2147483648", "SIZE 5 EQUAL", "P2SH,STRICTENC"], -["-549755813887", "SIZE 5 EQUAL", "P2SH,STRICTENC"], -["-549755813888", "SIZE 6 EQUAL", "P2SH,STRICTENC"], -["-9223372036854775807", "SIZE 8 EQUAL", "P2SH,STRICTENC"], -["'abcdefghijklmnopqrstuvwxyz'", "SIZE 26 EQUAL", "P2SH,STRICTENC"], - -["42", "SIZE 1 EQUALVERIFY 42 EQUAL", "P2SH,STRICTENC", "SIZE does not consume argument"], - -["2 -2 ADD", "0 EQUAL", "P2SH,STRICTENC"], -["2147483647 -2147483647 ADD", "0 EQUAL", "P2SH,STRICTENC"], -["-1 -1 ADD", "-2 EQUAL", "P2SH,STRICTENC"], - -["0 0","EQUAL", "P2SH,STRICTENC"], -["1 1 ADD", "2 EQUAL", "P2SH,STRICTENC"], -["1 1ADD", "2 EQUAL", "P2SH,STRICTENC"], -["111 1SUB", "110 EQUAL", "P2SH,STRICTENC"], -["111 1 ADD 12 SUB", "100 EQUAL", "P2SH,STRICTENC"], -["0 ABS", "0 EQUAL", "P2SH,STRICTENC"], -["16 ABS", "16 EQUAL", "P2SH,STRICTENC"], -["-16 ABS", "-16 NEGATE EQUAL", "P2SH,STRICTENC"], -["0 NOT", "NOP", "P2SH,STRICTENC"], -["1 NOT", "0 EQUAL", "P2SH,STRICTENC"], -["11 NOT", "0 EQUAL", "P2SH,STRICTENC"], -["0 0NOTEQUAL", "0 EQUAL", "P2SH,STRICTENC"], -["1 0NOTEQUAL", "1 EQUAL", "P2SH,STRICTENC"], -["111 0NOTEQUAL", "1 EQUAL", "P2SH,STRICTENC"], -["-111 0NOTEQUAL", "1 EQUAL", "P2SH,STRICTENC"], -["1 1 BOOLAND", "NOP", "P2SH,STRICTENC"], -["1 0 BOOLAND", "NOT", "P2SH,STRICTENC"], -["0 1 BOOLAND", "NOT", "P2SH,STRICTENC"], -["0 0 BOOLAND", "NOT", "P2SH,STRICTENC"], -["16 17 BOOLAND", "NOP", "P2SH,STRICTENC"], -["1 1 BOOLOR", "NOP", "P2SH,STRICTENC"], -["1 0 BOOLOR", "NOP", "P2SH,STRICTENC"], -["0 1 BOOLOR", "NOP", "P2SH,STRICTENC"], -["0 0 BOOLOR", "NOT", "P2SH,STRICTENC"], -["16 17 BOOLOR", "NOP", "P2SH,STRICTENC"], -["11 10 1 ADD", "NUMEQUAL", "P2SH,STRICTENC"], -["11 10 1 ADD", "NUMEQUALVERIFY 1", "P2SH,STRICTENC"], -["11 10 1 ADD", "NUMNOTEQUAL NOT", "P2SH,STRICTENC"], -["111 10 1 ADD", "NUMNOTEQUAL", "P2SH,STRICTENC"], -["11 10", "LESSTHAN NOT", "P2SH,STRICTENC"], -["4 4", "LESSTHAN NOT", "P2SH,STRICTENC"], -["10 11", "LESSTHAN", "P2SH,STRICTENC"], -["-11 11", "LESSTHAN", "P2SH,STRICTENC"], -["-11 -10", "LESSTHAN", "P2SH,STRICTENC"], -["11 10", "GREATERTHAN", "P2SH,STRICTENC"], -["4 4", "GREATERTHAN NOT", "P2SH,STRICTENC"], -["10 11", "GREATERTHAN NOT", "P2SH,STRICTENC"], -["-11 11", "GREATERTHAN NOT", "P2SH,STRICTENC"], -["-11 -10", "GREATERTHAN NOT", "P2SH,STRICTENC"], -["11 10", "LESSTHANOREQUAL NOT", "P2SH,STRICTENC"], -["4 4", "LESSTHANOREQUAL", "P2SH,STRICTENC"], -["10 11", "LESSTHANOREQUAL", "P2SH,STRICTENC"], -["-11 11", "LESSTHANOREQUAL", "P2SH,STRICTENC"], -["-11 -10", "LESSTHANOREQUAL", "P2SH,STRICTENC"], -["11 10", "GREATERTHANOREQUAL", "P2SH,STRICTENC"], -["4 4", "GREATERTHANOREQUAL", "P2SH,STRICTENC"], -["10 11", "GREATERTHANOREQUAL NOT", "P2SH,STRICTENC"], -["-11 11", "GREATERTHANOREQUAL NOT", "P2SH,STRICTENC"], -["-11 -10", "GREATERTHANOREQUAL NOT", "P2SH,STRICTENC"], -["1 0 MIN", "0 NUMEQUAL", "P2SH,STRICTENC"], -["0 1 MIN", "0 NUMEQUAL", "P2SH,STRICTENC"], -["-1 0 MIN", "-1 NUMEQUAL", "P2SH,STRICTENC"], -["0 -2147483647 MIN", "-2147483647 NUMEQUAL", "P2SH,STRICTENC"], -["2147483647 0 MAX", "2147483647 NUMEQUAL", "P2SH,STRICTENC"], -["0 100 MAX", "100 NUMEQUAL", "P2SH,STRICTENC"], -["-100 0 MAX", "0 NUMEQUAL", "P2SH,STRICTENC"], -["0 -2147483647 MAX", "0 NUMEQUAL", "P2SH,STRICTENC"], -["0 0 1", "WITHIN", "P2SH,STRICTENC"], -["1 0 1", "WITHIN NOT", "P2SH,STRICTENC"], -["0 -2147483647 2147483647", "WITHIN", "P2SH,STRICTENC"], -["-1 -100 100", "WITHIN", "P2SH,STRICTENC"], -["11 -100 100", "WITHIN", "P2SH,STRICTENC"], -["-2147483647 -100 100", "WITHIN NOT", "P2SH,STRICTENC"], -["2147483647 -100 100", "WITHIN NOT", "P2SH,STRICTENC"], - -["2147483647 2147483647 SUB", "0 EQUAL", "P2SH,STRICTENC"], -["2147483647 DUP ADD", "4294967294 EQUAL", "P2SH,STRICTENC", ">32 bit EQUAL is valid"], -["2147483647 NEGATE DUP ADD", "-4294967294 EQUAL", "P2SH,STRICTENC"], - -["''", "RIPEMD160 0x14 0x9c1185a5c5e9fc54612808977ee8f548b2258d31 EQUAL", "P2SH,STRICTENC"], -["'a'", "RIPEMD160 0x14 0x0bdc9d2d256b3ee9daae347be6f4dc835a467ffe EQUAL", "P2SH,STRICTENC"], -["'abcdefghijklmnopqrstuvwxyz'", "RIPEMD160 0x14 0xf71c27109c692c1b56bbdceb5b9d2865b3708dbc EQUAL", "P2SH,STRICTENC"], -["''", "SHA1 0x14 0xda39a3ee5e6b4b0d3255bfef95601890afd80709 EQUAL", "P2SH,STRICTENC"], -["'a'", "SHA1 0x14 0x86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 EQUAL", "P2SH,STRICTENC"], -["'abcdefghijklmnopqrstuvwxyz'", "SHA1 0x14 0x32d10c7b8cf96570ca04ce37f2a19d84240d3a89 EQUAL", "P2SH,STRICTENC"], -["''", "SHA256 0x20 0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 EQUAL", "P2SH,STRICTENC"], -["'a'", "SHA256 0x20 0xca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb EQUAL", "P2SH,STRICTENC"], -["'abcdefghijklmnopqrstuvwxyz'", "SHA256 0x20 0x71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73 EQUAL", "P2SH,STRICTENC"], -["''", "DUP HASH160 SWAP SHA256 RIPEMD160 EQUAL", "P2SH,STRICTENC"], -["''", "DUP HASH256 SWAP SHA256 SHA256 EQUAL", "P2SH,STRICTENC"], -["''", "NOP HASH160 0x14 0xb472a266d0bd89c13706a4132ccfb16f7c3b9fcb EQUAL", "P2SH,STRICTENC"], -["'a'", "HASH160 NOP 0x14 0x994355199e516ff76c4fa4aab39337b9d84cf12b EQUAL", "P2SH,STRICTENC"], -["'abcdefghijklmnopqrstuvwxyz'", "HASH160 0x4c 0x14 0xc286a1af0947f58d1ad787385b1c2c4a976f9e71 EQUAL", "P2SH,STRICTENC"], -["''", "HASH256 0x20 0x5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456 EQUAL", "P2SH,STRICTENC"], -["'a'", "HASH256 0x20 0xbf5d3affb73efd2ec6c36ad3112dd933efed63c4e1cbffcfa88e2759c144f2d8 EQUAL", "P2SH,STRICTENC"], -["'abcdefghijklmnopqrstuvwxyz'", "HASH256 0x4c 0x20 0xca139bc10c2f660da42666f72e89a225936fc60f193c161124a672050c434671 EQUAL", "P2SH,STRICTENC"], - - -["1","NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10 1 EQUAL", "P2SH,STRICTENC"], -["'NOP_1_to_10' NOP1 NOP2 NOP3 NOP4 NOP5 NOP6 NOP7 NOP8 NOP9 NOP10","'NOP_1_to_10' EQUAL", "P2SH,STRICTENC"], - -["0", "IF 0xba ELSE 1 ENDIF", "P2SH,STRICTENC", "opcodes above NOP10 invalid if executed"], -["0", "IF 0xbb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xbc ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xbd ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xbe ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xbf ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xc0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xc1 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xc2 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xc3 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xc4 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xc5 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xc6 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xc7 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xc8 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xc9 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xca ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xcb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xcc ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xcd ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xce ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xcf ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xd0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xd1 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xd2 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xd3 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xd4 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xd5 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xd6 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xd7 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xd8 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xd9 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xda ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xdb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xdc ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xdd ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xde ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xdf ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xe0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xe1 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xe2 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xe3 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xe4 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xe5 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xe6 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xe7 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xe8 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xe9 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xea ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xeb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xec ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xed ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xee ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xef ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xf0 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xf1 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xf2 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xf3 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xf4 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xf5 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xf6 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xf7 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xf8 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xf9 ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xfa ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xfb ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xfc ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xfd ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xfe ELSE 1 ENDIF", "P2SH,STRICTENC"], -["0", "IF 0xff ELSE 1 ENDIF", "P2SH,STRICTENC"], - -["NOP", -"'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'", -"P2SH,STRICTENC", -"520 byte push"], -["1", -"0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", -"P2SH,STRICTENC", -"201 opcodes executed. 0x61 is NOP"], -["1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", -"1 2 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", -"P2SH,STRICTENC", -"1,000 stack size (0x6f is 3DUP)"], -["1 TOALTSTACK 2 TOALTSTACK 3 4 5 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", -"1 2 3 4 5 6 7 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", -"P2SH,STRICTENC", -"1,000 stack size (altstack cleared between scriptSig/scriptPubKey)"], -["'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f", -"'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 'bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb' 0x6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f6f 2DUP 0x616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161616161", -"P2SH,STRICTENC", -"Max-size (10,000-byte), max-push(520 bytes), max-opcodes(201), max stack size(1,000 items). 0x6f is 3DUP, 0x61 is NOP"], - -["0", -"IF 0x5050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050505050 ENDIF 1", -"P2SH,STRICTENC", -">201 opcodes, but RESERVED (0x50) doesn't count towards opcode limit."], - -["NOP","1", "P2SH,STRICTENC"], - -["1", "0x01 0x01 EQUAL", "P2SH,STRICTENC", "The following is useful for checking implementations of BN_bn2mpi"], -["127", "0x01 0x7F EQUAL", "P2SH,STRICTENC"], -["128", "0x02 0x8000 EQUAL", "P2SH,STRICTENC", "Leave room for the sign bit"], -["32767", "0x02 0xFF7F EQUAL", "P2SH,STRICTENC"], -["32768", "0x03 0x008000 EQUAL", "P2SH,STRICTENC"], -["8388607", "0x03 0xFFFF7F EQUAL", "P2SH,STRICTENC"], -["8388608", "0x04 0x00008000 EQUAL", "P2SH,STRICTENC"], -["2147483647", "0x04 0xFFFFFF7F EQUAL", "P2SH,STRICTENC"], -["2147483648", "0x05 0x0000008000 EQUAL", "P2SH,STRICTENC"], -["549755813887", "0x05 0xFFFFFFFF7F EQUAL", "P2SH,STRICTENC"], -["549755813888", "0x06 0xFFFFFFFF7F EQUAL", "P2SH,STRICTENC"], -["9223372036854775807", "0x08 0xFFFFFFFFFFFFFF7F EQUAL", "P2SH,STRICTENC"], -["-1", "0x01 0x81 EQUAL", "P2SH,STRICTENC", "Numbers are little-endian with the MSB being a sign bit"], -["-127", "0x01 0xFF EQUAL", "P2SH,STRICTENC"], -["-128", "0x02 0x8080 EQUAL", "P2SH,STRICTENC"], -["-32767", "0x02 0xFFFF EQUAL", "P2SH,STRICTENC"], -["-32768", "0x03 0x008080 EQUAL", "P2SH,STRICTENC"], -["-8388607", "0x03 0xFFFFFF EQUAL", "P2SH,STRICTENC"], -["-8388608", "0x04 0x00008080 EQUAL", "P2SH,STRICTENC"], -["-2147483647", "0x04 0xFFFFFFFF EQUAL", "P2SH,STRICTENC"], -["-2147483648", "0x05 0x0000008080 EQUAL", "P2SH,STRICTENC"], -["-4294967295", "0x05 0xFFFFFFFF80 EQUAL", "P2SH,STRICTENC"], -["-549755813887", "0x05 0xFFFFFFFFFF EQUAL", "P2SH,STRICTENC"], -["-549755813888", "0x06 0x000000008080 EQUAL", "P2SH,STRICTENC"], -["-9223372036854775807", "0x08 0xFFFFFFFFFFFFFFFF EQUAL", "P2SH,STRICTENC"], - -["2147483647", "1ADD 2147483648 EQUAL", "P2SH,STRICTENC", "We can do math on 4-byte integers, and compare 5-byte ones"], -["2147483647", "1ADD 1", "P2SH,STRICTENC"], -["-2147483647", "1ADD 1", "P2SH,STRICTENC"], - -["1", "0x02 0x0100 EQUAL NOT", "P2SH,STRICTENC", "Not the same byte array..."], -["1", "0x02 0x0100 NUMEQUAL", "P2SH,STRICTENC", "... but they are numerically equal"], -["11", "0x4c 0x03 0x0b0000 NUMEQUAL", "P2SH,STRICTENC"], -["0", "0x01 0x80 EQUAL NOT", "P2SH,STRICTENC"], -["0", "0x01 0x80 NUMEQUAL", "P2SH,STRICTENC", "Zero numerically equals negative zero"], -["0", "0x02 0x0080 NUMEQUAL", "P2SH,STRICTENC"], -["0x03 0x000080", "0x04 0x00000080 NUMEQUAL", "P2SH,STRICTENC"], -["0x03 0x100080", "0x04 0x10000080 NUMEQUAL", "P2SH,STRICTENC"], -["0x03 0x100000", "0x04 0x10000000 NUMEQUAL", "P2SH,STRICTENC"], - -["NOP", "NOP 1", "P2SH,STRICTENC", "The following tests check the if(stack.size() < N) tests in each opcode"], -["1", "IF 1 ENDIF", "P2SH,STRICTENC", "They are here to catch copy-and-paste errors"], -["0", "NOTIF 1 ENDIF", "P2SH,STRICTENC", "Most of them are duplicated elsewhere,"], -["1", "VERIFY 1", "P2SH,STRICTENC", "but, hey, more is always better, right?"], - -["0", "TOALTSTACK 1", "P2SH,STRICTENC"], -["1", "TOALTSTACK FROMALTSTACK", "P2SH,STRICTENC"], -["0 0", "2DROP 1", "P2SH,STRICTENC"], -["0 1", "2DUP", "P2SH,STRICTENC"], -["0 0 1", "3DUP", "P2SH,STRICTENC"], -["0 1 0 0", "2OVER", "P2SH,STRICTENC"], -["0 1 0 0 0 0", "2ROT", "P2SH,STRICTENC"], -["0 1 0 0", "2SWAP", "P2SH,STRICTENC"], -["1", "IFDUP", "P2SH,STRICTENC"], -["NOP", "DEPTH 1", "P2SH,STRICTENC"], -["0", "DROP 1", "P2SH,STRICTENC"], -["1", "DUP", "P2SH,STRICTENC"], -["0 1", "NIP", "P2SH,STRICTENC"], -["1 0", "OVER", "P2SH,STRICTENC"], -["1 0 0 0 3", "PICK", "P2SH,STRICTENC"], -["1 0", "PICK", "P2SH,STRICTENC"], -["1 0 0 0 3", "ROLL", "P2SH,STRICTENC"], -["1 0", "ROLL", "P2SH,STRICTENC"], -["1 0 0", "ROT", "P2SH,STRICTENC"], -["1 0", "SWAP", "P2SH,STRICTENC"], -["0 1", "TUCK", "P2SH,STRICTENC"], - -["1", "SIZE", "P2SH,STRICTENC"], - -["0 0", "EQUAL", "P2SH,STRICTENC"], -["0 0", "EQUALVERIFY 1", "P2SH,STRICTENC"], - -["0", "1ADD", "P2SH,STRICTENC"], -["2", "1SUB", "P2SH,STRICTENC"], -["-1", "NEGATE", "P2SH,STRICTENC"], -["-1", "ABS", "P2SH,STRICTENC"], -["0", "NOT", "P2SH,STRICTENC"], -["-1", "0NOTEQUAL", "P2SH,STRICTENC"], - -["1 0", "ADD", "P2SH,STRICTENC"], -["1 0", "SUB", "P2SH,STRICTENC"], -["-1 -1", "BOOLAND", "P2SH,STRICTENC"], -["-1 0", "BOOLOR", "P2SH,STRICTENC"], -["0 0", "NUMEQUAL", "P2SH,STRICTENC"], -["0 0", "NUMEQUALVERIFY 1", "P2SH,STRICTENC"], -["-1 0", "NUMNOTEQUAL", "P2SH,STRICTENC"], -["-1 0", "LESSTHAN", "P2SH,STRICTENC"], -["1 0", "GREATERTHAN", "P2SH,STRICTENC"], -["0 0", "LESSTHANOREQUAL", "P2SH,STRICTENC"], -["0 0", "GREATERTHANOREQUAL", "P2SH,STRICTENC"], -["-1 0", "MIN", "P2SH,STRICTENC"], -["1 0", "MAX", "P2SH,STRICTENC"], -["-1 -1 0", "WITHIN", "P2SH,STRICTENC"], - -["0", "RIPEMD160", "P2SH,STRICTENC"], -["0", "SHA1", "P2SH,STRICTENC"], -["0", "SHA256", "P2SH,STRICTENC"], -["0", "HASH160", "P2SH,STRICTENC"], -["0", "HASH256", "P2SH,STRICTENC"], -["NOP", "CODESEPARATOR 1", "P2SH,STRICTENC"], - -["NOP", "NOP1 1", "P2SH,STRICTENC"], -["NOP", "NOP2 1", "P2SH,STRICTENC"], -["NOP", "NOP3 1", "P2SH,STRICTENC"], -["NOP", "NOP4 1", "P2SH,STRICTENC"], -["NOP", "NOP5 1", "P2SH,STRICTENC"], -["NOP", "NOP6 1", "P2SH,STRICTENC"], -["NOP", "NOP7 1", "P2SH,STRICTENC"], -["NOP", "NOP8 1", "P2SH,STRICTENC"], -["NOP", "NOP9 1", "P2SH,STRICTENC"], -["NOP", "NOP10 1", "P2SH,STRICTENC"], - -["", "0 0 0 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "CHECKMULTISIG is allowed to have zero keys and/or sigs"], -["", "0 0 0 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 0 1 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "Zero sigs means no sigs are checked"], -["", "0 0 0 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], - -["", "0 0 0 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "CHECKMULTISIG is allowed to have zero keys and/or sigs"], -["", "0 0 0 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 0 1 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "Zero sigs means no sigs are checked"], -["", "0 0 0 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], - -["", "0 0 'a' 'b' 2 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC", "Test from up to 20 pubkeys, all not checked"], -["", "0 0 'a' 'b' 'c' 3 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 4 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 5 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 6 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 7 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 8 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 9 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 10 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 11 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 12 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 13 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 14 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 15 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 16 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 17 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 18 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 19 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG VERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 1 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 2 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 3 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 4 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 5 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 6 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 7 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 8 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 9 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 10 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 11 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 12 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 13 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 14 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 15 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 16 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 17 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 18 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 19 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], -["", "0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY DEPTH 0 EQUAL", "P2SH,STRICTENC"], - -["", -"0 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG 0 0 CHECKMULTISIG", -"P2SH,STRICTENC", -"nOpCount is incremented by the number of keys evaluated in addition to the usual one op per op. In this case we have zero keys, so we can execute 201 CHECKMULTISIGS"], - -["1", -"0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY 0 0 0 CHECKMULTISIGVERIFY", -"P2SH,STRICTENC"], - -["", -"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIG", -"P2SH,STRICTENC", -"Even though there are no signatures being checked nOpCount is incremented by the number of keys."], - -["1", -"NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP NOP 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY 0 0 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 20 CHECKMULTISIGVERIFY", -"P2SH,STRICTENC"], - -["0 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC", "Very basic P2SH"], -["0x4c 0 0x01 1", "HASH160 0x14 0xda1745e9b549bd0bfa1a569971c77eba30cd5a4b EQUAL", "P2SH,STRICTENC"], - -["0x40 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242", -"0x4d 0x4000 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242 EQUAL", -"P2SH,STRICTENC", -"Basic PUSH signedness check"], - -["0x4c 0x40 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242", -"0x4d 0x4000 0x42424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242424242 EQUAL", -"P2SH,STRICTENC", -"Basic PUSHDATA1 signedness check"], - -["0x00", "SIZE 0 EQUAL", "P2SH,STRICTENC", "Basic OP_0 execution"] -] diff --git a/src/test/resources/com/dogecoin/dogecoinj/script/tx_invalid.json b/src/test/resources/com/dogecoin/dogecoinj/script/tx_invalid.json deleted file mode 100644 index 638a705f..00000000 --- a/src/test/resources/com/dogecoin/dogecoinj/script/tx_invalid.json +++ /dev/null @@ -1,107 +0,0 @@ -[ -["The following are deserialized transactions which are invalid."], -["They are in the form"], -["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], -["serializedTransaction, verifyFlags]"], -["Objects that are only a single string (like this one) are ignored"], - -["0e1b5688cf179cd9f7cbda1fac0090f6e684bbf8cd946660120197c3f3681809 but with extra junk appended to the end of the scriptPubKey"], -[[["6ca7ec7b1847f6bdbd737176050e6a08d66ccd55bb94ad24f4018024107a5827", 0, "0x41 0x043b640e983c9690a14c039a2037ecc3467b27a0dcd58f19d76c7bc118d09fec45adc5370a1c5bf8067ca9f5557a4cf885fdb0fe0dcc9c3a7137226106fbc779a5 CHECKSIG VERIFY 1"]], -"010000000127587a10248001f424ad94bb55cd6cd6086a0e05767173bdbdf647187beca76c000000004948304502201b822ad10d6adc1a341ae8835be3f70a25201bbff31f59cbb9c5353a5f0eca18022100ea7b2f7074e9aa9cf70aa8d0ffee13e6b45dddabf1ab961bda378bcdb778fa4701ffffffff0100f2052a010000001976a914fc50c5907d86fed474ba5ce8b12a66e0a4c139d888ac00000000", "P2SH"], - -["This is the nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG from tx_valid.json"], -["but with the signature duplicated in the scriptPubKey with a non-standard pushdata prefix"], -["See FindAndDelete, which will only remove if it uses the same pushdata prefix as is standard"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x4c 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"], - -["Same as above, but with the sig in the scriptSig also pushed with the same non-standard OP_PUSHDATA"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x4c 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006b4c473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"], - -["An invalid P2SH Transaction"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]], -"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", "P2SH"], - -["Tests for CheckTransaction()"], -["No inputs"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]], -"0100000000010000000000000000015100000000", "P2SH"], - -["No outputs"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x05ab9e14d983742513f0f451e105ffb4198d1dd4 EQUAL"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022100f16703104aab4e4088317c862daec83440242411b039d14280e03dd33b487ab802201318a7be236672c5c56083eb7a5a195bc57a40af7923ff8545016cd3b571e2a601232103c40e5d339df3f30bf753e7e04450ae4ef76c9e45587d1d993bdc4cd06f0651c7acffffffff0000000000", "P2SH"], - -["Negative output"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xae609aca8061d77c5e111f6bb62501a6bbe2bfdb EQUAL"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d4830450220063222cbb128731fc09de0d7323746539166544d6c1df84d867ccea84bcc8903022100bf568e8552844de664cd41648a031554327aa8844af34b4f27397c65b92c04de0123210243ec37dee0e2e053a9c976f43147e79bc7d9dc606ea51010af1ac80db6b069e1acffffffff01ffffffffffffffff015100000000", "P2SH"], - -["MAX_MONEY + 1 output"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010140075af0750700015100000000", "P2SH"], - -["MAX_MONEY output + 1 output"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xb558cbf4930954aa6a344363a15668d7477ae716 EQUAL"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510001000000000000015100000000", "P2SH"], - -["Duplicate inputs"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x236d0639db62b0773fd8ac34dc85ae19e9aba80a EQUAL"]], -"01000000020001000000000000000000000000000000000000000000000000000000000000000000006c47304402204bb1197053d0d7799bf1b30cd503c44b58d6240cccbdc85b6fe76d087980208f02204beeed78200178ffc6c74237bb74b3f276bbb4098b5605d814304fe128bf1431012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0deaacffffffff0001000000000000000000000000000000000000000000000000000000000000000000006c47304402202306489afef52a6f62e90bf750bbcdf40c06f5c6b138286e6b6b86176bb9341802200dba98486ea68380f47ebb19a7df173b99e6bc9c681d6ccf3bde31465d1f16b3012321039e8815e15952a7c3fada1905f8cf55419837133bd7756c0ef14fc8dfe50c0deaacffffffff010000000000000000015100000000", "P2SH"], - -["Coinbase of size 1"], -["Note the input is just required to make the tester happy"], -[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], -"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0151ffffffff010000000000000000015100000000", "P2SH"], - -["Coinbase of size 101"], -["Note the input is just required to make the tester happy"], -[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], -"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff655151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", "P2SH"], - -["Null txin"], -[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "HASH160 0x14 0x02dae7dbbda56097959cba59b1989dd3e47937bf EQUAL"]], -"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6e49304602210086f39e028e46dafa8e1e3be63906465f4cf038fbe5ed6403dc3e74ae876e6431022100c4625c675cfc5c7e3a0e0d7eaec92ac24da20c73a88eb40d09253e51ac6def5201232103a183ddc41e84753aca47723c965d1b5c8b0e2b537963518355e6dd6cf8415e50acffffffff010000000000000000015100000000", "P2SH"], - -["Same as the transactions in valid with one input SIGHASH_ALL and one SIGHASH_ANYONECANPAY, but we set the _ANYONECANPAY sequence number, invalidating the SIGHASH_ALL signature"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"], - ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]], - "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df10101000000000200000000000000000000000000000000000000000000000000000000000000000000484730440220201dc2d030e380e8f9cfb41b442d930fa5a685bb2c8db5906671f865507d0670022018d9e7a8d4c8d86a73c2a724ee38ef983ec249827e0e464841735955c707ece98101000000010100000000000000015100000000", "P2SH"], - -["CHECKMULTISIG with incorrect signature order"], -["Note the input is just required to make the tester happy"], -[[["b3da01dd4aae683c7aee4d5d8b52a540a508e1115f77cd7fa9a291243f501223", 0, "HASH160 0x14 0xb1ce99298d5f07364b57b1e5c9cc00be0b04a954 EQUAL"]], -"01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe000048304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f401483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000", "P2SH"], - - -["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"], -["It is an OP_CHECKMULTISIG with the dummy value missing"], -[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], -"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004847304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"], - - -["CHECKMULTISIG SCRIPT_VERIFY_NULLDUMMY tests:"], - -["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"], -["It is an OP_CHECKMULTISIG with the dummy value set to something other than an empty string"], -[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], -"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a010047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"], - -["As above, but using a OP_1"], -[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], -"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000495147304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"], - -["As above, but using a OP_1NEGATE"], -[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], -"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000494f47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"], - -["As above, but with the dummy byte missing"], -[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], -"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004847304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"], - - -["Empty stack when we try to run CHECKSIG"], -[[["ad503f72c18df5801ee64d76090afe4c607fb2b822e9b7b63c5826c50e22fc3b", 0, "0x21 0x027c3a97665bf283a102a587a62a30a0c102d4d3b141015e2cae6f64e2543113e5 CHECKSIG NOT"]], -"01000000013bfc220ec526583cb6b7e922b8b27f604cfe0a09764de61e80f58dc1723f50ad0000000000ffffffff0101000000000000002321027c3a97665bf283a102a587a62a30a0c102d4d3b141015e2cae6f64e2543113e5ac00000000", "P2SH"], - -["Make diffs cleaner by leaving a comment here without comma at the end"] -] diff --git a/src/test/resources/com/dogecoin/dogecoinj/script/tx_valid.json b/src/test/resources/com/dogecoin/dogecoinj/script/tx_valid.json deleted file mode 100644 index aa8e5ca6..00000000 --- a/src/test/resources/com/dogecoin/dogecoinj/script/tx_valid.json +++ /dev/null @@ -1,182 +0,0 @@ -[ -["The following are deserialized transactions which are valid."], -["They are in the form"], -["[[[prevout hash, prevout index, prevout scriptPubKey], [input 2], ...],"], -["serializedTransaction, verifyFlags]"], -["Objects that are only a single string (like this one) are ignored"], - -["The following is 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"], -["It is of particular interest because it contains an invalidly-encoded signature which OpenSSL accepts"], -["See http://r6.ca/blog/20111119T211504Z.html"], -["It is also the first OP_CHECKMULTISIG transaction in standard form"], -[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], -"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000490047304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"], - -["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"], -["It is an OP_CHECKMULTISIG with an arbitrary extra byte stuffed into the signature at pos length - 2"], -["The dummy byte is fine however, so the NULLDUMMY flag should be happy"], -[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], -"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a0048304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2bab01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH,NULLDUMMY"], - -["The following is a tweaked form of 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63"], -["It is an OP_CHECKMULTISIG with the dummy value set to something other than an empty string"], -[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], -"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba260000000004a01ff47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"], - -["As above, but using a OP_1"], -[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], -"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000495147304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"], - -["As above, but using a OP_1NEGATE"], -[[["60a20bd93aa49ab4b28d514ec10b06e1829ce6818ec06cd3aabd013ebcdc4bb1", 0, "1 0x41 0x04cc71eb30d653c0c3163990c47b976f3fb3f37cccdcbedb169a1dfef58bbfbfaff7d8a473e7e2e6d317b87bafe8bde97e3cf8f065dec022b51d11fcdd0d348ac4 0x41 0x0461cbdcc5409fb4b4d42b51d33381354d80e550078cb532a34bfa2fcfdeb7d76519aecc62770f5b0e4ef8551946d8a540911abe3e7854a26f39f58b25c15342af 2 OP_CHECKMULTISIG"]], -"0100000001b14bdcbc3e01bdaad36cc08e81e69c82e1060bc14e518db2b49aa43ad90ba26000000000494f47304402203f16c6f40162ab686621ef3000b04e75418a0c0cb2d8aebeac894ae360ac1e780220ddc15ecdfc3507ac48e1681a33eb60996631bf6bf5bc0a0682c4db743ce7ca2b01ffffffff0140420f00000000001976a914660d4ef3a743e3e696ad990364e555c271ad504b88ac00000000", "P2SH"], - -["The following is c99c49da4c38af669dea436d3e73780dfdb6c1ecf9958baa52960e8baee30e73"], -["It is of interest because it contains a 0-sequence as well as a signature of SIGHASH type 0 (which is not a real type)"], -[[["406b2b06bcd34d3c8733e6b79f7a394c8a431fbf4ff5ac705c93f4076bb77602", 0, "DUP HASH160 0x14 0xdc44b1164188067c3a32d4780f5996fa14a4f2d9 EQUALVERIFY CHECKSIG"]], -"01000000010276b76b07f4935c70acf54fbf1f438a4c397a9fb7e633873c4dd3bc062b6b40000000008c493046022100d23459d03ed7e9511a47d13292d3430a04627de6235b6e51a40f9cd386f2abe3022100e7d25b080f0bb8d8d5f878bba7d54ad2fda650ea8d158a33ee3cbd11768191fd004104b0e2c879e4daf7b9ab68350228c159766676a14f5815084ba166432aab46198d4cca98fa3e9981d0a90b2effc514b76279476550ba3663fdcaff94c38420e9d5000000000100093d00000000001976a9149a7b0f3b80c6baaeedce0a0842553800f832ba1f88ac00000000", "P2SH"], - -["A nearly-standard transaction with CHECKSIGVERIFY 1 instead of CHECKSIG"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"], - -["Same as above, but with the signature duplicated in the scriptPubKey with the proper pushdata prefix"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0x5b6462475454710f3c22f5fdf0b40704c92f25c3 EQUALVERIFY CHECKSIGVERIFY 1 0x47 0x3044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a01"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006a473044022067288ea50aa799543a536ff9306f8e1cba05b9c6b10951175b924f96732555ed022026d7b5265f38d21541519e4a1e55044d5b9e17e15cdbaf29ae3792e99e883e7a012103ba8c8b86dea131c22ab967e6dd99bdae8eff7a1f75a2c35f1f944109e3fe5e22ffffffff010000000000000000015100000000", "P2SH"], - -["The following is f7fdd091fa6d8f5e7a8c2458f5c38faffff2d3f1406b6e4fe2c99dcc0d2d1cbb"], -["It caught a bug in the workaround for 23b397edccd3740a74adb603c9756370fafcde9bcc4483eb271ecad09a94dd63 in an overly simple implementation"], -[[["b464e85df2a238416f8bdae11d120add610380ea07f4ef19c5f9dfd472f96c3d", 0, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"], -["b7978cc96e59a8b13e0865d3f95657561a7f725be952438637475920bac9eb21", 1, "DUP HASH160 0x14 0xbef80ecf3a44500fda1bc92176e442891662aed2 EQUALVERIFY CHECKSIG"]], -"01000000023d6cf972d4dff9c519eff407ea800361dd0a121de1da8b6f4138a2f25de864b4000000008a4730440220ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e022049cffa1cdc102a0b56e0e04913606c70af702a1149dc3b305ab9439288fee090014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff21ebc9ba20594737864352e95b727f1a565756f9d365083eb1a8596ec98c97b7010000008a4730440220503ff10e9f1e0de731407a4a245531c9ff17676eda461f8ceeb8c06049fa2c810220c008ac34694510298fa60b3f000df01caa244f165b727d4896eb84f81e46bcc4014104266abb36d66eb4218a6dd31f09bb92cf3cfa803c7ea72c1fc80a50f919273e613f895b855fb7465ccbc8919ad1bd4a306c783f22cd3227327694c4fa4c1c439affffffff01f0da5200000000001976a914857ccd42dded6df32949d4646dfa10a92458cfaa88ac00000000", "P2SH"], - -["The following tests for the presence of a bug in the handling of SIGHASH_SINGLE"], -["It results in signing the constant 1, instead of something generated based on the transaction,"], -["when the input doing the signing has an index greater than the maximum output index"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "DUP HASH160 0x14 0xe52b482f2faa8ecbf0db344f93c84ac908557f33 EQUALVERIFY CHECKSIG"], ["0000000000000000000000000000000000000000000000000000000000000200", 0, "1"]], -"01000000020002000000000000000000000000000000000000000000000000000000000000000000000151ffffffff0001000000000000000000000000000000000000000000000000000000000000000000006b483045022100c9cdd08798a28af9d1baf44a6c77bcc7e279f47dc487c8c899911bc48feaffcc0220503c5c50ae3998a733263c5c0f7061b483e2b56c4c41b456e7d2f5a78a74c077032102d5c25adb51b61339d2b05315791e21bbe80ea470a49db0135720983c905aace0ffffffff010000000000000000015100000000", "P2SH"], - -["An invalid P2SH Transaction"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x7a052c840ba73af26755de42cf01cc9e0a49fef0 EQUAL"]], -"010000000100010000000000000000000000000000000000000000000000000000000000000000000009085768617420697320ffffffff010000000000000000015100000000", "NONE"], - -["A valid P2SH Transaction using the standard transaction type put forth in BIP 16"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x8febbed40483661de6958d957412f82deed8e2f7 EQUAL"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100c66c9cdf4c43609586d15424c54707156e316d88b0a1534c9e6b0d4f311406310221009c0fe51dbc9c4ab7cc25d3fdbeccf6679fe6827f08edf2b4a9f16ee3eb0e438a0123210338e8034509af564c62644c07691942e0c056752008a173c89f60ab2a88ac2ebfacffffffff010000000000000000015100000000", "P2SH"], - -["Tests for CheckTransaction()"], -["MAX_MONEY output"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0x32afac281462b822adbec5094b8d4d337dd5bd6a EQUAL"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006e493046022100e1eadba00d9296c743cb6ecc703fd9ddc9b3cd12906176a226ae4c18d6b00796022100a71aef7d2874deff681ba6080f1b278bac7bb99c61b08a85f4311970ffe7f63f012321030c0588dc44d92bdcbf8e72093466766fdc265ead8db64517b0c542275b70fffbacffffffff010040075af0750700015100000000", "P2SH"], - -["MAX_MONEY output + 0 output"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "HASH160 0x14 0xb558cbf4930954aa6a344363a15668d7477ae716 EQUAL"]], -"01000000010001000000000000000000000000000000000000000000000000000000000000000000006d483045022027deccc14aa6668e78a8c9da3484fbcd4f9dcc9bb7d1b85146314b21b9ae4d86022100d0b43dece8cfb07348de0ca8bc5b86276fa88f7f2138381128b7c36ab2e42264012321029bb13463ddd5d2cc05da6e84e37536cb9525703cfd8f43afdb414988987a92f6acffffffff020040075af075070001510000000000000000015100000000", "P2SH"], - -["Coinbase of size 2"], -["Note the input is just required to make the tester happy"], -[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], -"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff025151ffffffff010000000000000000015100000000", "P2SH"], - -["Coinbase of size 100"], -["Note the input is just required to make the tester happy"], -[[["0000000000000000000000000000000000000000000000000000000000000000", -1, "1"]], -"01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff6451515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151515151ffffffff010000000000000000015100000000", "P2SH"], - -["Simple transaction with first input is signed with SIGHASH_ALL, second with SIGHASH_ANYONECANPAY"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"], - ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]], - "010000000200010000000000000000000000000000000000000000000000000000000000000000000049483045022100d180fd2eb9140aeb4210c9204d3f358766eb53842b2a9473db687fa24b12a3cc022079781799cd4f038b85135bbe49ec2b57f306b2bb17101b17f71f000fcab2b6fb01ffffffff0002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", "P2SH"], - -["Same as above, but we change the sequence number of the first input to check that SIGHASH_ANYONECANPAY is being followed"], -[[["0000000000000000000000000000000000000000000000000000000000000100", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"], - ["0000000000000000000000000000000000000000000000000000000000000200", 0, "0x21 0x035e7f0d4d0841bcd56c39337ed086b1a633ee770c1ffdd94ac552a95ac2ce0efc CHECKSIG"]], - "01000000020001000000000000000000000000000000000000000000000000000000000000000000004948304502203a0f5f0e1f2bdbcd04db3061d18f3af70e07f4f467cbc1b8116f267025f5360b022100c792b6e215afc5afc721a351ec413e714305cb749aae3d7fee76621313418df101010000000002000000000000000000000000000000000000000000000000000000000000000000004847304402205f7530653eea9b38699e476320ab135b74771e1c48b81a5d041e2ca84b9be7a802200ac8d1f40fb026674fe5a5edd3dea715c27baa9baca51ed45ea750ac9dc0a55e81ffffffff010100000000000000015100000000", "P2SH"], - -["afd9c17f8913577ec3509520bd6e5d63e9c0fd2a5f70c787993b097ba6ca9fae which has several SIGHASH_SINGLE signatures"], -[[["63cfa5a09dc540bf63e53713b82d9ea3692ca97cd608c384f2aa88e51a0aac70", 0, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"], - ["04e8d0fcf3846c6734477b98f0f3d4badfb78f020ee097a0be5fe347645b817d", 1, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"], - ["ee1377aff5d0579909e11782e1d2f5f7b84d26537be7f5516dd4e43373091f3f", 1, "DUP HASH160 0x14 0xdcf72c4fd02f5a987cf9b02f2fabfcac3341a87d EQUALVERIFY CHECKSIG"]], - "010000000370ac0a1ae588aaf284c308d67ca92c69a39e2db81337e563bf40c59da0a5cf63000000006a4730440220360d20baff382059040ba9be98947fd678fb08aab2bb0c172efa996fd8ece9b702201b4fb0de67f015c90e7ac8a193aeab486a1f587e0f54d0fb9552ef7f5ce6caec032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff7d815b6447e35fbea097e00e028fb7dfbad4f3f0987b4734676c84f3fcd0e804010000006b483045022100c714310be1e3a9ff1c5f7cacc65c2d8e781fc3a88ceb063c6153bf950650802102200b2d0979c76e12bb480da635f192cc8dc6f905380dd4ac1ff35a4f68f462fffd032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff3f1f097333e4d46d51f5e77b53264db8f7f5d2e18217e1099957d0f5af7713ee010000006c493046022100b663499ef73273a3788dea342717c2640ac43c5a1cf862c9e09b206fcb3f6bb8022100b09972e75972d9148f2bdd462e5cb69b57c1214b88fc55ca638676c07cfc10d8032103579ca2e6d107522f012cd00b52b9a65fb46f0c57b9b8b6e377c48f526a44741affffffff0380841e00000000001976a914bfb282c70c4191f45b5a6665cad1682f2c9cfdfb88ac80841e00000000001976a9149857cc07bed33a5cf12b9c5e0500b675d500c81188ace0fd1c00000000001976a91443c52850606c872403c0601e69fa34b26f62db4a88ac00000000", "P2SH"], - - ["ddc454a1c0c35c188c98976b17670f69e586d9c0f3593ea879928332f0a069e7, which spends an input that pushes using a PUSHDATA1 that is negative when read as signed"], - [[["c5510a5dd97a25f43175af1fe649b707b1df8e1a41489bac33a23087027a2f48", 0, "0x4c 0xae 0x606563686f2022553246736447566b58312b5a536e587574356542793066794778625456415675534a6c376a6a334878416945325364667657734f53474f36633338584d7439435c6e543249584967306a486956304f376e775236644546673d3d22203e20743b206f70656e73736c20656e63202d7061737320706173733a5b314a564d7751432d707269766b65792d6865785d202d64202d6165732d3235362d636263202d61202d696e207460 DROP DUP HASH160 0x14 0xbfd7436b6265aa9de506f8a994f881ff08cc2872 EQUALVERIFY CHECKSIG"]], - "0100000001482f7a028730a233ac9b48411a8edfb107b749e61faf7531f4257ad95d0a51c5000000008b483045022100bf0bbae9bde51ad2b222e87fbf67530fbafc25c903519a1e5dcc52a32ff5844e022028c4d9ad49b006dd59974372a54291d5764be541574bb0c4dc208ec51f80b7190141049dd4aad62741dc27d5f267f7b70682eee22e7e9c1923b9c0957bdae0b96374569b460eb8d5b40d972e8c7c0ad441de3d94c4a29864b212d56050acb980b72b2bffffffff0180969800000000001976a914e336d0017a9d28de99d16472f6ca6d5a3a8ebc9988ac00000000", "P2SH"], - -["Correct signature order"], -["Note the input is just required to make the tester happy"], -[[["b3da01dd4aae683c7aee4d5d8b52a540a508e1115f77cd7fa9a291243f501223", 0, "HASH160 0x14 0xb1ce99298d5f07364b57b1e5c9cc00be0b04a954 EQUAL"]], -"01000000012312503f2491a2a97fcd775f11e108a540a5528b5d4dee7a3c68ae4add01dab300000000fdfe0000483045022100f6649b0eddfdfd4ad55426663385090d51ee86c3481bdc6b0c18ea6c0ece2c0b0220561c315b07cffa6f7dd9df96dbae9200c2dee09bf93cc35ca05e6cdf613340aa0148304502207aacee820e08b0b174e248abd8d7a34ed63b5da3abedb99934df9fddd65c05c4022100dfe87896ab5ee3df476c2655f9fbe5bd089dccbef3e4ea05b5d121169fe7f5f4014c695221031d11db38972b712a9fe1fc023577c7ae3ddb4a3004187d41c45121eecfdbb5b7210207ec36911b6ad2382860d32989c7b8728e9489d7bbc94a6b5509ef0029be128821024ea9fac06f666a4adc3fc1357b7bec1fd0bdece2b9d08579226a8ebde53058e453aeffffffff0180380100000000001976a914c9b99cddf847d10685a4fabaa0baf505f7c3dfab88ac00000000", "P2SH"], - -["cc60b1f899ec0a69b7c3f25ddf32c4524096a9c5b01cbd84c6d0312a0c478984, which is a fairly strange transaction which relies on OP_CHECKSIG returning 0 when checking a completely invalid sig of length 0"], -[[["cbebc4da731e8995fe97f6fadcd731b36ad40e5ecb31e38e904f6e5982fa09f7", 0, "0x2102085c6600657566acc2d6382a47bc3f324008d2aa10940dd7705a48aa2a5a5e33ac7c2103f5d0fb955f95dd6be6115ce85661db412ec6a08abcbfce7da0ba8297c6cc0ec4ac7c5379a820d68df9e32a147cffa36193c6f7c43a1c8c69cda530e1c6db354bfabdcfefaf3c875379a820f531f3041d3136701ea09067c53e7159c8f9b2746a56c3d82966c54bbc553226879a5479827701200122a59a5379827701200122a59a6353798277537982778779679a68"]], -"0100000001f709fa82596e4f908ee331cb5e0ed46ab331d7dcfaf697fe95891e73dac4ebcb000000008c20ca42095840735e89283fec298e62ac2ddea9b5f34a8cbb7097ad965b87568100201b1b01dc829177da4a14551d2fc96a9db00c6501edfa12f22cd9cefd335c227f483045022100a9df60536df5733dd0de6bc921fab0b3eee6426501b43a228afa2c90072eb5ca02201c78b74266fac7d1db5deff080d8a403743203f109fbcabf6d5a760bf87386d20100ffffffff01c075790000000000232103611f9a45c18f28f06f19076ad571c344c82ce8fcfe34464cf8085217a2d294a6ac00000000", "P2SH"], - -["Empty pubkey"], -[[["229257c295e7f555421c1bfec8538dd30a4b5c37c1c8810bbe83cafa7811652c", 0, "0x00 CHECKSIG NOT"]], -"01000000012c651178faca83be0b81c8c1375c4b0ad38d53c8fe1b1c4255f5e795c25792220000000049483045022100d6044562284ac76c985018fc4a90127847708c9edb280996c507b28babdc4b2a02203d74eca3f1a4d1eea7ff77b528fde6d5dc324ec2dbfdb964ba885f643b9704cd01ffffffff010100000000000000232102c2410f8891ae918cab4ffc4bb4a3b0881be67c7a1e7faa8b5acf9ab8932ec30cac00000000", "P2SH"], - -["Empty signature"], -[[["9ca93cfd8e3806b9d9e2ba1cf64e3cc6946ee0119670b1796a09928d14ea25f7", 0, "0x21 0x028a1d66975dbdf97897e3a4aef450ebeb5b5293e4a0b4a6d3a2daaa0b2b110e02 CHECKSIG NOT"]], -"0100000001f725ea148d92096a79b1709611e06e94c63c4ef61cbae2d9b906388efd3ca99c000000000100ffffffff0101000000000000002321028a1d66975dbdf97897e3a4aef450ebeb5b5293e4a0b4a6d3a2daaa0b2b110e02ac00000000", "P2SH"], - -[[["444e00ed7840d41f20ecd9c11d3f91982326c731a02f3c05748414a4fa9e59be", 0, "1 0x00 0x21 0x02136b04758b0b6e363e7a6fbe83aaf527a153db2b060d36cc29f7f8309ba6e458 2 CHECKMULTISIG"]], -"0100000001be599efaa4148474053c2fa031c7262398913f1dc1d9ec201fd44078ed004e44000000004900473044022022b29706cb2ed9ef0cb3c97b72677ca2dfd7b4160f7b4beb3ba806aa856c401502202d1e52582412eba2ed474f1f437a427640306fd3838725fab173ade7fe4eae4a01ffffffff010100000000000000232103ac4bba7e7ca3e873eea49e08132ad30c7f03640b6539e9b59903cf14fd016bbbac00000000", "P2SH"], - -[[["e16abbe80bf30c080f63830c8dbf669deaef08957446e95940227d8c5e6db612", 0, "1 0x21 0x03905380c7013e36e6e19d305311c1b81fce6581f5ee1c86ef0627c68c9362fc9f 0x00 2 CHECKMULTISIG"]], -"010000000112b66d5e8c7d224059e946749508efea9d66bf8d0c83630f080cf30be8bb6ae100000000490047304402206ffe3f14caf38ad5c1544428e99da76ffa5455675ec8d9780fac215ca17953520220779502985e194d84baa36b9bd40a0dbd981163fa191eb884ae83fc5bd1c86b1101ffffffff010100000000000000232103905380c7013e36e6e19d305311c1b81fce6581f5ee1c86ef0627c68c9362fc9fac00000000", "P2SH"], - -[[["ebbcf4bfce13292bd791d6a65a2a858d59adbf737e387e40370d4e64cc70efb0", 0, "2 0x21 0x033bcaa0a602f0d44cc9d5637c6e515b0471db514c020883830b7cefd73af04194 0x21 0x03a88b326f8767f4f192ce252afe33c94d25ab1d24f27f159b3cb3aa691ffe1423 2 CHECKMULTISIG NOT"]], -"0100000001b0ef70cc644e0d37407e387e73bfad598d852a5aa6d691d72b2913cebff4bceb000000004a00473044022068cd4851fc7f9a892ab910df7a24e616f293bcb5c5fbdfbc304a194b26b60fba022078e6da13d8cb881a22939b952c24f88b97afd06b4c47a47d7f804c9a352a6d6d0100ffffffff0101000000000000002321033bcaa0a602f0d44cc9d5637c6e515b0471db514c020883830b7cefd73af04194ac00000000", "P2SH"], - -[[["ba4cd7ae2ad4d4d13ebfc8ab1d93a63e4a6563f25089a18bf0fc68f282aa88c1", 0, "2 0x21 0x037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe1 0x21 0x02edc823cd634f2c4033d94f5755207cb6b60c4b1f1f056ad7471c47de5f2e4d50 2 CHECKMULTISIG NOT"]], -"0100000001c188aa82f268fcf08ba18950f263654a3ea6931dabc8bf3ed1d4d42aaed74cba000000004b0000483045022100940378576e069aca261a6b26fb38344e4497ca6751bb10905c76bb689f4222b002204833806b014c26fd801727b792b1260003c55710f87c5adbd7a9cb57446dbc9801ffffffff0101000000000000002321037c615d761e71d38903609bf4f46847266edc2fb37532047d747ba47eaae5ffe1ac00000000", "P2SH"], - - -["OP_CODESEPARATOR tests"], - -["Test that SignatureHash() removes OP_CODESEPARATOR with FindAndDelete()"], -[[["bc7fd132fcf817918334822ee6d9bd95c889099c96e07ca2c1eb2cc70db63224", 0, "CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIG"]], -"01000000012432b60dc72cebc1a27ce0969c0989c895bdd9e62e8234839117f8fc32d17fbc000000004a493046022100a576b52051962c25e642c0fd3d77ee6c92487048e5d90818bcf5b51abaccd7900221008204f8fb121be4ec3b24483b1f92d89b1b0548513a134e345c5442e86e8617a501ffffffff010000000000000000016a00000000", "P2SH"], -[[["83e194f90b6ef21fa2e3a365b63794fb5daa844bdc9b25de30899fcfe7b01047", 0, "CODESEPARATOR CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIG"]], -"01000000014710b0e7cf9f8930de259bdc4b84aa5dfb9437b665a3e3a21ff26e0bf994e183000000004a493046022100a166121a61b4eeb19d8f922b978ff6ab58ead8a5a5552bf9be73dc9c156873ea02210092ad9bc43ee647da4f6652c320800debcf08ec20a094a0aaf085f63ecb37a17201ffffffff010000000000000000016a00000000", "P2SH"], - -["Hashed data starts at the CODESEPARATOR"], -[[["326882a7f22b5191f1a0cc9962ca4b878cd969cf3b3a70887aece4d801a0ba5e", 0, "0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CODESEPARATOR CHECKSIG"]], -"01000000015ebaa001d8e4ec7a88703a3bcf69d98c874bca6299cca0f191512bf2a7826832000000004948304502203bf754d1c6732fbf87c5dcd81258aefd30f2060d7bd8ac4a5696f7927091dad1022100f5bcb726c4cf5ed0ed34cc13dadeedf628ae1045b7cb34421bc60b89f4cecae701ffffffff010000000000000000016a00000000", "P2SH"], - -["But only if execution has reached it"], -[[["a955032f4d6b0c9bfe8cad8f00a8933790b9c1dc28c82e0f48e75b35da0e4944", 0, "0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIGVERIFY CODESEPARATOR 0x21 0x038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041 CHECKSIGVERIFY CODESEPARATOR 1"]], -"010000000144490eda355be7480f2ec828dcc1b9903793a8008fad8cfe9b0c6b4d2f0355a900000000924830450221009c0a27f886a1d8cb87f6f595fbc3163d28f7a81ec3c4b252ee7f3ac77fd13ffa02203caa8dfa09713c8c4d7ef575c75ed97812072405d932bd11e6a1593a98b679370148304502201e3861ef39a526406bad1e20ecad06be7375ad40ddb582c9be42d26c3a0d7b240221009d0a3985e96522e59635d19cc4448547477396ce0ef17a58e7d74c3ef464292301ffffffff010000000000000000016a00000000", "P2SH"], - -["CHECKSIG is legal in scriptSigs"], -[[["ccf7f4053a02e653c36ac75c891b7496d0dc5ce5214f6c913d9cf8f1329ebee0", 0, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]], -"0100000001e0be9e32f1f89c3d916c4f21e55cdcd096741b895cc76ac353e6023a05f4f7cc00000000d86149304602210086e5f736a2c3622ebb62bd9d93d8e5d76508b98be922b97160edc3dcca6d8c47022100b23c312ac232a4473f19d2aeb95ab7bdf2b65518911a0d72d50e38b5dd31dc820121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac4730440220508fa761865c8abd81244a168392876ee1d94e8ed83897066b5e2df2400dad24022043f5ee7538e87e9c6aef7ef55133d3e51da7cc522830a9c4d736977a76ef755c0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"], - -["Same semantics for OP_CODESEPARATOR"], -[[["10c9f0effe83e97f80f067de2b11c6a00c3088a4bce42c5ae761519af9306f3c", 1, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]], -"01000000013c6f30f99a5161e75a2ce4bca488300ca0c6112bde67f0807fe983feeff0c91001000000e608646561646265656675ab61493046022100ce18d384221a731c993939015e3d1bcebafb16e8c0b5b5d14097ec8177ae6f28022100bcab227af90bab33c3fe0a9abfee03ba976ee25dc6ce542526e9b2e56e14b7f10121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac493046022100c3b93edcc0fd6250eb32f2dd8a0bba1754b0f6c3be8ed4100ed582f3db73eba2022100bf75b5bd2eff4d6bf2bda2e34a40fcc07d4aa3cf862ceaa77b47b81eff829f9a01ab21038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"], - -["Signatures are removed from the script they are in by FindAndDelete() in the CHECKSIG code; even multiple instances of one signature can be removed."], -[[["6056ebd549003b10cbbd915cea0d82209fe40b8617104be917a26fa92cbe3d6f", 0, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]], -"01000000016f3dbe2ca96fa217e94b1017860be49f20820dea5c91bdcb103b0049d5eb566000000000fd1d0147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140147304402203989ac8f9ad36b5d0919d97fa0a7f70c5272abee3b14477dc646288a8b976df5022027d19da84a066af9053ad3d1d7459d171b7e3a80bc6c4ef7a330677a6be548140121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ac47304402203757e937ba807e4a5da8534c17f9d121176056406a6465054bdd260457515c1a02200f02eccf1bec0f3a0d65df37889143c2e88ab7acec61a7b6f5aa264139141a2b0121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"], - -["That also includes ahead of the opcode being executed."], -[[["5a6b0021a6042a686b6b94abc36b387bef9109847774e8b1e51eb8cc55c53921", 1, "DUP HASH160 0x14 0xee5a6aa40facefb2655ac23c0c28c57c65c41f9b EQUALVERIFY CHECKSIG"]], -"01000000012139c555ccb81ee5b1e87477840991ef7b386bc3ab946b6b682a04a621006b5a01000000fdb40148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390121038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f2204148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a5800390175ac4830450220646b72c35beeec51f4d5bc1cbae01863825750d7f490864af354e6ea4f625e9c022100f04b98432df3a9641719dbced53393022e7249fb59db993af1118539830aab870148304502201723e692e5f409a7151db386291b63524c5eb2030df652b1f53022fd8207349f022100b90d9bbf2f3366ce176e5e780a00433da67d9e5c79312c6388312a296a580039017521038479a0fa998cd35259a2ef0a7a5c68662c1474f88ccb6d08a7677bbec7f22041ffffffff010000000000000000016a00000000", "P2SH"], - -["Finally CHECKMULTISIG removes all signatures prior to hashing the script containing those signatures. In conjunction with the SIGHASH_SINGLE bug this lets us test whether or not FindAndDelete() is actually present in scriptPubKey/redeemScript evaluation by including a signature of the digest 0x01 We can compute in advance for our pubkey, embed it it in the scriptPubKey, and then also using a normal SIGHASH_ALL signature. If FindAndDelete() wasn't run, the 'bugged' signature would still be in the hashed script, and the normal signature would fail."], - -["Here's an example on mainnet within a P2SH redeemScript. Remarkably it's a standard transaction in <0.9"], -[[["b5b598de91787439afd5938116654e0b16b7a0d0f82742ba37564219c5afcbf9", 0, "DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG"], - ["ab9805c6d57d7070d9a42c5176e47bb705023e6b67249fb6760880548298e742", 0, "HASH160 0x14 0xd8dacdadb7462ae15cd906f1878706d0da8660e6 EQUAL"]], -"0100000002f9cbafc519425637ba4227f8d0a0b7160b4e65168193d5af39747891de98b5b5000000006b4830450221008dd619c563e527c47d9bd53534a770b102e40faa87f61433580e04e271ef2f960220029886434e18122b53d5decd25f1f4acb2480659fea20aabd856987ba3c3907e0121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffff42e7988254800876b69f24676b3e0205b77be476512ca4d970707dd5c60598ab00000000fd260100483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a53034930460221008431bdfa72bc67f9d41fe72e94c88fb8f359ffa30b33c72c121c5a877d922e1002210089ef5fc22dd8bfc6bf9ffdb01a9862d27687d424d1fefbab9e9c7176844a187a014c9052483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71210378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c7153aeffffffff01a08601000000000017a914d8dacdadb7462ae15cd906f1878706d0da8660e68700000000", "P2SH"], - -["Same idea, but with bare CHECKMULTISIG"], -[[["ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db", 0, "DUP HASH160 0x14 0xf6f365c40f0739b61de827a44751e5e99032ed8f EQUALVERIFY CHECKSIG"], - ["ceafe58e0f6e7d67c0409fbbf673c84c166e3c5d3c24af58f7175b18df3bb3db", 1, "2 0x48 0x3045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 0x21 0x0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71 3 CHECKMULTISIG"]], -"0100000002dbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce000000006b4830450221009627444320dc5ef8d7f68f35010b4c050a6ed0d96b67a84db99fda9c9de58b1e02203e4b4aaa019e012e65d69b487fdf8719df72f488fa91506a80c49a33929f1fd50121022b78b756e2258af13779c1a1f37ea6800259716ca4b7f0b87610e0bf3ab52a01ffffffffdbb33bdf185b17f758af243c5d3c6e164cc873f6bb9f40c0677d6e0f8ee5afce010000009300483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303483045022015bd0139bcccf990a6af6ec5c1c52ed8222e03a0d51c334df139968525d2fcd20221009f9efe325476eb64c3958e4713e9eefe49bf1d820ed58d2112721b134e2a1a5303ffffffff01a0860100000000001976a9149bc0bbdd3024da4d0c38ed1aecf5c68dd1d3fa1288ac00000000", "P2SH"], - - -["Make diffs cleaner by leaving a comment here without comma at the end"] -] diff --git a/src/test/resources/com/dogecoin/dogecoinj/wallet/deterministic-wallet-serialization.txt b/src/test/resources/com/dogecoin/dogecoinj/wallet/deterministic-wallet-serialization.txt deleted file mode 100644 index 5e648b16..00000000 --- a/src/test/resources/com/dogecoin/dogecoinj/wallet/deterministic-wallet-serialization.txt +++ /dev/null @@ -1,278 +0,0 @@ -type: DETERMINISTIC_MNEMONIC -secret_bytes: "aerobic toe save section draw warm cute upon raccoon mother priority pilot taste sweet next traffic fatal sword dentist original crisp team caution rebel" -creation_timestamp: 1389353062000 -deterministic_seed: "E\032\356\206\230,\275\263\364=\334^f\307\037\350\321X7R\262z\205\3564\371tp\2639R\342\027 J\266\253\250\320\022\031\233\271~O$\330\260\214\fz\231tI\353\215*\037\355\205\213.\224?" - -type: DETERMINISTIC_KEY -secret_bytes: "\270E0\202(\362b\023\276\264\347\226E2\360\221\347\325\233L\203\3276\272\213\2436&\304\373\221\025" -public_key: "\002\342$\253\332\031\352\324q\316M\251}\274\267\370X$\366>Q\316\005\330\376\353f!WHLL\a" -creation_timestamp: 1389353062000 -deterministic_key { - chain_code: "XL\240FW\203\316\230\334\374J\003\357=\215\001\206\365\207Z\006m\334X`\236,;_\304\000^" -} - -type: DETERMINISTIC_KEY -secret_bytes: "\354B\331\275;\000\254?\3428\006\220G\365\243\333s\260s\213R\313\307\377f\331B\351\327=\001\333" -public_key: "\002\357\\\252\376]\023\315\'\316`\317\362\032@\232\"\360\331\335\221] `\016,\351<\b\300\225\032m" -deterministic_key { - chain_code: "\370\017\223\021O?.@gZ|\233j\3437\317q-\241!J \323\'\264s\203\314\321\v\346" - path: 2147483648 -} - -type: DETERMINISTIC_KEY -secret_bytes: "a\305j\001P\217Q\242\261.\353\367\315" -deterministic_key { - chain_code: "\231B\211S[\216\237\277q{a\365\216\325\250\223s\v\n(\364\257@3c\312rix\260c\217" - path: 2147483648 - path: 0 - issued_subkeys: 2 - lookahead_size: 10 - sigsRequiredToSpend: 1 -} - -type: DETERMINISTIC_KEY -secret_bytes: "\f0\266\235\272\205\212:\265\372\214P\226\344\a{S0\354\250\210\316L\256;W\036\200t\347\343\246" -public_key: "\0022\n\252\267NDr.7i7\332\232x\367\204G-|\204\301\333G\033g\300O\241\006\217\366\370" -deterministic_key { - chain_code: "\213\237\327\245a\273\274\310\377\360\351\352<\211k\033g\0251>y\236\345Jb\244[\b\fO\0311" - path: 2147483648 - path: 1 - issued_subkeys: 1 - lookahead_size: 10 - sigsRequiredToSpend: 1 -} - -type: DETERMINISTIC_KEY -public_key: "\002O_Q\223\337\360\245\234\322b_op\b?\030\364\255l\206\344`w\274\204\"\257\235U<}\377" -deterministic_key { - chain_code: "\331\233\342\227\336r\212>\021\022p\347* +\220\021{\206\310Z\314\335\322\230\331\365\221}\321\036\035" - path: 2147483648 - path: 0 - path: 0 -} - -type: DETERMINISTIC_KEY -public_key: "\003\270\311\006\363\375\002{\310\254n\301\366\303\315\255\3462\004/\251\'\205+\341~d\275\350\"\313\204\313" -deterministic_key { - chain_code: "5\037!\360\335\017\276\231\273\3531\020\253\223 \312\240M+\250\2520e\006\034\214{\331\376\201\004\306" - path: 2147483648 - path: 0 - path: 1 -} - -type: DETERMINISTIC_KEY -public_key: "\003\000\n\256n\324$.\324\365\231\f\224\001\376\266\341\036Q\212\374>\245\324\\8*\342\370\251x\b-" -deterministic_key { - chain_code: "5\202n|A\251$y+t\005\365\231\357\323\264E\266l\220\367\211dA\306\370\247<\'\034\323\324" - path: 2147483648 - path: 0 - path: 2 -} - -type: DETERMINISTIC_KEY -public_key: "\002\313/\026\020\254\240\3455\216\342E\300\316\353m.\270\204\264\327\220H\326E9\310\227 \023~\204\215" -deterministic_key { - chain_code: "\342\263a\033~\374\234UN\034\302\300\370\232\347B#L\251\267\035\255\210\356\vE\264\210\317\030]t" - path: 2147483648 - path: 0 - path: 3 -} - -type: DETERMINISTIC_KEY -public_key: "\002\217\n\021GL\354\214\354WhX\254\351\337w.\211&q1o\003\033\330\352**\351\356\210\264m" -deterministic_key { - chain_code: "\036\216\345\320e\267p\241\000\204\254\370\251d\000\253\354\316RH\275RS\221\016\343=T\236\335\222P" - path: 2147483648 - path: 0 - path: 4 -} - -type: DETERMINISTIC_KEY -public_key: "\003\325\n\347\346\3273\312J\211e\335?\227\236\304i\227\377J\222;\253\017\213\371\235d\220\231\026aV" -deterministic_key { - chain_code: "YSn>5\364i(j\b\326\212,\f,\322\3200\230\210)\366g\201\274\232\356\027\212O\345\215" - path: 2147483648 - path: 0 - path: 5 -} - -type: DETERMINISTIC_KEY -public_key: "\003\264\331\220\207*\342T\277\323\363\210\266\335\300\245?\024d\002\021\263|\253\035\253\244D\023\004\200\212X" -deterministic_key { - chain_code: "yP\342|\327\364\034\f\302}\236\032\031\t\345h(q7\346?wR\221\325\370\021\225\334\317Bg" - path: 2147483648 - path: 0 - path: 6 -} - -type: DETERMINISTIC_KEY -public_key: "\002HX\261\035\270!\263\2232-F\334\226n=<\0178\270^\202\225\264PF\v#\bdP/\355" -deterministic_key { - chain_code: "Z#\227\222\225\303\203\006q\206\321\v\355\353\220#Oh\360]\001IQD\333\025\356\276\342\270\021\313" - path: 2147483648 - path: 0 - path: 7 -} - -type: DETERMINISTIC_KEY -public_key: "\002\020C\2310\227\302\342\274u\217\021h\270\235\356\326_\365\321\261\272\340\267\n\335~\360\343\"Ow\b" -deterministic_key { - chain_code: "\232\000\3117\235\003`)\021g}/\203tk\201\021\364\247\245;\253\321\202\207\342\265\267_<\206\224" - path: 2147483648 - path: 0 - path: 8 -} - -type: DETERMINISTIC_KEY -public_key: "\002\276\211n\305\3339[D\337+\034\263\267U0\263\3039}/\376\207\030\364K\335\301\245\311\241\3419" -deterministic_key { - chain_code: "B\232\f\')\277\034\316HOdn\213\b\204\361\030\357YS \365zY\2749e\260)\233.-" - path: 2147483648 - path: 0 - path: 9 -} - -type: DETERMINISTIC_KEY -public_key: "\002h\356\202\222P\204x\345\226\017\256/E\304\273{)\272\034\375\2451\321\257\233\372?\320\352\356\271K" -deterministic_key { - chain_code: "\035\222\325\fY\221(\006\tf#7\370\355el\377\276\245\354\002\327\320\247\315V\004\016v\367\351\225" - path: 2147483648 - path: 0 - path: 10 -} - -type: DETERMINISTIC_KEY -public_key: "\002\325\313@\"\320\035\277(\245\222\342{\374g\235\203\347\217\035\204j\027\034\244\021bY0\247P`\323" -deterministic_key { - chain_code: "\226~!\327\210.\033\214\251\2367\205<\226`UF\354\234/\365\267E\317\202\354\211P\244\221\336\200" - path: 2147483648 - path: 0 - path: 11 -} - -type: DETERMINISTIC_KEY -public_key: "\003\000\334\035\2400n\26636x\316\327\3666\271\375K\031\366\307\221J@\331@dL\232Bv\324\262" -deterministic_key { - chain_code: "\207^n\317\370\t\207\341*\\\360\026iBRTQ#\252Z\237\373{\315\333\004\340nA9\252\352" - path: 2147483648 - path: 0 - path: 12 -} - -type: DETERMINISTIC_KEY -public_key: "\002\225b\3515\202\233\335\320.7\265\274uh\230N\242\254\317J\364\331\2345\220)\362\334\216\202\\" -deterministic_key { - chain_code: "\202:\344\3109?\350\345\001\314(\244q\370\233Rk\261}\302(\275\326\305R\342:\246\036\nV\330" - path: 2147483648 - path: 1 - path: 0 -} - -type: DETERMINISTIC_KEY -public_key: "\003>K!8\222VEL\371\305 z\aD8\020\233\330S\251T\330\201V\026-k2\227\266;" -deterministic_key { - chain_code: "\223\265.\200\316\361\241{\223\342c\212\0213ym+\032=#\360\333X\003\2770Z\311\335\267\342\313" - path: 2147483648 - path: 1 - path: 1 -} - -type: DETERMINISTIC_KEY -public_key: "\003\331t\251d\023\355w\221\266\301\264\306T\252\350\200\260A\220\363\212\345\021\222\236\003\210\215\342\r\251\000" -deterministic_key { - chain_code: "\276\262\033\030\227\271&e\254\377\346\031\2112\344[\234Z\221-\033\306P,Mi\021\313r\031\317\341" - path: 2147483648 - path: 1 - path: 2 -} - -type: DETERMINISTIC_KEY -public_key: "\002D\374\231\027\306\310\251\261\200\350@\ro\314\216\037>rp\017\276Q\203\027\016\213\320\206VqO\237" -deterministic_key { - chain_code: "_K4\n\356\235\036\243O\261\200\004\367\324\305;1\247I\350*\353`\204\004d\202\302\335\200/#" - path: 2147483648 - path: 1 - path: 3 -} - -type: DETERMINISTIC_KEY -public_key: "\003\370\352\3530]|\262\270]5\361\263\255)\027f\342\262\272a-\275\006\302\266\236\344\332\364\r\260\321" -deterministic_key { - chain_code: "o!GH\357\030\264\003_S\305\204\234wO\344.\215\377\232\025\206\351\030\227,\303%U2x\225" - path: 2147483648 - path: 1 - path: 4 -} - -type: DETERMINISTIC_KEY -public_key: "\002\221\021\370a[\205\267\036\021\366`\036\371\253Yk\r\303\025\f\255\2768\310\212\234\221\333\344\340t" -deterministic_key { - chain_code: "\370~\245F\n\307\377Q:\v\207\245\336F\376\2443R\034\346\b\372\b\\o\303\204D#}\266" - path: 2147483648 - path: 1 - path: 5 -} - -type: DETERMINISTIC_KEY -public_key: "\002c\034w@c\225\257n~G\330\002\241^\264\231\030\025\220gr\202`u\b\262\361\312\246\202J\341" -deterministic_key { - chain_code: "\\\2542\003\022\254\361*\a/4\307\3430\322\303\v\205\351\027\260 l\332\326\235<\363v\020\232" - path: 2147483648 - path: 1 - path: 6 -} - -type: DETERMINISTIC_KEY -public_key: "\003\266\304\006g\244l\271>\364\357G8B\374\026w\316\022\205\313\220\274\273>$\350\212o!\rt\230" -deterministic_key { - chain_code: "6]\325WN\017o\255\314\213\344\201f\204\361\235\'\343\217\341m\327\326=T\2018g\324\261`\335" - path: 2147483648 - path: 1 - path: 7 -} - -type: DETERMINISTIC_KEY -public_key: "\003X\331\344\227G\366//a\305j\001P\217Q\242\261.\353\367\315" -deterministic_key { - chain_code: "\231B\211S[\216\237\277q{a\365\216\325\250\223s\v\n(\364\257@3c\312rix\260c\217" - path: 2147483648 - path: 0 - issued_subkeys: 2 - lookahead_size: 10 - sigsRequiredToSpend: 1 -} - -type: DETERMINISTIC_KEY -public_key: "\0022\n\252\267NDr.7i7\332\232x\367\204G-|\204\301\333G\033g\300O\241\006\217\366\370" -deterministic_key { - chain_code: "\213\237\327\245a\273\274\310\377\360\351\352<\211k\033g\0251>y\236\345Jb\244[\b\fO\0311" - path: 2147483648 - path: 1 - issued_subkeys: 1 - lookahead_size: 10 - sigsRequiredToSpend: 1 -} - -type: DETERMINISTIC_KEY -public_key: "\002O_Q\223\337\360\245\234\322b_op\b?\030\364\255l\206\344`w\274\204\"\257\235U<}\377" -deterministic_key { - chain_code: "\331\233\342\227\336r\212>\021\022p\347* +\220\021{\206\310Z\314\335\322\230\331\365\221}\321\036\035" - path: 2147483648 - path: 0 - path: 0 -} - -type: DETERMINISTIC_KEY -public_key: "\003\270\311\006\363\375\002{\310\254n\301\366\303\315\255\3462\004/\251\'\205+\341~d\275\350\"\313\204\313" -deterministic_key { - chain_code: "5\037!\360\335\017\276\231\273\3531\020\253\223 \312\240M+\250\2520e\006\034\214{\331\376\201\004\306" - path: 2147483648 - path: 0 - path: 1 -} - -type: DETERMINISTIC_KEY -public_key: "\003\000\n\256n\324$.\324\365\231\f\224\001\376\266\341\036Q\212\374>\245\324\\8*\342\370\251x\b-" -deterministic_key { - chain_code: "5\202n|A\251$y+t\005\365\231\357\323\264E\266l\220\367\211dA\306\370\247<\'\034\323\324" - path: 2147483648 - path: 0 - path: 2 -} - -type: DETERMINISTIC_KEY -public_key: "\002\313/\026\020\254\240\3455\216\342E\300\316\353m.\270\204\264\327\220H\326E9\310\227 \023~\204\215" -deterministic_key { - chain_code: "\342\263a\033~\374\234UN\034\302\300\370\232\347B#L\251\267\035\255\210\356\vE\264\210\317\030]t" - path: 2147483648 - path: 0 - path: 3 -} - -type: DETERMINISTIC_KEY -public_key: "\002\217\n\021GL\354\214\354WhX\254\351\337w.\211&q1o\003\033\330\352**\351\356\210\264m" -deterministic_key { - chain_code: "\036\216\345\320e\267p\241\000\204\254\370\251d\000\253\354\316RH\275RS\221\016\343=T\236\335\222P" - path: 2147483648 - path: 0 - path: 4 -} - -type: DETERMINISTIC_KEY -public_key: "\003\325\n\347\346\3273\312J\211e\335?\227\236\304i\227\377J\222;\253\017\213\371\235d\220\231\026aV" -deterministic_key { - chain_code: "YSn>5\364i(j\b\326\212,\f,\322\3200\230\210)\366g\201\274\232\356\027\212O\345\215" - path: 2147483648 - path: 0 - path: 5 -} - -type: DETERMINISTIC_KEY -public_key: "\003\264\331\220\207*\342T\277\323\363\210\266\335\300\245?\024d\002\021\263|\253\035\253\244D\023\004\200\212X" -deterministic_key { - chain_code: "yP\342|\327\364\034\f\302}\236\032\031\t\345h(q7\346?wR\221\325\370\021\225\334\317Bg" - path: 2147483648 - path: 0 - path: 6 -} - -type: DETERMINISTIC_KEY -public_key: "\002HX\261\035\270!\263\2232-F\334\226n=<\0178\270^\202\225\264PF\v#\bdP/\355" -deterministic_key { - chain_code: "Z#\227\222\225\303\203\006q\206\321\v\355\353\220#Oh\360]\001IQD\333\025\356\276\342\270\021\313" - path: 2147483648 - path: 0 - path: 7 -} - -type: DETERMINISTIC_KEY -public_key: "\002\020C\2310\227\302\342\274u\217\021h\270\235\356\326_\365\321\261\272\340\267\n\335~\360\343\"Ow\b" -deterministic_key { - chain_code: "\232\000\3117\235\003`)\021g}/\203tk\201\021\364\247\245;\253\321\202\207\342\265\267_<\206\224" - path: 2147483648 - path: 0 - path: 8 -} - -type: DETERMINISTIC_KEY -public_key: "\002\276\211n\305\3339[D\337+\034\263\267U0\263\3039}/\376\207\030\364K\335\301\245\311\241\3419" -deterministic_key { - chain_code: "B\232\f\')\277\034\316HOdn\213\b\204\361\030\357YS \365zY\2749e\260)\233.-" - path: 2147483648 - path: 0 - path: 9 -} - -type: DETERMINISTIC_KEY -public_key: "\002h\356\202\222P\204x\345\226\017\256/E\304\273{)\272\034\375\2451\321\257\233\372?\320\352\356\271K" -deterministic_key { - chain_code: "\035\222\325\fY\221(\006\tf#7\370\355el\377\276\245\354\002\327\320\247\315V\004\016v\367\351\225" - path: 2147483648 - path: 0 - path: 10 -} - -type: DETERMINISTIC_KEY -public_key: "\002\325\313@\"\320\035\277(\245\222\342{\374g\235\203\347\217\035\204j\027\034\244\021bY0\247P`\323" -deterministic_key { - chain_code: "\226~!\327\210.\033\214\251\2367\205<\226`UF\354\234/\365\267E\317\202\354\211P\244\221\336\200" - path: 2147483648 - path: 0 - path: 11 -} - -type: DETERMINISTIC_KEY -public_key: "\003\000\334\035\2400n\26636x\316\327\3666\271\375K\031\366\307\221J@\331@dL\232Bv\324\262" -deterministic_key { - chain_code: "\207^n\317\370\t\207\341*\\\360\026iBRTQ#\252Z\237\373{\315\333\004\340nA9\252\352" - path: 2147483648 - path: 0 - path: 12 -} - -type: DETERMINISTIC_KEY -public_key: "\002\225b\3515\202\233\335\320.7\265\274uh\230N\242\254\317J\364\331\2345\220)\362\334\216\202\\" -deterministic_key { - chain_code: "\202:\344\3109?\350\345\001\314(\244q\370\233Rk\261}\302(\275\326\305R\342:\246\036\nV\330" - path: 2147483648 - path: 1 - path: 0 -} - -type: DETERMINISTIC_KEY -public_key: "\003>K!8\222VEL\371\305 z\aD8\020\233\330S\251T\330\201V\026-k2\227\266;" -deterministic_key { - chain_code: "\223\265.\200\316\361\241{\223\342c\212\0213ym+\032=#\360\333X\003\2770Z\311\335\267\342\313" - path: 2147483648 - path: 1 - path: 1 -} - -type: DETERMINISTIC_KEY -public_key: "\003\331t\251d\023\355w\221\266\301\264\306T\252\350\200\260A\220\363\212\345\021\222\236\003\210\215\342\r\251\000" -deterministic_key { - chain_code: "\276\262\033\030\227\271&e\254\377\346\031\2112\344[\234Z\221-\033\306P,Mi\021\313r\031\317\341" - path: 2147483648 - path: 1 - path: 2 -} - -type: DETERMINISTIC_KEY -public_key: "\002D\374\231\027\306\310\251\261\200\350@\ro\314\216\037>rp\017\276Q\203\027\016\213\320\206VqO\237" -deterministic_key { - chain_code: "_K4\n\356\235\036\243O\261\200\004\367\324\305;1\247I\350*\353`\204\004d\202\302\335\200/#" - path: 2147483648 - path: 1 - path: 3 -} - -type: DETERMINISTIC_KEY -public_key: "\003\370\352\3530]|\262\270]5\361\263\255)\027f\342\262\272a-\275\006\302\266\236\344\332\364\r\260\321" -deterministic_key { - chain_code: "o!GH\357\030\264\003_S\305\204\234wO\344.\215\377\232\025\206\351\030\227,\303%U2x\225" - path: 2147483648 - path: 1 - path: 4 -} - -type: DETERMINISTIC_KEY -public_key: "\002\221\021\370a[\205\267\036\021\366`\036\371\253Yk\r\303\025\f\255\2768\310\212\234\221\333\344\340t" -deterministic_key { - chain_code: "\370~\245F\n\307\377Q:\v\207\245\336F\376\2443R\034\346\b\372\b\\o\303\204D#}\266" - path: 2147483648 - path: 1 - path: 5 -} - -type: DETERMINISTIC_KEY -public_key: "\002c\034w@c\225\257n~G\330\002\241^\264\231\030\025\220gr\202`u\b\262\361\312\246\202J\341" -deterministic_key { - chain_code: "\\\2542\003\022\254\361*\a/4\307\3430\322\303\v\205\351\027\260 l\332\326\235<\363v\020\232" - path: 2147483648 - path: 1 - path: 6 -} - -type: DETERMINISTIC_KEY -public_key: "\003\266\304\006g\244l\271>\364\357G8B\374\026w\316\022\205\313\220\274\273>$\350\212o!\rt\230" -deterministic_key { - chain_code: "6]\325WN\017o\255\314\213\344\201f\204\361\235\'\343\217\341m\327\326=T\2018g\324\261`\335" - path: 2147483648 - path: 1 - path: 7 -} - -type: DETERMINISTIC_KEY -public_key: "\003X\331\344\227G\366//