/**
 * Copyright 2017 ZuInnoTe (Jörn Franke) <zuinnote@gmail.com>
 *
 * 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 org.zuinnote.hadoop.ethereum.format.common;


import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.jupiter.api.Test;
import org.zuinnote.hadoop.ethereum.format.exception.EthereumBlockReadException;

/**
 * @author jornfranke
 *
 */
public class EthereumFormatReaderTest {
	static final int DEFAULT_BUFFERSIZE=64*1024;
	static final int DEFAULT_MAXSIZE_ETHEREUMBLOCK=1 * 1024 * 1024;
	private static final Log LOG = LogFactory.getLog(EthereumFormatReaderTest.class.getName());
	public static int CHAIN_ID=1;

	@Test
	public void checkTestDataGenesisBlockAvailable() {
		ClassLoader classLoader = getClass().getClassLoader();
		String fileName="ethgenesis.bin";
		String fileNameGenesis=classLoader.getResource("testdata/"+fileName).getFile();
		assertNotNull(fileNameGenesis,"Test Data File \""+fileName+"\" is not null in resource path");
		File file = new File(fileNameGenesis);
		assertTrue( file.exists(),"Test Data File \""+fileName+"\" exists");
		assertFalse( file.isDirectory(),"Test Data File \""+fileName+"\" is not a directory");
	}

	@Test
	public void checkTestDataBlock1Available() {
		ClassLoader classLoader = getClass().getClassLoader();
		String fileName="eth1.bin";
		String fileNameGenesis=classLoader.getResource("testdata/"+fileName).getFile();
		assertNotNull(fileNameGenesis,"Test Data File \""+fileName+"\" is not null in resource path");
		File file = new File(fileNameGenesis);
		assertTrue( file.exists(),"Test Data File \""+fileName+"\" exists");
		assertFalse( file.isDirectory(),"Test Data File \""+fileName+"\" is not a directory");
	}

	@Test
	public void checkTestDataBlock1346406Available() {
		ClassLoader classLoader = getClass().getClassLoader();
		String fileName="eth1346406.bin";
		String fileNameGenesis=classLoader.getResource("testdata/"+fileName).getFile();
		assertNotNull(fileNameGenesis,"Test Data File \""+fileName+"\" is not null in resource path");
		File file = new File(fileNameGenesis);
		assertTrue( file.exists(),"Test Data File \""+fileName+"\" exists");
		assertFalse( file.isDirectory(),"Test Data File \""+fileName+"\" is not a directory");
	}

	@Test
	public void checkTestDataBlock3346406Available() {
		ClassLoader classLoader = getClass().getClassLoader();
		String fileName="eth3346406.bin";
		String fileNameGenesis=classLoader.getResource("testdata/"+fileName).getFile();
		assertNotNull(fileNameGenesis,"Test Data File \""+fileName+"\" is not null in resource path");
		File file = new File(fileNameGenesis);
		assertTrue( file.exists(),"Test Data File \""+fileName+"\" exists");
		assertFalse( file.isDirectory(),"Test Data File \""+fileName+"\" is not a directory");
	}

	@Test
	public void checkTestDataBlock0to10Available() {
		ClassLoader classLoader = getClass().getClassLoader();
		String fileName="eth0to10.bin";
		String fileNameGenesis=classLoader.getResource("testdata/"+fileName).getFile();
		assertNotNull(fileNameGenesis,"Test Data File \""+fileName+"\" is not null in resource path");
		File file = new File(fileNameGenesis);
		assertTrue( file.exists(),"Test Data File \""+fileName+"\" exists");
		assertFalse( file.isDirectory(),"Test Data File \""+fileName+"\" is not a directory");
	}

	@Test
	public void checkTestDataBlock351000to3510010Available() {
		ClassLoader classLoader = getClass().getClassLoader();
		String fileName="eth351000to3510010.bin";
		String fileNameGenesis=classLoader.getResource("testdata/"+fileName).getFile();
		assertNotNull(fileNameGenesis,"Test Data File \""+fileName+"\" is not null in resource path");
		File file = new File(fileNameGenesis);
		assertTrue( file.exists(),"Test Data File \""+fileName+"\" exists");
		assertFalse( file.isDirectory(),"Test Data File \""+fileName+"\" is not a directory");
	}


	@Test
	public void checkTestDataBlock4800251Available() {
		ClassLoader classLoader = getClass().getClassLoader();
		String fileName="eth4800251.bin";
		String fileNameGenesis=classLoader.getResource("testdata/"+fileName).getFile();
		assertNotNull(fileNameGenesis,"Test Data File \""+fileName+"\" is not null in resource path");
		File file = new File(fileNameGenesis);
		assertTrue( file.exists(),"Test Data File \""+fileName+"\" exists");
		assertFalse( file.isDirectory(),"Test Data File \""+fileName+"\" is not a directory");
	}

	@Test
	public void checkTestDataBlocks70000007000010Available() {
		ClassLoader classLoader = getClass().getClassLoader();
		String fileName="eth70000007000010";
		String fileNameGenesis=classLoader.getResource("testdata/"+fileName).getFile();
		assertNotNull(fileNameGenesis,"Test Data File \""+fileName+"\" is not null in resource path");
		File file = new File(fileNameGenesis);
		assertTrue( file.exists(),"Test Data File \""+fileName+"\" exists");
		assertFalse( file.isDirectory(),"Test Data File \""+fileName+"\" is not a directory");
	}

	@Test
	public void parseGenesisBlockAsEthereumRawBlockHeap() throws IOException, EthereumBlockReadException {
		ClassLoader classLoader = getClass().getClassLoader();
		String fileName="ethgenesis.bin";
		String fileNameBlock=classLoader.getResource("testdata/"+fileName).getFile();
		File file = new File(fileNameBlock);
		boolean direct=false;
		FileInputStream fin = new FileInputStream(file);
		EthereumBlockReader ebr = null;
		try {
			ebr = new EthereumBlockReader(fin,this.DEFAULT_MAXSIZE_ETHEREUMBLOCK, this.DEFAULT_BUFFERSIZE,direct);
			ByteBuffer blockByteBuffer = ebr.readRawBlock();
			assertFalse( blockByteBuffer.isDirect(),"Raw Genesis Block is HeapByteBuffer");
			assertEquals( 540, blockByteBuffer.limit(),"Raw Genesis block has a size of 540 bytes");
		} finally {
			if (ebr!=null) {
				ebr.close();
			}
		}
	}

	@Test
	public void parseGenesisBlockAsEthereumRawBlockDirect() throws IOException, EthereumBlockReadException {
		ClassLoader classLoader = getClass().getClassLoader();
		String fileName="ethgenesis.bin";
		String fileNameBlock=classLoader.getResource("testdata/"+fileName).getFile();
		File file = new File(fileNameBlock);
		boolean direct=true;
		FileInputStream fin = new FileInputStream(file);
		EthereumBlockReader ebr = null;
		try {
			ebr = new EthereumBlockReader(fin,this.DEFAULT_MAXSIZE_ETHEREUMBLOCK, this.DEFAULT_BUFFERSIZE,direct);
			ByteBuffer blockByteBuffer = ebr.readRawBlock();
			assertTrue( blockByteBuffer.isDirect(),"Raw Genesis Block is DirectByteBuffer");
			assertEquals( 540, blockByteBuffer.limit(),"Raw Genesis block has a size of 540 bytes");
		} finally {
			if (ebr!=null) {
				ebr.close();
			}
		}
	}

	@Test
	public void parseBlockOneAsEthereumRawBlockHeap() throws IOException, EthereumBlockReadException {
		ClassLoader classLoader = getClass().getClassLoader();
		String fileName="eth1.bin";
		String fileNameBlock=classLoader.getResource("testdata/"+fileName).getFile();
		File file = new File(fileNameBlock);
		boolean direct=false;
		FileInputStream fin = new FileInputStream(file);
		EthereumBlockReader ebr = null;
		try {
			ebr = new EthereumBlockReader(fin,this.DEFAULT_MAXSIZE_ETHEREUMBLOCK, this.DEFAULT_BUFFERSIZE,direct);
			ByteBuffer blockByteBuffer = ebr.readRawBlock();
			assertFalse( blockByteBuffer.isDirect(),"Raw block 1 is HeapByteBuffer");
			assertEquals( 537, blockByteBuffer.limit(),"Raw block 1 has a size of 537 bytes");
		} finally {
			if (ebr!=null) {
				ebr.close();
			}
		}
	}

	@Test
	public void parseBlockOneAsEthereumRawBlockDirect() throws IOException, EthereumBlockReadException {
		ClassLoader classLoader = getClass().getClassLoader();
		String fileName="eth1.bin";
		String fileNameBlock=classLoader.getResource("testdata/"+fileName).getFile();
		File file = new File(fileNameBlock);
		boolean direct=true;
		FileInputStream fin = new FileInputStream(file);
		EthereumBlockReader ebr = null;
		try {
			ebr = new EthereumBlockReader(fin,this.DEFAULT_MAXSIZE_ETHEREUMBLOCK, this.DEFAULT_BUFFERSIZE,direct);
			ByteBuffer blockByteBuffer = ebr.readRawBlock();
			assertTrue( blockByteBuffer.isDirect(),"Raw block 1 is DirectByteBuffer");
			assertEquals( 537, blockByteBuffer.limit(),"Raw block 1 has a size of 537 bytes");
		} finally {
			if (ebr!=null) {
				ebr.close();
			}
		}
	}

	@Test
	public void parseBlock1346406AsEthereumRawBlockHeap() throws IOException, EthereumBlockReadException {
		ClassLoader classLoader = getClass().getClassLoader();
		String fileName="eth1346406.bin";
		String fileNameBlock=classLoader.getResource("testdata/"+fileName).getFile();
		File file = new File(fileNameBlock);
		boolean direct=false;
		FileInputStream fin = new FileInputStream(file);
		EthereumBlockReader ebr = null;
		try {
			ebr = new EthereumBlockReader(fin,this.DEFAULT_MAXSIZE_ETHEREUMBLOCK, this.DEFAULT_BUFFERSIZE,direct);
			ByteBuffer blockByteBuffer = ebr.readRawBlock();
			assertFalse( blockByteBuffer.isDirect(),"Raw block 1346406 is HeapByteBuffer");
			assertEquals( 1223, blockByteBuffer.limit(),"Raw block 1346406 has a size of 1223 bytes");
		} finally {
			if (ebr!=null) {
				ebr.close();
			}
		}
	}

	@Test
	public void parseBlock1346406AsEthereumRawBlockDirect() throws IOException, EthereumBlockReadException {
		ClassLoader classLoader = getClass().getClassLoader();
		String fileName="eth1346406.bin";
		String fileNameBlock=classLoader.getResource("testdata/"+fileName).getFile();
		File file = new File(fileNameBlock);
		boolean direct=true;
		FileInputStream fin = new FileInputStream(file);
		EthereumBlockReader ebr = null;
		try {
			ebr = new EthereumBlockReader(fin,this.DEFAULT_MAXSIZE_ETHEREUMBLOCK, this.DEFAULT_BUFFERSIZE,direct);
			ByteBuffer blockByteBuffer = ebr.readRawBlock();
			assertTrue( blockByteBuffer.isDirect(),"Raw block 1346406 is DirectByteBuffer");
			assertEquals( 1223, blockByteBuffer.limit(),"Raw block 1346406 has a size of 1223 bytes");
		} finally {
			if (ebr!=null) {
				ebr.close();
			}
		}
	}

	@Test
	public void parseBlock3346406AsEthereumRawBlockHeap() throws IOException, EthereumBlockReadException {
		ClassLoader classLoader = getClass().getClassLoader();
		String fileName="eth3346406.bin";
		String fileNameBlock=classLoader.getResource("testdata/"+fileName).getFile();
		File file = new File(fileNameBlock);
		boolean direct=false;
		FileInputStream fin = new FileInputStream(file);
		EthereumBlockReader ebr = null;
		try {
			ebr = new EthereumBlockReader(fin,this.DEFAULT_MAXSIZE_ETHEREUMBLOCK, this.DEFAULT_BUFFERSIZE,direct);
			ByteBuffer blockByteBuffer = ebr.readRawBlock();
			assertFalse( blockByteBuffer.isDirect(),"Raw block 3346406 is HeapByteBuffer");
			assertEquals( 2251, blockByteBuffer.limit(),"Raw block 3346406 has a size of 2251 bytes");
		} finally {
			if (ebr!=null) {
				ebr.close();
			}
		}
	}

	@Test
	public void parseBlock3346406AsEthereumRawBlockDirect() throws IOException, EthereumBlockReadException {
		ClassLoader classLoader = getClass().getClassLoader();
		String fileName="eth3346406.bin";
		String fileNameBlock=classLoader.getResource("testdata/"+fileName).getFile();
		File file = new File(fileNameBlock);
		boolean direct=true;
		FileInputStream fin = new FileInputStream(file);
		EthereumBlockReader ebr = null;
		try {
			ebr = new EthereumBlockReader(fin,this.DEFAULT_MAXSIZE_ETHEREUMBLOCK, this.DEFAULT_BUFFERSIZE,direct);
			ByteBuffer blockByteBuffer = ebr.readRawBlock();
			assertTrue( blockByteBuffer.isDirect(),"Raw block 3346406 is DirectByteBuffer");
			assertEquals( 2251, blockByteBuffer.limit(),"Raw block 3346406 has a size of 2251 bytes");
		} finally {
			if (ebr!=null) {
				ebr.close();
			}
		}
	}

	@Test
	public void parseBlock0to10AsEthereumRawBlockHeap() throws IOException, EthereumBlockReadException {
		ClassLoader classLoader = getClass().getClassLoader();
		String fileName="eth0to10.bin";
		String fileNameBlock=classLoader.getResource("testdata/"+fileName).getFile();
		File file = new File(fileNameBlock);
		boolean direct=false;
		FileInputStream fin = new FileInputStream(file);
		EthereumBlockReader ebr = null;
		try {
			ebr = new EthereumBlockReader(fin,this.DEFAULT_MAXSIZE_ETHEREUMBLOCK, this.DEFAULT_BUFFERSIZE,direct);
			ByteBuffer blockByteBuffer = ebr.readRawBlock();
			assertFalse( blockByteBuffer.isDirect(),"Raw block 0 is HeapByteBuffer");
			assertEquals( 540, blockByteBuffer.limit(),"Raw block 0 has a size of 540 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 537, blockByteBuffer.limit(),"Raw block 1 has a size of 537 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 544, blockByteBuffer.limit(),"Raw block 2 has a size of 544 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 1079, blockByteBuffer.limit(),"Raw block 3 has a size of 1079 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 1079, blockByteBuffer.limit(),"Raw block 4 has a size of 1079 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 537, blockByteBuffer.limit(),"Raw block 5 has a size of 537 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 537, blockByteBuffer.limit(),"Raw block 6 has a size of 537 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 1078, blockByteBuffer.limit(),"Raw block 7 has a size of 1078 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 537, blockByteBuffer.limit(),"Raw block 8 has a size of 537 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 544, blockByteBuffer.limit(),"Raw block 9 has a size of 544 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 537, blockByteBuffer.limit(),"Raw block 10 has a size of 537 bytes");
		} finally {
			if (ebr!=null) {
				ebr.close();
			}
		}
	}

	@Test
	public void parseBlock0to10AsEthereumRawBlockDirect() throws IOException, EthereumBlockReadException {
		ClassLoader classLoader = getClass().getClassLoader();
		String fileName="eth0to10.bin";
		String fileNameBlock=classLoader.getResource("testdata/"+fileName).getFile();
		File file = new File(fileNameBlock);
		boolean direct=true;
		FileInputStream fin = new FileInputStream(file);
		EthereumBlockReader ebr = null;
		try {
			ebr = new EthereumBlockReader(fin,this.DEFAULT_MAXSIZE_ETHEREUMBLOCK, this.DEFAULT_BUFFERSIZE,direct);
			ByteBuffer blockByteBuffer = ebr.readRawBlock();
			assertTrue( blockByteBuffer.isDirect(),"Raw block 0 is DirectByteBuffer");
			assertEquals( 540, blockByteBuffer.limit(),"Raw block 0 has a size of 540 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 537, blockByteBuffer.limit(),"Raw block 1 has a size of 537 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 544, blockByteBuffer.limit(),"Raw block 2 has a size of 544 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 1079, blockByteBuffer.limit(),"Raw block 3 has a size of 1079 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 1079, blockByteBuffer.limit(),"Raw block 4 has a size of 1079 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 537, blockByteBuffer.limit(),"Raw block 5 has a size of 537 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 537, blockByteBuffer.limit(),"Raw block 6 has a size of 537 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 1078, blockByteBuffer.limit(),"Raw block 7 has a size of 1078 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 537, blockByteBuffer.limit(),"Raw block 8 has a size of 537 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 544, blockByteBuffer.limit(),"Raw block 9 has a size of 544 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 537, blockByteBuffer.limit(),"Raw block 10 has a size of 537 bytes");
		} finally {
			if (ebr!=null) {
				ebr.close();
			}
		}
	}

	@Test
	public void parseBlock35100to351010AsEthereumRawBlockHeap() throws IOException, EthereumBlockReadException {
		ClassLoader classLoader = getClass().getClassLoader();
		String fileName="eth351000to3510010.bin";
		String fileNameBlock=classLoader.getResource("testdata/"+fileName).getFile();
		File file = new File(fileNameBlock);
		boolean direct=false;
		FileInputStream fin = new FileInputStream(file);
		EthereumBlockReader ebr = null;
		try {
			ebr = new EthereumBlockReader(fin,this.DEFAULT_MAXSIZE_ETHEREUMBLOCK, this.DEFAULT_BUFFERSIZE,direct);
			ByteBuffer blockByteBuffer = ebr.readRawBlock();
			assertFalse( blockByteBuffer.isDirect(),"Raw block 3510000 is HeapByteBuffer");
			assertEquals( 2842, blockByteBuffer.limit(),"Raw block 3510000 has a size of 2842 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 539, blockByteBuffer.limit(),"Raw block 3510001 has a size of 539 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 2595, blockByteBuffer.limit(),"Raw block 3510002 has a size of 2595 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 11636, blockByteBuffer.limit(),"Raw block 3510003 has a size of 11636 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 1335, blockByteBuffer.limit(),"Raw block 3510004 has a size of 1335 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 9126, blockByteBuffer.limit(),"Raw block 3510005 has a size of 9126 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 7807, blockByteBuffer.limit(),"Raw block 3510006 has a size of 7807 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 532, blockByteBuffer.limit(),"Raw block 3510007 has a size of 532 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 1393, blockByteBuffer.limit(),"Raw block 3510008 has a size of 1393 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 1217, blockByteBuffer.limit(),"Raw block 3510009 has a size of 1217 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 1016, blockByteBuffer.limit(),"Raw block 3510010 has a size of 1016 bytes");
		} finally {
			if (ebr!=null) {
				ebr.close();
			}
		}
	}


	@Test
	public void parseBlock35100to351010AsEthereumRawBlockDirect() throws IOException, EthereumBlockReadException {
		ClassLoader classLoader = getClass().getClassLoader();
		String fileName="eth351000to3510010.bin";
		String fileNameBlock=classLoader.getResource("testdata/"+fileName).getFile();
		File file = new File(fileNameBlock);
		boolean direct=true;
		FileInputStream fin = new FileInputStream(file);
		EthereumBlockReader ebr = null;
		try {
			ebr = new EthereumBlockReader(fin,this.DEFAULT_MAXSIZE_ETHEREUMBLOCK, this.DEFAULT_BUFFERSIZE,direct);
			ByteBuffer blockByteBuffer = ebr.readRawBlock();
			assertTrue( blockByteBuffer.isDirect(),"Raw block 3510000 is DirecteBuffer");
			assertEquals( 2842, blockByteBuffer.limit(),"Raw block 3510000 has a size of 2842 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 539, blockByteBuffer.limit(),"Raw block 3510001 has a size of 539 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 2595, blockByteBuffer.limit(),"Raw block 3510002 has a size of 2595 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 11636, blockByteBuffer.limit(),"Raw block 3510003 has a size of 11636 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 1335, blockByteBuffer.limit(),"Raw block 3510004 has a size of 1335 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 9126, blockByteBuffer.limit(),"Raw block 3510005 has a size of 9126 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 7807, blockByteBuffer.limit(),"Raw block 3510006 has a size of 7807 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 532, blockByteBuffer.limit(),"Raw block 3510007 has a size of 532 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 1393, blockByteBuffer.limit(),"Raw block 3510008 has a size of 1393 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 1217, blockByteBuffer.limit(),"Raw block 3510009 has a size of 1217 bytes");
			blockByteBuffer = ebr.readRawBlock();
			assertEquals( 1016, blockByteBuffer.limit(),"Raw block 3510010 has a size of 1016 bytes");
		} finally {
			if (ebr!=null) {
				ebr.close();
			}
		}
	}

	@Test
	public void parseGenesisBlockAsEthereumBlockHeap() throws IOException, EthereumBlockReadException, ParseException {
		ClassLoader classLoader = getClass().getClassLoader();
		String fileName="ethgenesis.bin";
		String fileNameBlock=classLoader.getResource("testdata/"+fileName).getFile();
		File file = new File(fileNameBlock);
		boolean direct=false;
		FileInputStream fin = new FileInputStream(file);
		EthereumBlockReader ebr = null;
		try {
			ebr = new EthereumBlockReader(fin,this.DEFAULT_MAXSIZE_ETHEREUMBLOCK, this.DEFAULT_BUFFERSIZE,direct);
			EthereumBlock eblock = ebr.readBlock();
			EthereumBlockHeader eblockHeader = eblock.getEthereumBlockHeader();
			List<EthereumTransaction> eTransactions = eblock.getEthereumTransactions();
			List<EthereumBlockHeader> eUncles = eblock.getUncleHeaders();
			assertEquals( 0, eTransactions.size(),"Genesis block contains 0 transactions");
			assertEquals(0, eUncles.size(),"Genesis block contains 0 uncleHeaders");
			byte[] expectedParentHash = new byte[] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
			assertArrayEquals( expectedParentHash, eblockHeader.getParentHash(),"Genesis block contains a 32 byte hash consisting only of 0x00");
			byte[] expectedUncleHash = new byte[] {(byte) 0x1D,(byte) 0xCC,0x4D,(byte) 0xE8,(byte) 0xDE, (byte) 0xC7,(byte) 0x5D,
					(byte) 0x7A,(byte) 0xAB,(byte) 0x85,(byte) 0xB5,(byte) 0x67,(byte) 0xB6,(byte) 0xCC,(byte) 0xD4,
					0x1A,(byte) 0xD3,(byte)0x12, 0x45,0x1B,(byte) 0x94,(byte) 0x8A,0x74,0x13,(byte) 0xF0,
					(byte) 0xA1,0x42,(byte) 0xFD,0x40,(byte) 0xD4,(byte) 0x93,0x47};
			assertArrayEquals( expectedUncleHash, eblockHeader.getUncleHash(),"Genesis block contains a correct 32 byte uncle hash");
			byte[] expectedCoinbase = new byte[] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
			assertArrayEquals(expectedCoinbase,eblockHeader.getCoinBase(),"Genesis block contains a 20 byte coinbase consisting only of 0x00");
			byte[] expectedStateRoot= new byte[] {(byte) 0xD7,(byte) 0xF8,(byte) 0x97,0x4F,(byte) 0xB5,(byte) 0xAC,0x78,(byte) 0xD9,(byte) 0xAC,0x09,(byte) 0x9B,(byte) 0x9A,(byte) 0xD5,0x01,(byte) 0x8B,(byte) 0xED,(byte) 0xC2,(byte) 0xCE,0x0A,0x72,(byte) 0xDA,(byte) 0xD1,(byte) 0x82,0x7A,0x17,0x09,(byte) 0xDA,0x30,0x58,0x0F,0x05,0x44};
			assertArrayEquals(expectedStateRoot,eblockHeader.getStateRoot(),"Genesis block contains a correct 32 byte stateroot");
			byte[] expectedTxTrieRoot= new byte[] {0x56,(byte) 0xE8,0x1F,0x17,0x1B,(byte) 0xCC,0x55,(byte) 0xA6,(byte) 0xFF,(byte) 0x83,0x45,(byte) 0xE6,(byte) 0x92,(byte) 0xC0,(byte) 0xF8,0x6E,0x5B,0x48,(byte) 0xE0,0x1B,(byte) 0x99,0x6C,(byte) 0xAD,(byte) 0xC0,0x01,0x62,0x2F,(byte) 0xB5,(byte) 0xE3,0x63,(byte) 0xB4,0x21};
			assertArrayEquals(expectedTxTrieRoot,eblockHeader.getTxTrieRoot(),"Genesis block contains a correct 32 byte txTrieRoot");
			byte[] expectedReceiptTrieRoot=new byte[] {0x56,(byte) 0xE8,0x1F,0x17,0x1B,(byte) 0xCC,0x55,(byte) 0xA6,(byte) 0xFF,(byte) 0x83,0x45,(byte) 0xE6,(byte) 0x92,(byte) 0xC0,(byte) 0xF8,0x6E,0x5B,0x48,(byte) 0xE0,0x1B,(byte) 0x99,0x6C,(byte) 0xAD,(byte) 0xC0,0x01,0x62,0x2F,(byte) 0xB5,(byte) 0xE3,0x63,(byte) 0xB4,0x21};
			assertArrayEquals(expectedReceiptTrieRoot,eblockHeader.getReceiptTrieRoot(),"Genesis block contains a correct 32 byte ReceiptTrieRoot");
			byte[] expectedLogsBloom = new byte[] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
			assertArrayEquals( expectedLogsBloom, eblockHeader.getLogsBloom(),"Genesis block contains a 256 byte log bloom consisting only of 0x00");
			byte[] expectedDifficulty = new byte[] {0x04,0x00,0x00,0x00,0x00};
			assertArrayEquals( expectedDifficulty, eblockHeader.getDifficulty(),"Genesis block contains a correct 5 byte difficulty");
			assertEquals(0L, eblockHeader.getTimestamp(),"Genesis block contains a timestamp of 0");
			long expectedNumber = 0L;
			assertEquals( BigInteger.valueOf(expectedNumber), eblockHeader.getNumber(),"Genesis block contains a number 0");
			byte[] expectedGasLimit = new byte[] {0x13,(byte) 0x88};
			assertArrayEquals( expectedGasLimit, eblockHeader.getGasLimitRaw(),"Genesis block contains a correct 2 byte gas limit");
			long expectedGasUsed = 0L;
			assertEquals( BigInteger.valueOf(expectedGasUsed), eblockHeader.getGasUsed(),"Genesis block contains a gas used of  0");
			byte[] expectedMixHash= new byte[] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
			assertArrayEquals( expectedMixHash, eblockHeader.getMixHash(),"Genesis block contains a correct 32 byte mix hash consisting only of 0x00");
			byte[] expectedExtraData= new byte[] {0x11,(byte) 0xBB,(byte) 0xE8,(byte) 0xDB,0x4E,0x34,0x7B,0x4E,(byte) 0x8C,(byte) 0x93,0x7C,0x1C,(byte) 0x83,0x70,(byte) 0xE4,(byte) 0xB5,(byte) 0xED,0x33,(byte) 0xAD,(byte) 0xB3,(byte) 0xDB,0x69,(byte) 0xCB,(byte) 0xDB,0x7A,0x38,(byte) 0xE1,(byte) 0xE5,0x0B,0x1B,(byte) 0x82,(byte) 0xFA};
			assertArrayEquals( expectedExtraData, eblockHeader.getExtraData(),"Genesis block contains correct 32 byte extra data");
			byte[] expectedNonce = new byte[] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42};
			assertArrayEquals( expectedNonce, eblockHeader.getNonce(),"Genesis block contains a correct 8 byte nonce");
		} finally {
			if (ebr!=null) {
				ebr.close();
			}
		}
	}



	@Test
	public void parseGenesisBlockAsEthereumBlockDirect() throws IOException, EthereumBlockReadException, ParseException {
		ClassLoader classLoader = getClass().getClassLoader();
		String fileName="ethgenesis.bin";
		String fileNameBlock=classLoader.getResource("testdata/"+fileName).getFile();
		File file = new File(fileNameBlock);
		boolean direct=true;
		FileInputStream fin = new FileInputStream(file);
		EthereumBlockReader ebr = null;
		try {
			ebr = new EthereumBlockReader(fin,this.DEFAULT_MAXSIZE_ETHEREUMBLOCK, this.DEFAULT_BUFFERSIZE,direct);
			EthereumBlock eblock = ebr.readBlock();
			EthereumBlockHeader eblockHeader = eblock.getEthereumBlockHeader();
			List<EthereumTransaction> eTransactions = eblock.getEthereumTransactions();
			List<EthereumBlockHeader> eUncles = eblock.getUncleHeaders();
			assertEquals( 0, eTransactions.size(),"Genesis block contains 0 transactions");
			assertEquals(0, eUncles.size(),"Genesis block contains 0 uncleHeaders");
			byte[] expectedParentHash = new byte[] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
			assertArrayEquals( expectedParentHash, eblockHeader.getParentHash(),"Genesis block contains a 32 byte hash consisting only of 0x00");
			byte[] expectedUncleHash = new byte[] {(byte) 0x1D,(byte) 0xCC,0x4D,(byte) 0xE8,(byte) 0xDE, (byte) 0xC7,(byte) 0x5D,
					(byte) 0x7A,(byte) 0xAB,(byte) 0x85,(byte) 0xB5,(byte) 0x67,(byte) 0xB6,(byte) 0xCC,(byte) 0xD4,
					0x1A,(byte) 0xD3,(byte)0x12, 0x45,0x1B,(byte) 0x94,(byte) 0x8A,0x74,0x13,(byte) 0xF0,
					(byte) 0xA1,0x42,(byte) 0xFD,0x40,(byte) 0xD4,(byte) 0x93,0x47};
			assertArrayEquals( expectedUncleHash, eblockHeader.getUncleHash(),"Genesis block contains a correct 32 byte uncle hash");
			byte[] expectedCoinbase = new byte[] {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
			assertArrayEquals(expectedCoinbase,eblockHeader.getCoinBase(),"Genesis block contains a 20 byte coinbase consisting only of 0x00");
			byte[] expectedStateRoot= new byte[] {(byte) 0xD7,(byte) 0xF8,(byte) 0x97,0x4F,(byte) 0xB5,(byte) 0xAC,0x78,(byte) 0xD9,(byte) 0xAC,0x09,(byte) 0x9B,(byte) 0x9A,(byte) 0xD5,0x01,(byte) 0x8B,(byte) 0xED,(byte) 0xC2,(byte) 0xCE,0x0A,0x72,(byte) 0xDA,(byte) 0xD1,(byte) 0x82,0x7A,0x17,0x09,(byte) 0xDA,0x30,0x58,0x0F,0x05,0x44};
			assertArrayEquals(expectedStateRoot,eblockHeader.getStateRoot(),"Genesis block contains a correct 32 byte stateroot");
			byte[] expectedTxTrieRoot= new byte[] {0x56,(byte) 0xE8,0x1F,0x17,0x1B,(byte) 0xCC,0x55,(byte) 0xA6,(byte) 0xFF,(byte) 0x83,0x45,(byte) 0xE6,(byte) 0x92,(byte) 0xC0,(byte) 0xF8,0x6E,0x5B,0x48,(byte) 0xE0,0x1B,(byte) 0x99,0x6C,(byte) 0xAD,(byte) 0xC0,0x01,0x62,0x2F,(byte) 0xB5,(byte) 0xE3,0x63,(byte) 0xB4,0x21};
			assertArrayEquals(expectedTxTrieRoot,eblockHeader.getTxTrieRoot(),"Genesis block contains a correct 32 byte txTrieRoot");
			byte[] expectedReceiptTrieRoot=new byte[] {0x56,(byte) 0xE8,0x1F,0x17,0x1B,(byte) 0xCC,0x55,(byte) 0xA6,(byte) 0xFF,(byte) 0x83,0x45,(byte) 0xE6,(byte) 0x92,(byte) 0xC0,(byte) 0xF8,0x6E,0x5B,0x48,(byte) 0xE0,0x1B,(byte) 0x99,0x6C,(byte) 0xAD,(byte) 0xC0,0x01,0x62,0x2F,(byte) 0xB5,(byte) 0xE3,0x63,(byte) 0xB4,0x21};
			assertArrayEquals(expectedReceiptTrieRoot,eblockHeader.getReceiptTrieRoot(),"Genesis block contains a correct 32 byte ReceiptTrieRoot");
